From 55e68401be875975951237e932d992db1c322c17 Mon Sep 17 00:00:00 2001 From: Tomasz Paluszkiewicz <tomaszp@man.poznan.pl> Date: Thu, 27 Jun 2019 14:01:50 +0200 Subject: [PATCH 1/3] Split Data store from Context --- include/pdi/context.h | 71 +-- include/pdi/context_proxy.h | 30 +- include/pdi/data_descriptor.h | 15 +- include/pdi/data_store.h | 134 +++++ include/pdi/pdi_fwd.h | 4 + plugins/decl_hdf5/dataset_op.cxx | 4 +- plugins/decl_hdf5/decl_hdf5.cxx | 2 +- plugins/decl_sion/decl_sion.cxx | 16 +- plugins/flowvr/src/module.h | 10 +- .../src/payloads/payload_button_event.h | 4 +- plugins/flowvr/src/payloads/payload_chunk.h | 30 +- plugins/flowvr/src/payloads/payload_data.h | 40 +- .../flowvr/src/payloads/payload_mouse_event.h | 8 +- plugins/flowvr/src/port.h | 2 +- plugins/flowvr/src/stamps/stamp.h | 2 +- plugins/flowvr/src/stamps/stamp_desc.h | 10 +- plugins/flowvr/src/trace.h | 4 +- plugins/mpi/mpi.cxx | 4 +- plugins/mpi/mpi_comm_transtyper.h | 4 +- plugins/pycall/pycall.cxx | 2 +- plugins/test/test.cxx | 2 +- plugins/trace/trace.cxx | 2 +- plugins/user_code/user_code.cxx | 4 +- src/CMakeLists.txt | 2 + src/context.cxx | 56 +- src/context_proxy.cxx | 42 +- src/data_descriptor.cxx | 12 + src/data_descriptor_impl.cxx | 76 +-- src/data_descriptor_impl.h | 8 +- src/data_store.cxx | 78 +++ src/data_store_impl.cxx | 197 +++++++ src/data_store_impl.h | 107 ++++ src/expression.cxx | 10 +- src/global_context.cxx | 68 +-- src/global_context.h | 66 +-- src/pdi.cxx | 9 +- src/python/pdi.cxx | 8 +- tests/CMakeLists.txt | 1 + tests/PDI_context.cxx | 469 --------------- tests/PDI_data_store.cxx | 534 ++++++++++++++++++ tests/PDI_expression.cxx | 11 +- tests/mocks/context_mock.h | 23 +- tests/mocks/data_store_mock.h | 61 ++ tests/mocks/global_context_mock.h | 20 - 44 files changed, 1271 insertions(+), 991 deletions(-) create mode 100644 include/pdi/data_store.h create mode 100644 src/data_store.cxx create mode 100644 src/data_store_impl.cxx create mode 100644 src/data_store_impl.h create mode 100644 tests/PDI_data_store.cxx create mode 100644 tests/mocks/data_store_mock.h diff --git a/include/pdi/context.h b/include/pdi/context.h index b2c5bdc1a..4fc93aa41 100644 --- a/include/pdi/context.h +++ b/include/pdi/context.h @@ -26,17 +26,12 @@ #define PDI_CONTEXT_H_ #include <functional> -#include <list> #include <memory> -#include <stack> #include <string> -#include <unordered_map> -#include <unordered_set> #include <pdi/pdi_fwd.h> -#include <pdi/data_descriptor.h> +#include <pdi/data_store.h> #include <pdi/datatype_template.h> -#include <pdi/ref_any.h> namespace PDI { @@ -44,57 +39,15 @@ namespace PDI { class PDI_EXPORT Context { public: - /** An iterator used to go through the descriptor store. - */ - class Iterator - { - friend class Context; - /// The iterator this wraps - std::unordered_map<std::string, std::unique_ptr<Data_descriptor>>::iterator m_data; - Iterator(const std::unordered_map<std::string, std::unique_ptr<Data_descriptor>>::iterator& data); - Iterator(std::unordered_map<std::string, std::unique_ptr<Data_descriptor>>::iterator&& data); - public: - Data_descriptor* operator-> (); - Data_descriptor& operator* (); - Iterator& operator++ (); - bool operator!= (const Iterator&); - }; - /** A function that parses a PC_tree_t to create a datatype_template */ typedef std::function<Datatype_template_uptr(Context&, PC_tree_t)> Datatype_template_parser; -protected: - Iterator get_iterator(const std::unordered_map<std::string, std::unique_ptr<Data_descriptor>>::iterator& data); - - Iterator get_iterator(std::unordered_map<std::string, std::unique_ptr<Data_descriptor>>::iterator&& data); - -public: virtual ~Context(); - /** Accesses the descriptor for a specific name. Might be uninitialized - */ - virtual Data_descriptor& desc(const std::string& name) = 0; - - /** Accesses the descriptor for a specific name. Might be uninitialized - */ - virtual Data_descriptor& desc(const char* name) = 0; - - /** Accesses the descriptor for a specific name. Might be uninitialized - */ - virtual Data_descriptor& operator[](const std::string& name) = 0; - - /** Accesses the descriptor for a specific name. Might be uninitialized - */ - virtual Data_descriptor& operator[](const char* name) = 0; - - /** Returns an iterator on the first descriptor + /** Access the data store of the context */ - virtual Iterator begin() = 0; - - /** Returns an iterator past the last descriptor - */ - virtual Iterator end() = 0; + virtual Data_store& data() = 0; /** Triggers a PDI "event" * \param[in] name the event name @@ -125,15 +78,6 @@ public: */ virtual std::function<void()> add_init_callback(const std::function<void()>& callback) = 0; - /** Adds new data callback to context - * - * \param[in] callback function to call when data is being available - * \param[in] name the name of the data on which call the callback, if not specified it's called on any data - * - * \return function that removes callback - */ - virtual std::function<void()> add_data_callback(const std::function<void(const std::string&, Ref)>& callback, const std::string& name = {}) = 0; - /** Adds new event callback to context * * \param[in] callback function to call when event is called @@ -143,15 +87,6 @@ public: */ virtual std::function<void()> add_event_callback(const std::function<void(const std::string&)>& callback, const std::string& name = {}) = 0; - /** Adds new empty desc access callback to context - * - * \param[in] callback function to call when event is called - * \param[in] name the name of the data on which call the callback, if not specified it's called on any data - * - * \return function that removes callback - */ - virtual std::function<void()> add_empty_desc_access_callback(const std::function<void(const std::string&)>& callback, const std::string& name = {}) = 0; - }; } // namespace PDI diff --git a/include/pdi/context_proxy.h b/include/pdi/context_proxy.h index 1f7c0b0aa..637e7d634 100644 --- a/include/pdi/context_proxy.h +++ b/include/pdi/context_proxy.h @@ -25,11 +25,10 @@ #ifndef PDI_CONTEXT_PROXY_H_ #define PDI_CONTEXT_PROXY_H_ -#include "context.h" #include "pdi_fwd.h" +#include "context.h" #include <string> -#include <unordered_map> namespace PDI { @@ -40,29 +39,7 @@ class PDI_EXPORT Context_proxy : public Context public: Context_proxy(Context& ctx, std::string plugin_name, PC_tree_t logging_tree); - /** Context::desc proxy for plugins - */ - Data_descriptor& desc(const std::string& name) override; - - /** Context::desc proxy for plugins - */ - Data_descriptor& desc(const char* name) override; - - /** Context::operator[] proxy for plugins - */ - Data_descriptor& operator[](const std::string& name) override; - - /** Context::operator[] proxy for plugins - */ - Data_descriptor& operator[](const char* name) override; - - /** Context::begin proxy for plugins - */ - Iterator begin() override; - - /** Context::end proxy for plugins - */ - Iterator end() override; + Data_store& data() override; /** Context::event proxy for plugins */ @@ -86,11 +63,8 @@ public: std::function<void()> add_init_callback(const std::function<void()>& callback) override; - std::function<void()> add_data_callback(const std::function<void(const std::string&, Ref)>& callback, const std::string& name = {}) override; - std::function<void()> add_event_callback(const std::function<void(const std::string&)>& callback, const std::string& name = {}) override; - std::function<void()> add_empty_desc_access_callback(const std::function<void(const std::string&)>& callback, const std::string& name = {}) override; }; } //namespace PDI diff --git a/include/pdi/data_descriptor.h b/include/pdi/data_descriptor.h index ec5f7458d..3af19680c 100644 --- a/include/pdi/data_descriptor.h +++ b/include/pdi/data_descriptor.h @@ -36,8 +36,21 @@ namespace PDI { class PDI_EXPORT Data_descriptor { +protected: + /** Lets implementation of the Data_descriptor to call trigger_data_callbacks + * in Data_store class + * + * \param data_store the data store to trigger data callbacks on + */ + void trigger_data_callbacks(Data_store& data_store); + + /** Lets implementation of the Data_descriptor to call trigger_empty_desc_access_callbacks + * in Data_store class + * + * \param data_store the data store to trigger empty_desc_access callbacks on + */ + void trigger_empty_desc_access_callbacks(Data_store& data_store); public: - virtual ~Data_descriptor(); /** Set the datatype template used to type raw pointers shared diff --git a/include/pdi/data_store.h b/include/pdi/data_store.h new file mode 100644 index 000000000..3e7219bb2 --- /dev/null +++ b/include/pdi/data_store.h @@ -0,0 +1,134 @@ +/******************************************************************************* + * Copyright (C) 2019 Commissariat a l'energie atomique et aux energies alternatives (CEA) + * Copyright (C) 2019 Institute of Bioorganic Chemistry Polish Academy of Science (PSNC) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of CEA nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#ifndef PDI_DATA_STORE_H_ +#define PDI_DATA_STORE_H_ + +#include <functional> +#include <list> +#include <map> +#include <memory> +#include <string> +#include <unordered_map> +#include <unordered_set> + +#include <pdi/pdi_fwd.h> +#include <pdi/data_descriptor.h> +#include <pdi/datatype_template.h> +#include <pdi/ref_any.h> + + +namespace PDI { + +class PDI_EXPORT Data_store +{ +public: + friend class Data_descriptor; + + /** An iterator used to go through the descriptor store. + */ + class Iterator + { + friend class Data_store; + /// The iterator this wraps + std::unordered_map<std::string, std::unique_ptr<Data_descriptor>>::iterator m_data; + Iterator(const std::unordered_map<std::string, std::unique_ptr<Data_descriptor>>::iterator& data); + Iterator(std::unordered_map<std::string, std::unique_ptr<Data_descriptor>>::iterator&& data); + public: + Data_descriptor* operator-> (); + Data_descriptor& operator* (); + Iterator& operator++ (); + bool operator!= (const Iterator&); + }; + +protected: + Iterator get_iterator(const std::unordered_map<std::string, std::unique_ptr<Data_descriptor>>::iterator& data); + + Iterator get_iterator(std::unordered_map<std::string, std::unique_ptr<Data_descriptor>>::iterator&& data); + +private: + /** Triggers data callbacks + * + * \param[in] name name of the descriptor that triggers callbacks + * \param[in] ref reference to the value of the data behind the descriptor + */ + virtual void trigger_data_callbacks(const std::string& name, Ref ref) = 0; + + /** Triggers empty_desc_access callbacks + * + * \param[in] name name of the descriptor that triggers callbacks + */ + virtual void trigger_empty_desc_access_callbacks(const std::string& name) = 0; + +public: + virtual ~Data_store(); + + /** Accesses the descriptor for a specific name. Might be uninitialized + */ + virtual Data_descriptor& desc(const std::string& name) = 0; + + /** Accesses the descriptor for a specific name. Might be uninitialized + */ + virtual Data_descriptor& desc(const char* name) = 0; + + /** Accesses the descriptor for a specific name. Might be uninitialized + */ + virtual Data_descriptor& operator[](const std::string& name) = 0; + + /** Accesses the descriptor for a specific name. Might be uninitialized + */ + virtual Data_descriptor& operator[](const char* name) = 0; + + /** Returns an iterator on the first descriptor + */ + virtual Iterator begin() = 0; + + /** Returns an iterator past the last descriptor + */ + virtual Iterator end() = 0; + + /** Adds new data callback to context + * + * \param[in] callback function to call when data is being available + * \param[in] name the name of the data on which call the callback, if not specified it's called on any data + * + * \return function that removes callback + */ + virtual std::function<void()> add_data_callback(const std::function<void(const std::string&, Ref)>& callback, const std::string& name = {}) = 0; + + /** Adds new empty desc access callback to context + * + * \param[in] callback function to call when event is called + * \param[in] name the name of the data on which call the callback, if not specified it's called on any data + * + * \return function that removes callback + */ + virtual std::function<void()> add_empty_desc_access_callback(const std::function<void(const std::string&)>& callback, const std::string& name = {}) = 0; + +}; + +} // namespace PDI + +#endif // PDI_DATA_STORE_H_ diff --git a/include/pdi/pdi_fwd.h b/include/pdi/pdi_fwd.h index 34a47c00a..de465794d 100644 --- a/include/pdi/pdi_fwd.h +++ b/include/pdi/pdi_fwd.h @@ -61,6 +61,10 @@ typedef std::unique_ptr<Datatype_template> Datatype_template_uptr; typedef std::unique_ptr<Datatype> Datatype_uptr; +/** Contains the set of data descriptors and descriptor related callbacks + */ +class Data_store; + /** A data descriptors with a name and a value, it contains an implicit type * template that is used when exposing untyped data */ diff --git a/plugins/decl_hdf5/dataset_op.cxx b/plugins/decl_hdf5/dataset_op.cxx index 7f6f25331..2044a6272 100644 --- a/plugins/decl_hdf5/dataset_op.cxx +++ b/plugins/decl_hdf5/dataset_op.cxx @@ -120,7 +120,7 @@ void Dataset_op::execute(Context& ctx, hid_t h5_file, hid_t xfer_lst, const unor void Dataset_op::do_read(Context& ctx, hid_t h5_file, hid_t read_lst) { - Ref_w ref = ctx[m_value].ref(); + Ref_w ref = ctx.data()[m_value].ref(); if ( !ref ) { ctx.logger()->warn("Reference to read not available: `{}'", m_value); return; @@ -144,7 +144,7 @@ void Dataset_op::do_read(Context& ctx, hid_t h5_file, hid_t read_lst) void Dataset_op::do_write(Context& ctx, hid_t h5_file, hid_t write_lst, const unordered_map<string, PDI::Datatype_template_uptr>& dsets) { - Ref_r ref = ctx[m_value].ref(); + Ref_r ref = ctx.data()[m_value].ref(); if ( !ref ) { ctx.logger()->warn("Reference to write not available: `{}'", m_value); return; diff --git a/plugins/decl_hdf5/decl_hdf5.cxx b/plugins/decl_hdf5/decl_hdf5.cxx index f6afcd46c..992034510 100644 --- a/plugins/decl_hdf5/decl_hdf5.cxx +++ b/plugins/decl_hdf5/decl_hdf5.cxx @@ -116,7 +116,7 @@ public: } }); - ctx.add_data_callback([this](const std::string& name, Ref ref) { + ctx.data().add_data_callback([this](const std::string& name, Ref ref) { this->data(name, ref); }); ctx.add_event_callback([this](const std::string& name) { diff --git a/plugins/decl_sion/decl_sion.cxx b/plugins/decl_sion/decl_sion.cxx index dd5a535d1..f7c2fd3be 100644 --- a/plugins/decl_sion/decl_sion.cxx +++ b/plugins/decl_sion/decl_sion.cxx @@ -198,13 +198,13 @@ struct decl_sion_plugin: Plugin { input_events{parse_events(PC_get(conf, ".inputs"))} { if (PC_status(conf)) throw Error {PDI_ERR_CONFIG, "Configuration is invalid"}; - Data_descriptor& comm_desc = ctx.desc(comm_name); + Data_descriptor& comm_desc = ctx.data().desc(comm_name); if ( !comm_desc.empty() ) { if (MPI_Comm_dup(*(static_cast<const MPI_Comm*>(Ref_r{comm_desc.ref()}.get())), &comm)) { throw Error {PDI_ERR_SYSTEM, "Cannot duplicate MPI communicator"}; } } - ctx.add_data_callback([this](const std::string& name, Ref ref) { + ctx.data().add_data_callback([this](const std::string& name, Ref ref) { this->data(name, ref); }); @@ -235,7 +235,7 @@ struct decl_sion_plugin: Plugin { { // check that data is available and data type is dense for (auto&& var : event.vars) { - if (Ref_r ref = context().desc(var).ref()) { + if (Ref_r ref = context().data().desc(var).ref()) { if (!ref.type().dense()) { throw Error {PDI_ERR_IMPL, "Sparse data type of variable '%s' is not supported", var.c_str()}; } @@ -248,7 +248,7 @@ struct decl_sion_plugin: Plugin { sion_int64 chunksize = 0; for (auto&& var : event.vars) { - const Ref& ref = context().desc(var).ref(); + const Ref& ref = context().data().desc(var).ref(); if (!ref) { throw Error {PDI_ERR_RIGHT, "Dataset unavailable '%s'", var.c_str()}; } @@ -261,7 +261,7 @@ struct decl_sion_plugin: Plugin { int sid = sion_paropen_mpi(event.file.to_string(context()).c_str(), "w,keyval=inline", &n_files, comm, &comm, &chunksize, &blksize, &rank, NULL, NULL); for (auto&& var : event.vars) { - Ref_r ref = context().desc(var).ref(); + Ref_r ref = context().data().desc(var).ref(); if (!ref) { throw Error {PDI_ERR_RIGHT, "Dataset unavailable '%s'", var.c_str()}; } @@ -300,7 +300,7 @@ struct decl_sion_plugin: Plugin { { // check that data type is dense for (auto&& var : event.vars) { - Ref cref = context().desc(var).ref(); + Ref cref = context().data().desc(var).ref(); if (Ref_w ref = cref) { if (!ref.type().dense()) { throw Error {PDI_ERR_IMPL, "Sparse data type of variable '%s' is not supported", var.c_str()}; @@ -319,7 +319,7 @@ struct decl_sion_plugin: Plugin { int sid = sion_paropen_mpi(event.file.to_string(context()).c_str(), "r,keyval=unknown", &n_files, comm, &comm, &chunksize, &blksize, &rank, NULL, NULL); for (auto&& var : event.vars) { - Ref_w ref = context().desc(var).ref(); + Ref_w ref = context().data().desc(var).ref(); if (!ref) { throw Error {PDI_ERR_RIGHT, "Dataset unavailable '%s'", var.c_str()}; } @@ -465,7 +465,7 @@ struct decl_sion_plugin: Plugin { void data(const std::string& name, Ref cref) { if ( name == comm_name ) { - if (MPI_Comm_dup(*(static_cast<const MPI_Comm*>(Ref_r{context().desc(name).ref()}.get())), &comm)) { + if (MPI_Comm_dup(*(static_cast<const MPI_Comm*>(Ref_r{context().data().desc(name).ref()}.get())), &comm)) { throw Error {PDI_ERR_SYSTEM, "Cannot duplicate MPI communicator"}; } } diff --git a/plugins/flowvr/src/module.h b/plugins/flowvr/src/module.h index 3813775d4..be3e3cfde 100644 --- a/plugins/flowvr/src/module.h +++ b/plugins/flowvr/src/module.h @@ -83,7 +83,7 @@ private: if (!PC_status(wait_on_data_node)) { std::string wait_data = PDI::to_string(wait_on_data_node); context().logger()->debug("(FlowVR) Module: wait_on_data = {}", wait_data); - context().add_data_callback([this](const std::string& name, PDI::Ref ref) { + context().data().add_data_callback([this](const std::string& name, PDI::Ref ref) { this->wait(name, ref); }, wait_data); } @@ -113,13 +113,13 @@ private: int nb_status = PDI::len(status_node); for (int status_id = 0; status_id < nb_status; status_id++) { std::string status_data = PDI::to_string(PC_get(status_node, "[%d]", status_id)); - context().add_data_callback([this](const std::string& name, PDI::Ref ref) { + context().data().add_data_callback([this](const std::string& name, PDI::Ref ref) { this->status(ref); }, status_data); } } else { std::string status_data = PDI::to_string(status_node); - context().add_data_callback([this](const std::string& name, PDI::Ref ref) { + context().data().add_data_callback([this](const std::string& name, PDI::Ref ref) { this->status(ref); }, status_data); } @@ -150,7 +150,7 @@ private: if (!PC_status(get_rank_node)) { std::string get_parallel_rank_data = PDI::to_string(get_rank_node); context().logger()->debug("(FlowVR) Module: Parallel rank = {}", get_parallel_rank_data); - context().add_data_callback([this](const std::string& name, PDI::Ref ref) { + context().data().add_data_callback([this](const std::string& name, PDI::Ref ref) { this->get_parallel_rank(name, ref); }, get_parallel_rank_data); } @@ -159,7 +159,7 @@ private: if (!PC_status(get_size_node)) { std::string get_parallel_size_data = PDI::to_string(get_size_node); context().logger()->debug("(FlowVR) Module: Parallel size = {}", get_parallel_size_data); - context().add_data_callback([this](const std::string& name, PDI::Ref ref) { + context().data().add_data_callback([this](const std::string& name, PDI::Ref ref) { this->get_parallel_size(name, ref); }, get_parallel_size_data); } diff --git a/plugins/flowvr/src/payloads/payload_button_event.h b/plugins/flowvr/src/payloads/payload_button_event.h index 55fb34f25..c16acff4f 100644 --- a/plugins/flowvr/src/payloads/payload_button_event.h +++ b/plugins/flowvr/src/payloads/payload_button_event.h @@ -146,7 +146,7 @@ public: m_flowvr_input_port{parent_port} { for (const auto& desc_value : m_desc_value_map) { - m_ctx.add_data_callback([this](const std::string& name, PDI::Ref ref) { + m_ctx.data().add_data_callback([this](const std::string& name, PDI::Ref ref) { this->data(name, ref); }, desc_value.first); } @@ -235,7 +235,7 @@ public: m_flowvr_output_port{parent_port} { for (const auto& desc_value : m_desc_value_map) { - m_ctx.add_data_callback([this](const std::string& name, PDI::Ref ref) { + m_ctx.data().add_data_callback([this](const std::string& name, PDI::Ref ref) { this->data(name, ref); }, desc_value.first); } diff --git a/plugins/flowvr/src/payloads/payload_chunk.h b/plugins/flowvr/src/payloads/payload_chunk.h index b59e3fa04..f77930e9b 100644 --- a/plugins/flowvr/src/payloads/payload_chunk.h +++ b/plugins/flowvr/src/payloads/payload_chunk.h @@ -77,7 +77,7 @@ protected: m_chunk_descs.emplace_back(PDI::to_string(PC_get(chunk_node, ".data"))); } for (const std::string& data_name : m_chunk_descs) { - m_ctx.add_empty_desc_access_callback([this](const std::string& name) { + m_ctx.data().add_empty_desc_access_callback([this](const std::string& name) { this->empty_desc_access(name); }, data_name); } @@ -178,8 +178,8 @@ public: long size = static_cast<long>(m_chunk_info.chunks_sizes[chunk_id]); if (!chunk_size_desc_it->second.empty()) { m_ctx.logger()->debug("(FlowVR) Input Chunk Payload ({}): Sharing size descriptor `{}' = {}", m_name, data_size_desc, size); - m_ctx[data_size_desc].share(&size, true, false); - m_ctx[data_size_desc].reclaim(); + m_ctx.data()[data_size_desc].share(&size, true, false); + m_ctx.data()[data_size_desc].reclaim(); m_ctx.logger()->debug("(FlowVR) Input Chunk Payload ({}): Share size descriptor complete ", m_name); } @@ -194,13 +194,13 @@ public: if (m_flowvr_buffer.unique(flowvr::Buffer::ALLSEGMENTS) ) { m_ctx.logger()->debug("(FlowVR) Input Chunk Payload ({}): Share (read/write) `{}'", m_name, chunk_desc); m_sharing_chunks = true; - m_ctx[chunk_desc].share(const_cast<flowvr::ubyte*>(m_flowvr_buffer.readAccess() + offset), true, true); + m_ctx.data()[chunk_desc].share(const_cast<flowvr::ubyte*>(m_flowvr_buffer.readAccess() + offset), true, true); m_ctx.logger()->debug("(FlowVR) Input Chunk Payload ({}): Share (read/write) complete `{}'", m_name, chunk_desc); } else { if (m_flowvr_buffer.valid()) { m_ctx.logger()->debug("(FlowVR) Input Chunk Payload ({}): Share (read only) `{}'", m_name, chunk_desc); m_sharing_chunks = true; - m_ctx[chunk_desc].share(const_cast<flowvr::ubyte*>(m_flowvr_buffer.readAccess() + offset), true, false); + m_ctx.data()[chunk_desc].share(const_cast<flowvr::ubyte*>(m_flowvr_buffer.readAccess() + offset), true, false); m_ctx.logger()->debug("(FlowVR) Input Chunk Payload ({}): Share (read only) complete `{}'", m_name, chunk_desc); } } @@ -208,7 +208,7 @@ public: m_ctx.logger()->warn("(FlowVR) Input Chunk Payload ({}): Flowvr data `{}' is empty or not valid", m_name, chunk_desc); m_ctx.logger()->debug("(FlowVR) Input Chunk Payload ({}): Sharing (nullptr) `{}'", m_name, chunk_desc); m_sharing_chunks = true; - m_ctx[chunk_desc].share(PDI::Ref(nullptr, nullptr, PDI::UNDEF_TYPE.clone_type(), true, false), false, false); + m_ctx.data()[chunk_desc].share(PDI::Ref(nullptr, nullptr, PDI::UNDEF_TYPE.clone_type(), true, false), false, false); m_ctx.logger()->debug("(FlowVR) Input Chunk Payload ({}): Share (nullptr) complete `{}'", m_name, chunk_desc); } } @@ -222,9 +222,9 @@ public: { for (std::string chunk_desc : m_chunk_descs) { if (!chunk_desc.empty()) { - if (!m_ctx[chunk_desc].empty()) { + if (!m_ctx.data()[chunk_desc].empty()) { m_ctx.logger()->debug("(FlowVR) Input Chunk Payload ({}): Reclaiming {}", m_name, chunk_desc); - m_ctx[chunk_desc].reclaim(); // have to reclaim (this is flowvr shared buffer) + m_ctx.data()[chunk_desc].reclaim(); // have to reclaim (this is flowvr shared buffer) m_sharing_chunks = false; } } @@ -248,9 +248,9 @@ public: ~Input_payload_chunk() { for (std::string chunk_desc : m_chunk_descs) { - if (!m_ctx[chunk_desc].empty() && m_sharing_chunks) { + if (!m_ctx.data()[chunk_desc].empty() && m_sharing_chunks) { m_ctx.logger()->debug("(FlowVR) Input Chunk Payload ({}): Destroing chunk, reclaiming {}", m_name, chunk_desc); - m_ctx[chunk_desc].reclaim(); // have to reclaim (this is flowvr shared buffer) + m_ctx.data()[chunk_desc].reclaim(); // have to reclaim (this is flowvr shared buffer) m_sharing_chunks = false; } } @@ -303,7 +303,7 @@ public: m_chunk_info.chunks_sizes.reset(new size_t[m_chunk_info.chunk_count]); size_t buffersize = sizeof(size_t) * (1 + m_chunk_info.chunk_count) ; //m_chunk_info for (int i = 0; i < m_chunk_info.chunk_count; i++) { - m_chunk_info.chunks_sizes[i] = m_ctx[m_chunk_descs[i]].default_type()->evaluate(m_ctx)->buffersize(); + m_chunk_info.chunks_sizes[i] = m_ctx.data()[m_chunk_descs[i]].default_type()->evaluate(m_ctx)->buffersize(); buffersize += m_chunk_info.chunks_sizes[i]; } m_flowvr_buffer = m_parent_port->getModule()->alloc(buffersize); @@ -327,7 +327,7 @@ public: m_ctx.logger()->debug("(FlowVR) Output Chunk Payload ({}): Sharing `{}'", m_name, data_name); m_sharing_chunks = true; - m_ctx[data_name].share(m_flowvr_buffer.writeAccess() + offset, false, true); + m_ctx.data()[data_name].share(m_flowvr_buffer.writeAccess() + offset, false, true); m_ctx.logger()->debug("(FlowVR) Output Chunk Payload ({}): Share complete `{}'", m_name, data_name); } @@ -355,7 +355,7 @@ public: for (std::string chunk_desc : m_chunk_descs) { if (!chunk_desc.empty()) { m_ctx.logger()->debug("(FlowVR) Output Chunk Payload ({}): Reclaiming `{}'", m_name, chunk_desc); - m_ctx[chunk_desc].reclaim(); // have to reclaim (this is flowvr shared buffer) + m_ctx.data()[chunk_desc].reclaim(); // have to reclaim (this is flowvr shared buffer) m_sharing_chunks = false; } } @@ -366,9 +366,9 @@ public: ~Output_payload_chunk() { for (std::string chunk_desc : m_chunk_descs) { - if (!m_ctx[chunk_desc].empty() && m_sharing_chunks) { + if (!m_ctx.data()[chunk_desc].empty() && m_sharing_chunks) { m_ctx.logger()->debug("(FlowVR) Output Chunk Payload ({}): Destroing payload, reclaiming {}", m_name, chunk_desc); - m_ctx[chunk_desc].reclaim(); // have to reclaim (this is flowvr shared buffer) + m_ctx.data()[chunk_desc].reclaim(); // have to reclaim (this is flowvr shared buffer) m_sharing_chunks = false; } } diff --git a/plugins/flowvr/src/payloads/payload_data.h b/plugins/flowvr/src/payloads/payload_data.h index 430dd1045..4f078f4f5 100644 --- a/plugins/flowvr/src/payloads/payload_data.h +++ b/plugins/flowvr/src/payloads/payload_data.h @@ -120,10 +120,10 @@ public: { load_data_size_desc(config); if (!m_data_desc.empty()) { - m_ctx.add_data_callback([this](const std::string& name, PDI::Ref ref) { + m_ctx.data().add_data_callback([this](const std::string& name, PDI::Ref ref) { this->copy_data_to_ref(name, ref); }, m_data_desc); - m_ctx.add_empty_desc_access_callback([this](const std::string& name) { + m_ctx.data().add_empty_desc_access_callback([this](const std::string& name) { this->empty_desc_access(name); }, m_data_desc); } @@ -165,7 +165,7 @@ public: if (m_data_selection) { m_data_selection->evaluate(m_ctx)->data_from_dense_copy(ref.get(), m_flowvr_buffer.readAccess()); } else { - m_ctx[m_data_desc].default_type()->evaluate(m_ctx)->data_from_dense_copy(ref.get(), m_flowvr_buffer.readAccess()); + m_ctx.data()[m_data_desc].default_type()->evaluate(m_ctx)->data_from_dense_copy(ref.get(), m_flowvr_buffer.readAccess()); } } } else { @@ -185,13 +185,13 @@ public: if (m_flowvr_buffer.unique(flowvr::Buffer::ALLSEGMENTS)) { m_ctx.logger()->debug("(FlowVR) Input Data Payload ({}): Sharing (read/write) `{}'", m_name, m_data_desc); m_sharing_buffer = true; - m_ctx[m_data_desc].share(const_cast<flowvr::ubyte*>(m_flowvr_buffer.readAccess()), true, true); + m_ctx.data()[m_data_desc].share(const_cast<flowvr::ubyte*>(m_flowvr_buffer.readAccess()), true, true); m_ctx.logger()->debug("(FlowVR) Input Data Payload ({}): Share complete (read/write) `{}'", m_name, m_data_desc); } else { if (m_flowvr_buffer.valid()) { m_ctx.logger()->debug("(FlowVR) Input Data Payload ({}): Share (read only) `{}'", m_name, m_data_desc); m_sharing_buffer = true; - m_ctx[m_data_desc].share(const_cast<flowvr::ubyte*>(m_flowvr_buffer.readAccess()), true, false); + m_ctx.data()[m_data_desc].share(const_cast<flowvr::ubyte*>(m_flowvr_buffer.readAccess()), true, false); m_ctx.logger()->debug("(FlowVR) Input Data Payload ({}): Share complete (read only) `{}'", m_name, m_data_desc); } } @@ -199,7 +199,7 @@ public: m_ctx.logger()->warn("(FlowVR) Input Data Payload ({}): Flowvr data {} is empty or not valid", m_name, m_data_desc); m_ctx.logger()->debug("(FlowVR) Input Data Payload ({}): Sharing (nullptr) `{}'", m_name, m_data_desc); m_sharing_buffer = true; - m_ctx[m_data_desc].share(PDI::Ref(nullptr, nullptr, PDI::UNDEF_TYPE.clone_type(), true, false), false, false); + m_ctx.data()[m_data_desc].share(PDI::Ref(nullptr, nullptr, PDI::UNDEF_TYPE.clone_type(), true, false), false, false); m_ctx.logger()->debug("(FlowVR) Input Data Payload ({}): Share complete (nullptr) `{}'", m_name, m_data_desc); } } @@ -212,9 +212,9 @@ public: flowvr::Stamps get_message() override { if (!m_data_desc.empty()) { - if (!m_ctx[m_data_desc].empty() && m_sharing_buffer) { + if (!m_ctx.data()[m_data_desc].empty() && m_sharing_buffer) { m_ctx.logger()->debug("(FlowVR) Input Data Payload ({}): Reclaiming `{}'", m_name, m_data_desc); - m_ctx[m_data_desc].reclaim(); // have to reclaim (this is flowvr shared buffer) + m_ctx.data()[m_data_desc].reclaim(); // have to reclaim (this is flowvr shared buffer) m_sharing_buffer = false; m_ctx.logger()->debug("(FlowVR) Input Data Payload ({}): Reclaim complete `{}'", m_name, m_data_desc); } @@ -232,8 +232,8 @@ public: //update size in metadata long size = m_flowvr_buffer.getSize(); m_ctx.logger()->debug("(FlowVR) Input Data Payload ({}): Sharing size descripotr `{}' = {}", m_name, m_data_size_desc, size); - m_ctx[m_data_size_desc].share(&size, true, false); - m_ctx[m_data_size_desc].reclaim(); + m_ctx.data()[m_data_size_desc].share(&size, true, false); + m_ctx.data()[m_data_size_desc].reclaim(); m_ctx.logger()->debug("(FlowVR) Input Data Payload ({}): Share complete `{}'", m_name, m_data_size_desc); } } @@ -242,10 +242,10 @@ public: ~Input_payload_data() { - if (!m_ctx[m_data_desc].empty()) { + if (!m_ctx.data()[m_data_desc].empty()) { if (m_sharing_buffer) { m_ctx.logger()->debug("(FlowVR) Input Data Payload ({}): Reclaiming {}", m_name, m_data_desc); - m_ctx[m_data_desc].reclaim(); // have to reclaim (this is flowvr shared buffer) + m_ctx.data()[m_data_desc].reclaim(); // have to reclaim (this is flowvr shared buffer) m_sharing_buffer = false; m_ctx.logger()->debug("(FlowVR) Input Data Payload ({}): Reclaim complete {}", m_name, m_data_desc); } @@ -269,7 +269,7 @@ class Output_payload_data : public Output_payload, public Payload_data if (m_data_selection) { datasize = m_data_selection->evaluate(m_ctx)->datasize(); } else { - datasize = m_ctx[m_data_desc].default_type()->evaluate(m_ctx)->datasize(); + datasize = m_ctx.data()[m_data_desc].default_type()->evaluate(m_ctx)->datasize(); } m_ctx.logger()->debug("(FlowVR) Output Data Payload ({}): Allocating {} B", m_name, datasize); if (m_flowvr_buffer_pool) { @@ -295,10 +295,10 @@ public: } if (!m_data_desc.empty()) { - m_ctx.add_data_callback([this](const std::string& name, PDI::Ref ref) { + m_ctx.data().add_data_callback([this](const std::string& name, PDI::Ref ref) { this->copy_data_from_ref(name, ref); }, m_data_desc); - m_ctx.add_empty_desc_access_callback([this](const std::string& name) { + m_ctx.data().add_empty_desc_access_callback([this](const std::string& name) { this->empty_desc_access(name); }, m_data_desc); } @@ -344,7 +344,7 @@ public: if (m_data_selection) { m_data_selection->evaluate(m_ctx)->data_to_dense_copy(m_flowvr_buffer.writeAccess(), ref.get()); } else { - m_ctx[m_data_desc].default_type()->evaluate(m_ctx)->data_to_dense_copy(m_flowvr_buffer.writeAccess(), ref.get()); + m_ctx.data()[m_data_desc].default_type()->evaluate(m_ctx)->data_to_dense_copy(m_flowvr_buffer.writeAccess(), ref.get()); } } } @@ -366,7 +366,7 @@ public: } m_ctx.logger()->debug("(FlowVR) Output Data Payload ({}): Sharing `{}'", m_name, m_data_desc); m_sharing_buffer = true; //must be before share (to not copy data) - m_ctx[data_name].share(m_flowvr_buffer.writeAccess(), false, true); + m_ctx.data()[data_name].share(m_flowvr_buffer.writeAccess(), false, true); m_ctx.logger()->debug("(FlowVR) Output Data Payload ({}): Share complete `{}'", m_name, m_data_desc); } @@ -395,7 +395,7 @@ public: } if (m_sharing_buffer) { m_ctx.logger()->debug("(FlowVR) Output Data Payload ({}): Reclaiming `{}'", m_name, m_data_desc); - m_ctx[m_data_desc].reclaim(); // have to reclaim (this is flowvr shared buffer) + m_ctx.data()[m_data_desc].reclaim(); // have to reclaim (this is flowvr shared buffer) m_sharing_buffer = false; m_ctx.logger()->debug("(FlowVR) Output Data Payload ({}): Reclaim complete `{}'", m_name, m_data_desc); } @@ -404,10 +404,10 @@ public: ~Output_payload_data() { - if (!m_ctx[m_data_desc].empty()) { + if (!m_ctx.data()[m_data_desc].empty()) { if (m_sharing_buffer) { m_ctx.logger()->debug("(FlowVR) Output Data Payload ({}): Reclaiming `{}'", m_name, m_data_desc); - m_ctx[m_data_desc].reclaim(); // have to reclaim (this is flowvr shared buffer) + m_ctx.data()[m_data_desc].reclaim(); // have to reclaim (this is flowvr shared buffer) m_sharing_buffer = false; m_ctx.logger()->debug("(FlowVR) Output Data Payload ({}): Reclaim complete `{}'", m_name, m_data_desc); } diff --git a/plugins/flowvr/src/payloads/payload_mouse_event.h b/plugins/flowvr/src/payloads/payload_mouse_event.h index f045955b1..0247f4357 100644 --- a/plugins/flowvr/src/payloads/payload_mouse_event.h +++ b/plugins/flowvr/src/payloads/payload_mouse_event.h @@ -143,11 +143,11 @@ public: Payload_mouse_event{ctx, name, config, parent_port}, m_flowvr_input_port{parent_port} { - m_ctx.add_data_callback([this](const std::string& name, PDI::Ref ref) { + m_ctx.data().add_data_callback([this](const std::string& name, PDI::Ref ref) { this->data_pos_xy(name, ref); }, m_desc_pos_xy.first); for (const auto& desc_value : m_desc_value_map) { - m_ctx.add_data_callback([this](const std::string& name, PDI::Ref ref) { + m_ctx.data().add_data_callback([this](const std::string& name, PDI::Ref ref) { this->data(name, ref); }, desc_value.first); } @@ -268,11 +268,11 @@ public: Payload_mouse_event{ctx, name, config, parent_port}, m_flowvr_output_port{parent_port} { - m_ctx.add_data_callback([this](const std::string& name, PDI::Ref ref) { + m_ctx.data().add_data_callback([this](const std::string& name, PDI::Ref ref) { this->data_pos_xy(name, ref); }, m_desc_pos_xy.first); for (const auto& desc_value : m_desc_value_map) { - m_ctx.add_data_callback([this](const std::string& name, PDI::Ref ref) { + m_ctx.data().add_data_callback([this](const std::string& name, PDI::Ref ref) { this->data(name, ref); }, desc_value.first); } diff --git a/plugins/flowvr/src/port.h b/plugins/flowvr/src/port.h index ec18b2639..37558f9b2 100644 --- a/plugins/flowvr/src/port.h +++ b/plugins/flowvr/src/port.h @@ -63,7 +63,7 @@ protected: { PC_tree_t isConnected_node = PC_get(config, ".isConnected"); if (!PC_status(isConnected_node)) { - m_ctx.add_data_callback([this](const std::string& name, PDI::Ref ref) { + m_ctx.data().add_data_callback([this](const std::string& name, PDI::Ref ref) { this->get_status(name, ref); }, PDI::to_string(isConnected_node)); } diff --git a/plugins/flowvr/src/stamps/stamp.h b/plugins/flowvr/src/stamps/stamp.h index fdf824049..623f5077d 100644 --- a/plugins/flowvr/src/stamps/stamp.h +++ b/plugins/flowvr/src/stamps/stamp.h @@ -62,7 +62,7 @@ class Stamp { size_t stamp_size = 1; //default for scalars - const PDI::Datatype_uptr stamp_datatype = m_ctx[data_desc].default_type()->evaluate(m_ctx); + const PDI::Datatype_uptr stamp_datatype = m_ctx.data()[data_desc].default_type()->evaluate(m_ctx); const PDI::Scalar_datatype* scalar_datatype = dynamic_cast<PDI::Scalar_datatype*>(stamp_datatype.get()); const PDI::Array_datatype* array_datatype = dynamic_cast<PDI::Array_datatype*>(stamp_datatype.get()); diff --git a/plugins/flowvr/src/stamps/stamp_desc.h b/plugins/flowvr/src/stamps/stamp_desc.h index 6e4ce2cf0..45ff82d76 100644 --- a/plugins/flowvr/src/stamps/stamp_desc.h +++ b/plugins/flowvr/src/stamps/stamp_desc.h @@ -58,7 +58,7 @@ public: } else { m_stamp_info = new flowvr::StampInfo(m_name, flowvr::TypeInt::create()); } - m_ctx.add_data_callback([this](const std::string& name, PDI::Ref ref) { + m_ctx.data().add_data_callback([this](const std::string& name, PDI::Ref ref) { this->data(name, ref); }, data_desc); m_ctx.logger()->debug("(FlowVR) Int STAMP ({}): Created", m_name); @@ -109,7 +109,7 @@ public: Stamp_base{ctx, parent_port, name} { m_stamp_info = new flowvr::StampInfo(m_name, flowvr::TypeFloat::create()); - m_ctx.add_data_callback([this](const std::string& name, PDI::Ref ref) { + m_ctx.data().add_data_callback([this](const std::string& name, PDI::Ref ref) { this->data(name, ref); }, data_desc); m_ctx.logger()->debug("(FlowVR) Float STAMP ({}): Created", m_name); @@ -164,7 +164,7 @@ public: } else { m_stamp_info = new flowvr::StampInfo(m_name, flowvr::TypeString::create()); } - m_ctx.add_data_callback([this](const std::string& name, PDI::Ref ref) { + m_ctx.data().add_data_callback([this](const std::string& name, PDI::Ref ref) { this->data(name, ref); }, data_desc); m_ctx.logger()->debug("(FlowVR) String STAMP ({}): Created", m_name); @@ -216,7 +216,7 @@ public: m_value(size) { m_stamp_info = new flowvr::StampInfo(m_name, flowvr::TypeArray::create(size, flowvr::TypeInt::create())); - m_ctx.add_data_callback([this](const std::string& name, PDI::Ref ref) { + m_ctx.data().add_data_callback([this](const std::string& name, PDI::Ref ref) { this->data(name, ref); }, data_desc); m_ctx.logger()->debug("(FlowVR) Int array STAMP ({}): Created with size = {}", m_name, size); @@ -272,7 +272,7 @@ public: m_value(size) { m_stamp_info = new flowvr::StampInfo(m_name, flowvr::TypeArray::create(size, flowvr::TypeFloat::create())); - m_ctx.add_data_callback([this](const std::string& name, PDI::Ref ref) { + m_ctx.data().add_data_callback([this](const std::string& name, PDI::Ref ref) { this->data(name, ref); }, data_desc); m_ctx.logger()->debug("(FlowVR) Float array STAMP ({}): Created with size = {}", m_name, size); diff --git a/plugins/flowvr/src/trace.h b/plugins/flowvr/src/trace.h index c2f5f441f..180004263 100644 --- a/plugins/flowvr/src/trace.h +++ b/plugins/flowvr/src/trace.h @@ -65,7 +65,7 @@ class Trace */ void load_trace(PDI::Context& ctx, std::string name) { - const PDI::Datatype_uptr trace_datatype = ctx[m_on_data].default_type()->evaluate(ctx); + const PDI::Datatype_uptr trace_datatype = ctx.data()[m_on_data].default_type()->evaluate(ctx); const PDI::Scalar_datatype* scalar_datatype = dynamic_cast<PDI::Scalar_datatype*>(trace_datatype.get()); const PDI::Array_datatype* array_datatype = dynamic_cast<PDI::Array_datatype*>(trace_datatype.get()); @@ -93,7 +93,7 @@ public: { load_on_data(config); load_trace(ctx, name); - ctx.add_data_callback([this](const std::string& name, PDI::Ref ref) { + ctx.data().add_data_callback([this](const std::string& name, PDI::Ref ref) { this->write(name, ref); }, m_on_data); diff --git a/plugins/mpi/mpi.cxx b/plugins/mpi/mpi.cxx index 4d2989699..b02fa9b42 100644 --- a/plugins/mpi/mpi.cxx +++ b/plugins/mpi/mpi.cxx @@ -74,7 +74,7 @@ struct mpi_plugin: Plugin { void add_predefined(Context& ctx, const string& name, void* data, Datatype_uptr type) { - Data_descriptor& predef_desc = ctx.desc(name); + Data_descriptor& predef_desc = ctx.data().desc(name); if (!predef_desc.empty()) { throw Error{PDI_ERR_IMPL, "Predefined descriptor already defined `%s'", name.c_str()}; } @@ -132,7 +132,7 @@ struct mpi_plugin: Plugin { MPI_Fint comm_null_f = MPI_Comm_c2f(MPI_COMM_NULL); add_predefined(ctx, "MPI_COMM_NULL_F", &comm_null_f, mpi_comm_f_datatype.clone_type()); - ctx.add_data_callback([this](const std::string& name, PDI::Ref ref) { + ctx.data().add_data_callback([this](const std::string& name, PDI::Ref ref) { this->m_transtyper.data(name.c_str(), ref); }); diff --git a/plugins/mpi/mpi_comm_transtyper.h b/plugins/mpi/mpi_comm_transtyper.h index 4a2e0dfa1..39c19ac33 100644 --- a/plugins/mpi/mpi_comm_transtyper.h +++ b/plugins/mpi/mpi_comm_transtyper.h @@ -150,8 +150,8 @@ public: auto&& descs_it = m_descs.find(name); if (descs_it == m_descs.end()) return; - auto&& source_desc = m_ctx[descs_it->first]; - auto&& transtype_desc = m_ctx[descs_it->second]; + auto&& source_desc = m_ctx.data()[descs_it->first]; + auto&& transtype_desc = m_ctx.data()[descs_it->second]; auto&& source_type_uptr = source_desc.default_type()->evaluate(m_ctx); auto&& transtype_type_uptr = transtype_desc.default_type()->evaluate(m_ctx); diff --git a/plugins/pycall/pycall.cxx b/plugins/pycall/pycall.cxx index 7ae6d8f63..bccbee6d4 100644 --- a/plugins/pycall/pycall.cxx +++ b/plugins/pycall/pycall.cxx @@ -92,7 +92,7 @@ public: { Ref r = m_value.to_ref(ctx); - PDI::Data_descriptor& desc = ctx.desc(m_name); + PDI::Data_descriptor& desc = ctx.data().desc(m_name); pyscope[m_name.c_str()] = to_python(r); } diff --git a/plugins/test/test.cxx b/plugins/test/test.cxx index 33a4b2f20..b38d0e70d 100644 --- a/plugins/test/test.cxx +++ b/plugins/test/test.cxx @@ -54,7 +54,7 @@ struct test_plugin: Plugin { test_plugin(Context& ctx, PC_tree_t): Plugin {ctx} { - ctx.add_data_callback([this](const std::string& name, Ref ref) { + ctx.data().add_data_callback([this](const std::string& name, Ref ref) { this->data(name, ref); }); ctx.add_event_callback([this](const std::string& name) { diff --git a/plugins/trace/trace.cxx b/plugins/trace/trace.cxx index 5f6aeacf0..4b101c9aa 100644 --- a/plugins/trace/trace.cxx +++ b/plugins/trace/trace.cxx @@ -54,7 +54,7 @@ struct trace_plugin: Plugin { trace_plugin(Context& ctx, PC_tree_t): Plugin {ctx} { - ctx.add_data_callback([this](const std::string& name, Ref ref) { + ctx.data().add_data_callback([this](const std::string& name, Ref ref) { this->data(name, ref); }); ctx.add_event_callback([this](const std::string& name) { diff --git a/plugins/user_code/user_code.cxx b/plugins/user_code/user_code.cxx index 905fbeb51..91bfe4cca 100644 --- a/plugins/user_code/user_code.cxx +++ b/plugins/user_code/user_code.cxx @@ -111,7 +111,7 @@ public: }; // class Alias ExposedAlias::ExposedAlias(Context& ctx, const Alias& alias): - m_desc{&ctx.desc(alias.m_name.c_str())} + m_desc{&ctx.data().desc(alias.m_name.c_str())} { try { m_desc->share(alias.m_value.to_ref(ctx), false, false); @@ -209,7 +209,7 @@ struct user_code_plugin: Plugin { opt_each(datas, [&](PC_tree_t one_data) { each(one_data, [&](PC_tree_t function_name, PC_tree_t parameters) { Trigger data_trigger{to_string(function_name), parameters}; - ctx.add_data_callback([&ctx, data_trigger](const std::string& name, Ref ref) mutable { + ctx.data().add_data_callback([&ctx, data_trigger](const std::string& name, Ref ref) mutable { data_trigger.call(ctx); }, to_string(data_name)); }); diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 685e6923f..58ba85790 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -128,6 +128,8 @@ set(PDI_SRC global_context.cxx data_descriptor.cxx data_descriptor_impl.cxx + data_store.cxx + data_store_impl.cxx datatype.cxx datatype_template.cxx error.cxx diff --git a/src/context.cxx b/src/context.cxx index fecc2044c..2956ffc44 100644 --- a/src/context.cxx +++ b/src/context.cxx @@ -24,65 +24,11 @@ #include "config.h" -#include <iostream> -#include <memory> - -#include <dlfcn.h> - -#include "pdi/paraconf_wrapper.h" -#include "pdi/plugin.h" -#include "pdi/ref_any.h" -#include "pdi/error.h" - #include "pdi/context.h" namespace PDI { -using std::move; -using std::string; -using std::unordered_map; -using std::unique_ptr; - -Context::Iterator::Iterator(const unordered_map<string, unique_ptr<Data_descriptor>>::iterator& data): - m_data(data) -{} - -Context::Iterator::Iterator(unordered_map<string, unique_ptr<Data_descriptor>>::iterator&& data): - m_data(move(data)) -{} - -Data_descriptor* Context::Iterator::operator-> () -{ - return m_data->second.get(); -} - -Data_descriptor& Context::Iterator::operator* () -{ - return *m_data->second; -} - -Context::Iterator& Context::Iterator::operator++ () -{ - ++m_data; - return *this; -} - -bool Context::Iterator::operator!= (const Iterator& o) -{ - return (m_data != o.m_data); -} - -Context::Iterator Context::get_iterator(const std::unordered_map<std::string, unique_ptr<Data_descriptor>>::iterator& data) -{ - return data; -} - -Context::Iterator Context::get_iterator(std::unordered_map<std::string, unique_ptr<Data_descriptor>>::iterator&& data) -{ - return move(data); -} - Context::~Context() = default; -} +} //namespace PDI diff --git a/src/context_proxy.cxx b/src/context_proxy.cxx index da6561916..d56ee8fab 100644 --- a/src/context_proxy.cxx +++ b/src/context_proxy.cxx @@ -25,9 +25,10 @@ #include <spdlog/spdlog.h> #include "pdi/context.h" -#include "pdi/context_proxy.h" #include "pdi/logger.h" +#include "pdi/context_proxy.h" + namespace PDI { Context_proxy::Context_proxy(Context& ctx, std::string plugin_name, PC_tree_t logging_tree): @@ -35,34 +36,9 @@ Context_proxy::Context_proxy(Context& ctx, std::string plugin_name, PC_tree_t lo m_plugin_logger{configure_logger(logging_tree, plugin_name)} {} -Data_descriptor& Context_proxy::desc(const std::string& name) -{ - return m_real_context.desc(name); -} - -Data_descriptor& Context_proxy::desc(const char* name) -{ - return m_real_context.desc(name); -} - -Data_descriptor& Context_proxy::operator[](const std::string& name) -{ - return m_real_context[name]; -} - -Data_descriptor& Context_proxy::operator[](const char* name) +Data_store& Context_proxy::data() { - return m_real_context[name]; -} - -Context::Iterator Context_proxy::begin() -{ - return m_real_context.begin(); -} - -Context::Iterator Context_proxy::end() -{ - return m_real_context.end(); + return m_real_context.data(); } void Context_proxy::event(const char* name) @@ -95,19 +71,9 @@ std::function<void()> Context_proxy::add_init_callback(const std::function<void( return m_real_context.add_init_callback(callback); } -std::function<void()> Context_proxy::add_data_callback(const std::function<void(const std::string&, Ref)>& callback, const std::string& name) -{ - return m_real_context.add_data_callback(callback, name); -} - std::function<void()> Context_proxy::add_event_callback(const std::function<void(const std::string&)>& callback, const std::string& name) { return m_real_context.add_event_callback(callback, name); } -std::function<void()> Context_proxy::add_empty_desc_access_callback(const std::function<void(const std::string&)>& callback, const std::string& name) -{ - return m_real_context.add_empty_desc_access_callback(callback, name); -} - } //namespace PDI diff --git a/src/data_descriptor.cxx b/src/data_descriptor.cxx index ae936f647..61bfd3d79 100644 --- a/src/data_descriptor.cxx +++ b/src/data_descriptor.cxx @@ -22,11 +22,23 @@ * THE SOFTWARE. ******************************************************************************/ +#include "pdi/data_store.h" + #include "pdi/data_descriptor.h" namespace PDI { +void Data_descriptor::trigger_data_callbacks(Data_store& data_store) +{ + data_store.trigger_data_callbacks(name(), ref()); +} + +void Data_descriptor::trigger_empty_desc_access_callbacks(Data_store& data_store) +{ + data_store.trigger_empty_desc_access_callbacks(name()); +} + Data_descriptor::~Data_descriptor() = default; } // namespace PDI diff --git a/src/data_descriptor_impl.cxx b/src/data_descriptor_impl.cxx index 79521c3f4..9e79289c9 100644 --- a/src/data_descriptor_impl.cxx +++ b/src/data_descriptor_impl.cxx @@ -27,7 +27,6 @@ #include <functional> #include <iostream> #include <memory> -#include <vector> #include <spdlog/spdlog.h> @@ -48,7 +47,6 @@ using std::nothrow; using std::stack; using std::string; using std::unique_ptr; -using std::vector; struct Data_descriptor_impl::Ref_holder { @@ -78,7 +76,7 @@ struct Data_descriptor_impl::Ref_holder::Impl: Data_descriptor_impl::Ref_holder }; -Data_descriptor_impl::Data_descriptor_impl(Global_context& ctx, const char* name): +Data_descriptor_impl::Data_descriptor_impl(Context& ctx, const char* name): m_context{ctx}, m_type{UNDEF_TYPE.clone_type()}, m_name{name}, @@ -145,40 +143,8 @@ Ref Data_descriptor_impl::ref() { assert((!metadata() || !m_refs.empty()) && "metadata descriptors should always keep a placeholder"); if (m_refs.empty()) { - std::vector<std::reference_wrapper<const std::function<void(const std::string&)>>> empty_desc_callbacks; - //add named callbacks - auto callback_it_pair = m_context.m_named_empty_desc_access_callbacks.equal_range(m_name); - for (auto it = callback_it_pair.first; it != callback_it_pair.second; it++) { - empty_desc_callbacks.emplace_back(std::cref(it->second)); - } - //add the unnamed callbacks - for (auto it = m_context.m_empty_desc_access_callbacks.begin(); it != m_context.m_empty_desc_access_callbacks.end(); it++) { - empty_desc_callbacks.emplace_back(std::cref(*it)); - } - //call gathered callbacks - vector<Error> errors; - for (const std::function<void(const std::string&)>& callback : empty_desc_callbacks) { - try { - callback(m_name); - //TODO: remove the faulty plugin in case of error? - } catch (const Error& e) { - errors.emplace_back(e); - } catch (const exception& e) { - errors.emplace_back(PDI_ERR_SYSTEM, e.what()); - } catch (...) { - errors.emplace_back(PDI_ERR_SYSTEM, "Not std::exception based error"); - } - } - if (!errors.empty()) { - if (1 == errors.size()) { - throw Error{errors.front().status(), "Error while triggering empty desc access `%s': %s", m_name.c_str(), errors.front().what()}; - } - string errmsg = "Multiple (" + std::to_string(errors.size()) + ") errors while triggering empty desc access `" + m_name + "':\n"; - for (auto&& err: errors) { - errmsg += string(err.what()) + "\n"; - } - throw Error{PDI_ERR_SYSTEM, "%s", errmsg.c_str()}; - } + //trigger empty desc callbacks + Data_descriptor::trigger_empty_desc_access_callbacks(m_context.data()); //at least one plugin should share a Ref if (m_refs.empty()) { @@ -242,40 +208,8 @@ void* Data_descriptor_impl::share(Ref data_ref, bool read, bool write) throw Error{PDI_ERR_RIGHT, "Unable to grant requested rights"}; } - std::vector<std::reference_wrapper<const std::function<void(const std::string&, Ref)>>> data_callbacks; - //add named callbacks - auto callback_it_pair = m_context.m_named_data_callbacks.equal_range(m_name); - for (auto it = callback_it_pair.first; it != callback_it_pair.second; it++) { - data_callbacks.emplace_back(std::cref(it->second)); - } - //add the unnamed callbacks - for (auto it = m_context.m_data_callbacks.begin(); it != m_context.m_data_callbacks.end(); it++) { - data_callbacks.emplace_back(std::cref(*it)); - } - //call gathered callbacks - vector<Error> errors; - for (const std::function<void(const std::string&, Ref)>& callback : data_callbacks) { - try { - callback(m_name, ref()); - //TODO: remove the faulty plugin in case of error? - } catch (const Error& e) { - errors.emplace_back(e); - } catch (const exception& e) { - errors.emplace_back(PDI_ERR_SYSTEM, e.what()); - } catch (...) { - errors.emplace_back(PDI_ERR_SYSTEM, "Not std::exception based error"); - } - } - if (!errors.empty()) { - if (1 == errors.size()) { - throw Error{errors.front().status(), "Error while triggering data share `%s': %s", m_name, errors.front().what()}; - } - string errmsg = "Multiple (" + std::to_string(errors.size()) + ") errors while triggering data share `" + m_name + "':\n"; - for (auto&& err: errors) { - errmsg += string(err.what()) + "\n"; - } - throw Error{PDI_ERR_SYSTEM, "%s", errmsg.c_str()}; - } + //trigger data callbacks + Data_descriptor::trigger_data_callbacks(m_context.data()); assert((!metadata() || !m_refs.empty()) && "metadata descriptors should always keep a placeholder"); return result; diff --git a/src/data_descriptor_impl.h b/src/data_descriptor_impl.h index bffd9f63c..99621a7ca 100644 --- a/src/data_descriptor_impl.h +++ b/src/data_descriptor_impl.h @@ -36,20 +36,20 @@ #include <pdi/datatype_template.h> #include <pdi/ref_any.h> -#include "global_context.h" +#include "data_store_impl.h" namespace PDI { class PDI_EXPORT Data_descriptor_impl : public Data_descriptor { - friend class Global_context; + friend class Data_store_impl; friend class Descriptor_test_handler; struct PDI_NO_EXPORT Ref_holder; /// The context this descriptor is part of - Global_context& m_context; + Context& m_context; /// References to the values of this descriptor std::stack<std::unique_ptr<Ref_holder>> m_refs; @@ -63,7 +63,7 @@ class PDI_EXPORT Data_descriptor_impl : public Data_descriptor /** Create an empty descriptor */ - Data_descriptor_impl(Global_context& ctx, const char* name); + Data_descriptor_impl(Context& ctx, const char* name); Data_descriptor_impl(const Data_descriptor_impl&) = delete; diff --git a/src/data_store.cxx b/src/data_store.cxx new file mode 100644 index 000000000..41b8603b3 --- /dev/null +++ b/src/data_store.cxx @@ -0,0 +1,78 @@ +/******************************************************************************* + * Copyright (C) 2019 Commissariat a l'energie atomique et aux energies alternatives (CEA) + * Copyright (C) 2019 Institute of Bioorganic Chemistry Polish Academy of Science (PSNC) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of CEA nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#include "pdi/data_store.h" + + +namespace PDI { + +using std::move; +using std::string; +using std::unordered_map; +using std::unique_ptr; + +Data_store::Iterator::Iterator(const unordered_map<string, unique_ptr<Data_descriptor>>::iterator& data): + m_data(data) +{} + +Data_store::Iterator::Iterator(unordered_map<string, unique_ptr<Data_descriptor>>::iterator&& data): + m_data(move(data)) +{} + +Data_descriptor* Data_store::Iterator::operator-> () +{ + return m_data->second.get(); +} + +Data_descriptor& Data_store::Iterator::operator* () +{ + return *m_data->second; +} + +Data_store::Iterator& Data_store::Iterator::operator++ () +{ + ++m_data; + return *this; +} + +bool Data_store::Iterator::operator!= (const Iterator& o) +{ + return (m_data != o.m_data); +} + +Data_store::Iterator Data_store::get_iterator(const std::unordered_map<std::string, unique_ptr<Data_descriptor>>::iterator& data) +{ + return data; +} + +Data_store::Iterator Data_store::get_iterator(std::unordered_map<std::string, unique_ptr<Data_descriptor>>::iterator&& data) +{ + return move(data); +} + +Data_store::~Data_store() = default; + +} + diff --git a/src/data_store_impl.cxx b/src/data_store_impl.cxx new file mode 100644 index 000000000..3a6989ddb --- /dev/null +++ b/src/data_store_impl.cxx @@ -0,0 +1,197 @@ +/******************************************************************************* + * Copyright (C) 2019 Commissariat a l'energie atomique et aux energies alternatives (CEA) + * Copyright (C) 2019 Institute of Bioorganic Chemistry Polish Academy of Science (PSNC) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of CEA nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#include <iostream> +#include <memory> +#include <vector> + +#include "pdi/paraconf_wrapper.h" +#include "pdi/plugin.h" +#include "pdi/ref_any.h" +#include "pdi/error.h" + +#include "data_descriptor_impl.h" + +#include "data_store_impl.h" + + +namespace PDI { + + +using std::exception; +using std::function; +using std::move; +using std::reference_wrapper; +using std::string; +using std::to_string; +using std::unordered_map; +using std::unique_ptr; +using std::vector; + +Data_store_impl::Data_store_impl(Context& ctx): + m_context{ctx} +{} + + +Data_descriptor& Data_store_impl::desc(const char* name) +{ + return *(m_descriptors.emplace(name, unique_ptr<Data_descriptor> {new Data_descriptor_impl{m_context, name}}).first->second); +} + +Data_descriptor& Data_store_impl::desc(const string& name) +{ + return desc(name.c_str()); +} + +Data_descriptor& Data_store_impl::operator[](const char* name) +{ + return desc(name); +} + +Data_descriptor& Data_store_impl::operator[](const string& name) +{ + return desc(name.c_str()); +} + +Data_store::Iterator Data_store_impl::begin() +{ + return Data_store::get_iterator(m_descriptors.begin()); +} + +Data_store::Iterator Data_store_impl::end() +{ + return Data_store::get_iterator(m_descriptors.end()); +} + +std::function<void()> Data_store_impl::add_data_callback(const std::function<void(const std::string&, Ref)>& callback, const std::string& name) +{ + if (name.empty()) { + m_data_callbacks.emplace_back(callback); + auto it = --m_data_callbacks.end(); + return [it, this]() { + this->m_data_callbacks.erase(it); + }; + } else { + auto it = m_named_data_callbacks.emplace(name, callback); + return [it, this]() { + this->m_named_data_callbacks.erase(it); + }; + } +} + +std::function<void()> Data_store_impl::add_empty_desc_access_callback(const std::function<void(const std::string&)>& callback, const std::string& name) +{ + if (name.empty()) { + m_empty_desc_access_callbacks.emplace_back(callback); + auto it = --m_empty_desc_access_callbacks.end(); + return [it, this]() { + this->m_empty_desc_access_callbacks.erase(it); + }; + } else { + auto it = m_named_empty_desc_access_callbacks.emplace(name, callback); + return [it, this]() { + this->m_named_empty_desc_access_callbacks.erase(it); + }; + } +} + +void Data_store_impl::trigger_data_callbacks(const string& name, Ref ref) +{ + vector<reference_wrapper<const function<void(const string&, Ref)>>> data_callbacks; + //add named callbacks + auto callback_it_pair = m_named_data_callbacks.equal_range(name); + for (auto it = callback_it_pair.first; it != callback_it_pair.second; it++) { + data_callbacks.emplace_back(std::cref(it->second)); + } + //add the unnamed callbacks + for (auto it = m_data_callbacks.begin(); it != m_data_callbacks.end(); it++) { + data_callbacks.emplace_back(std::cref(*it)); + } + //call gathered callbacks + vector<Error> errors; + for (const function<void(const string&, Ref)>& callback : data_callbacks) { + try { + callback(name, ref); + //TODO: remove the faulty plugin in case of error? + } catch (const Error& e) { + errors.emplace_back(e); + } catch (const exception& e) { + errors.emplace_back(PDI_ERR_SYSTEM, e.what()); + } catch (...) { + errors.emplace_back(PDI_ERR_SYSTEM, "Not std::exception based error"); + } + } + if (!errors.empty()) { + if (1 == errors.size()) { + throw Error{errors.front().status(), "Error while triggering data share `%s': %s", name, errors.front().what()}; + } + string errmsg = "Multiple (" + to_string(errors.size()) + ") errors while triggering data share `" + name + "':\n"; + for (auto&& err: errors) { + errmsg += string(err.what()) + "\n"; + } + throw Error{PDI_ERR_SYSTEM, "%s", errmsg.c_str()}; + } +} + +void Data_store_impl::trigger_empty_desc_access_callbacks(const string& name) +{ + vector<reference_wrapper<const function<void(const string&)>>> empty_desc_callbacks; + //add named callbacks + auto callback_it_pair = m_named_empty_desc_access_callbacks.equal_range(name); + for (auto it = callback_it_pair.first; it != callback_it_pair.second; it++) { + empty_desc_callbacks.emplace_back(std::cref(it->second)); + } + //add the unnamed callbacks + for (auto it = m_empty_desc_access_callbacks.begin(); it != m_empty_desc_access_callbacks.end(); it++) { + empty_desc_callbacks.emplace_back(std::cref(*it)); + } + //call gathered callbacks + vector<Error> errors; + for (const std::function<void(const std::string&)>& callback : empty_desc_callbacks) { + try { + callback(name); + //TODO: remove the faulty plugin in case of error? + } catch (const Error& e) { + errors.emplace_back(e); + } catch (const exception& e) { + errors.emplace_back(PDI_ERR_SYSTEM, e.what()); + } catch (...) { + errors.emplace_back(PDI_ERR_SYSTEM, "Not std::exception based error"); + } + } + if (!errors.empty()) { + if (1 == errors.size()) { + throw Error{errors.front().status(), "Error while triggering empty desc access `%s': %s", name.c_str(), errors.front().what()}; + } + string errmsg = "Multiple (" + to_string(errors.size()) + ") errors while triggering empty desc access `" + name + "':\n"; + for (auto&& err: errors) { + errmsg += string(err.what()) + "\n"; + } + throw Error{PDI_ERR_SYSTEM, "%s", errmsg.c_str()}; + } +} + +} + diff --git a/src/data_store_impl.h b/src/data_store_impl.h new file mode 100644 index 000000000..7bbe883b7 --- /dev/null +++ b/src/data_store_impl.h @@ -0,0 +1,107 @@ +/******************************************************************************* + * Copyright (C) 2019 Commissariat a l'energie atomique et aux energies alternatives (CEA) + * Copyright (C) 2019 Institute of Bioorganic Chemistry Polish Academy of Science (PSNC) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of CEA nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#ifndef PDI_DATA_STORE_IMPL_H_ +#define PDI_DATA_STORE_IMPL_H_ + +#include <functional> +#include <list> +#include <map> +#include <memory> +#include <string> +#include <unordered_map> + +#include <pdi/pdi_fwd.h> +#include <pdi/data_descriptor.h> +#include <pdi/data_store.h> +#include <pdi/datatype_template.h> +#include <pdi/ref_any.h> + + +namespace PDI { + +class PDI_EXPORT Data_store_impl: public Data_store +{ +private: + Context& m_context; + + /// Descriptors of the data + std::unordered_map<std::string, std::unique_ptr<Data_descriptor>> m_descriptors; + /** + * Callbacks called when any data is available + * + * This must be a list, because valid iterators are needed to properly remove the callback by plugin + */ + std::list<std::function<void(const std::string&, Ref)>> m_data_callbacks; + + /** + * Callbacks called when specified data is available. + * + * This must be an ordered multimap, because valid iterators are needed to properly remove the callback by plugin + */ + std::multimap<std::string, std::function<void(const std::string&, Ref)>> m_named_data_callbacks; + + /** + * Callbacks called on any empty desc access + * + * This must be a list, because valid iterators are needed to properly remove the callback by plugin + */ + std::list<std::function<void(const std::string&)>> m_empty_desc_access_callbacks; + + /** + * Callbacks called on specified empty desc access + * + * This must be an ordered multimap, because valid iterators are needed to properly remove the callback by plugin + */ + std::multimap<std::string, std::function<void(const std::string&)>> m_named_empty_desc_access_callbacks; + + void trigger_data_callbacks(const std::string& name, Ref ref) override; + + void trigger_empty_desc_access_callbacks(const std::string& name) override; + +public: + Data_store_impl(Context& ctx); + + Data_descriptor& desc(const std::string& name) override; + + Data_descriptor& desc(const char* name) override; + + Data_descriptor& operator[](const std::string& name) override; + + Data_descriptor& operator[](const char* name) override; + + Iterator begin() override; + + Iterator end() override; + + std::function<void()> add_data_callback(const std::function<void(const std::string&, Ref)>& callback, const std::string& name = {}) override; + + std::function<void()> add_empty_desc_access_callback(const std::function<void(const std::string&)>& callback, const std::string& name = {}) override; + +}; + +} // namespace PDI + +#endif // PDI_DATA_STORE_IMPL_H_ diff --git a/src/expression.cxx b/src/expression.cxx index d477cdd40..2f3dab902 100644 --- a/src/expression.cxx +++ b/src/expression.cxx @@ -34,10 +34,12 @@ #include "pdi/array_datatype.h" #include "pdi/context.h" +#include "pdi/datatype.h" +#include "pdi/data_descriptor.h" +#include "pdi/error.h" #include "pdi/ref_any.h" #include "pdi/scalar_datatype.h" -#include "pdi/error.h" -#include "pdi/datatype.h" + #include "pdi/expression.h" @@ -444,7 +446,7 @@ unique_ptr<Expression::Impl> Expression::Impl::Reference_expression::clone() con long Expression::Impl::Reference_expression::to_long(Context& ctx) const try { - if (Ref_r ref = ctx.desc(m_referenced.c_str()).ref()) { + if (Ref_r ref = ctx.data().desc(m_referenced.c_str()).ref()) { const Datatype* type = &ref.type(); long stride = 1; long idx = 0; @@ -505,7 +507,7 @@ Ref Expression::Impl::Reference_expression::to_ref(Context& ctx) const true }; } - return ctx.desc(m_referenced.c_str()).ref(); + return ctx.data().desc(m_referenced.c_str()).ref(); } unique_ptr<Expression::Impl> Expression::Impl::Reference_expression::parse(char const** val_str) diff --git a/src/global_context.cxx b/src/global_context.cxx index 59a4b11a5..7387d1b09 100644 --- a/src/global_context.cxx +++ b/src/global_context.cxx @@ -39,6 +39,7 @@ #include "pdi/error.h" #include "data_descriptor_impl.h" +#include "data_store_impl.h" #include "global_context.h" @@ -67,7 +68,7 @@ void load_data(Context& ctx, PC_tree_t node, bool is_metadata) int map_len = len(node); for (int map_id = 0; map_id < map_len; ++map_id) { - Data_descriptor& dsc = ctx.desc(to_string(PC_get(node, "{%d}", map_id)).c_str()); + Data_descriptor& dsc = ctx.data().desc(to_string(PC_get(node, "{%d}", map_id)).c_str()); dsc.metadata(is_metadata); dsc.default_type(ctx.datatype(PC_get(node, "<%d>", map_id))); } @@ -224,7 +225,8 @@ void Global_context::finalize() } Global_context::Global_context(PC_tree_t conf): - m_logger{configure_logger(PC_get(conf, ".logging"), "global")} + m_logger{configure_logger(PC_get(conf, ".logging"), "global")}, + m_data{new Data_store_impl{*this}} { // load basic datatypes Datatype_template::load_basic_datatypes(*this); @@ -265,34 +267,9 @@ Global_context::Global_context(PC_tree_t conf): } } -Data_descriptor& Global_context::desc(const char* name) +Data_store& Global_context::data() { - return *(m_descriptors.emplace(name, unique_ptr<Data_descriptor> {new Data_descriptor_impl{*this, name}}).first->second); -} - -Data_descriptor& Global_context::desc(const string& name) -{ - return desc(name.c_str()); -} - -Data_descriptor& Global_context::operator[](const char* name) -{ - return desc(name); -} - -Data_descriptor& Global_context::operator[](const string& name) -{ - return desc(name.c_str()); -} - -Global_context::Iterator Global_context::begin() -{ - return Context::get_iterator(m_descriptors.begin()); -} - -Global_context::Iterator Global_context::end() -{ - return Context::get_iterator(m_descriptors.end()); + return *m_data; } void Global_context::event(const char* name) @@ -380,22 +357,6 @@ std::function<void()> Global_context::add_init_callback(const std::function<void }; } -std::function<void()> Global_context::add_data_callback(const std::function<void(const std::string&, Ref)>& callback, const std::string& name) -{ - if (name.empty()) { - m_data_callbacks.emplace_back(callback); - auto it = --m_data_callbacks.end(); - return [it, this]() { - this->m_data_callbacks.erase(it); - }; - } else { - auto it = m_named_data_callbacks.emplace(name, callback); - return [it, this]() { - this->m_named_data_callbacks.erase(it); - }; - } -} - std::function<void()> Global_context::add_event_callback(const std::function<void(const std::string&)>& callback, const std::string& name) { if (name.empty()) { @@ -412,21 +373,4 @@ std::function<void()> Global_context::add_event_callback(const std::function<voi } } -std::function<void()> Global_context::add_empty_desc_access_callback(const std::function<void(const std::string&)>& callback, const std::string& name) -{ - if (name.empty()) { - m_empty_desc_access_callbacks.emplace_back(callback); - auto it = --m_empty_desc_access_callbacks.end(); - return [it, this]() { - this->m_empty_desc_access_callbacks.erase(it); - }; - } else { - auto it = m_named_empty_desc_access_callbacks.emplace(name, callback); - return [it, this]() { - this->m_named_empty_desc_access_callbacks.erase(it); - }; - } -} - - } diff --git a/src/global_context.h b/src/global_context.h index a91dfd443..6e18191c9 100644 --- a/src/global_context.h +++ b/src/global_context.h @@ -28,7 +28,6 @@ #include <list> #include <map> #include <memory> -#include <stack> #include <string> #include <unordered_map> @@ -45,8 +44,7 @@ namespace PDI { class PDI_EXPORT Global_context : public Context { private: - friend class Data_descriptor_impl; - + /// Global logger of PDI, should be constructed first, destroyed last Logger_sptr m_logger; @@ -59,8 +57,8 @@ private: /// Datatype_template constructors available in PDI std::unordered_map<std::string, Datatype_template_parser> m_datatype_parsers; - /// Descriptors of the data - std::unordered_map<std::string, std::unique_ptr<Data_descriptor>> m_descriptors; + /// Data store of the context + std::unique_ptr<Data_store> m_data; /// The loaded plugins - need to be after m_descriptors (to guarantee proper destroy order) std::unordered_map<std::string, std::unique_ptr<Plugin>> m_plugins; @@ -72,20 +70,6 @@ private: */ std::list<std::function<void()>> m_init_callbacks; - /** - * Callbacks called when any data is available - * - * This must be a list, because valid iterators are needed to properly remove the callback by plugin - */ - std::list<std::function<void(const std::string&, Ref)>> m_data_callbacks; - - /** - * Callbacks called when specified data is available. - * - * This must be an ordered multimap, because valid iterators are needed to properly remove the callback by plugin - */ - std::multimap<std::string, std::function<void(const std::string&, Ref)>> m_named_data_callbacks; - /** * Callbacks called on any event * @@ -100,20 +84,6 @@ private: */ std::multimap<std::string, std::function<void(const std::string&)>> m_named_event_callbacks; - /** - * Callbacks called on any empty desc access - * - * This must be a list, because valid iterators are needed to properly remove the callback by plugin - */ - std::list<std::function<void(const std::string&)>> m_empty_desc_access_callbacks; - - /** - * Callbacks called on specified empty desc access - * - * This must be an ordered multimap, because valid iterators are needed to properly remove the callback by plugin - */ - std::multimap<std::string, std::function<void(const std::string&)>> m_named_empty_desc_access_callbacks; - Global_context(const Global_context&) = delete; Global_context(Global_context&&) = delete; @@ -129,33 +99,8 @@ public: Global_context(PC_tree_t conf); - /** Accesses the descriptor for a specific name. Might be uninitialized - */ - Data_descriptor& desc(const std::string& name) override; - - /** Accesses the descriptor for a specific name. Might be uninitialized - */ - Data_descriptor& desc(const char* name) override; - - /** Accesses the descriptor for a specific name. Might be uninitialized - */ - Data_descriptor& operator[](const std::string& name) override; + Data_store& data() override; - /** Accesses the descriptor for a specific name. Might be uninitialized - */ - Data_descriptor& operator[](const char* name) override; - - /** Returns an iterator on the first descriptor - */ - Iterator begin() override; - - /** Returns an iterator past the last descriptor - */ - Iterator end() override; - - /** Triggers a PDI "event" - * \param[in] name the event name - */ void event(const char* name) override; Logger_sptr logger() const override; @@ -166,11 +111,8 @@ public: std::function<void()> add_init_callback(const std::function<void()>& callback) override; - std::function<void()> add_data_callback(const std::function<void(const std::string&, Ref)>& callback, const std::string& name = {}) override; - std::function<void()> add_event_callback(const std::function<void(const std::string&)>& callback, const std::string& name = {}) override; - std::function<void()> add_empty_desc_access_callback(const std::function<void(const std::string&)>& callback, const std::string& name = {}) override; }; } // namespace PDI diff --git a/src/pdi.cxx b/src/pdi.cxx index 798194044..838569753 100644 --- a/src/pdi.cxx +++ b/src/pdi.cxx @@ -58,7 +58,6 @@ using std::make_shared; using std::move; using std::setfill; using std::setw; -using std::stack; using std::string; using std::stringstream; using std::underlying_type; @@ -279,7 +278,7 @@ PDI_status_t PDI_share(const char* name, void* buffer, PDI_inout_t access) try { Paraconf_wrapper fw; - Global_context::context()[name].share(buffer, access & PDI_OUT, access & PDI_IN); + Global_context::context().data()[name].share(buffer, access & PDI_OUT, access & PDI_IN); return PDI_OK; } catch (const Error& e) { @@ -296,7 +295,7 @@ PDI_status_t PDI_access(const char* name, void** buffer, PDI_inout_t inout) try { Paraconf_wrapper fw; - Data_descriptor& desc = Global_context::context()[name]; + Data_descriptor& desc = Global_context::context().data()[name]; *buffer = desc.share(desc.ref(), inout & PDI_IN, inout & PDI_OUT); return PDI_OK; } catch (const Error& e) @@ -314,7 +313,7 @@ PDI_status_t PDI_release(const char* name) try { Paraconf_wrapper fw; - Global_context::context()[name].release(); + Global_context::context().data()[name].release(); return PDI_OK; } catch (const Error& e) { @@ -331,7 +330,7 @@ PDI_status_t PDI_reclaim(const char* name) try { Paraconf_wrapper fw; - Global_context::context()[name].reclaim(); + Global_context::context().data()[name].reclaim(); return PDI_OK; } catch (const Error& e) { diff --git a/src/python/pdi.cxx b/src/python/pdi.cxx index ed9af83ba..1fda64533 100644 --- a/src/python/pdi.cxx +++ b/src/python/pdi.cxx @@ -146,7 +146,7 @@ PYBIND11_MODULE(_pdi, m) static_cast<bool>(access & PDI_IN) }; try { - Global_context::context()[name].share(r, false, false); + Global_context::context().data()[name].share(r, false, false); } catch (...) { // on error, do not free the data as would be done automatically otherwise r.release(); @@ -156,7 +156,7 @@ PYBIND11_MODULE(_pdi, m) m.def("access", [](const char* name, PDI_inout_t inout) { Paraconf_wrapper fw; - Data_descriptor& desc = Global_context::context()[name]; + Data_descriptor& desc = Global_context::context().data()[name]; pyarr result = to_python(desc.ref()); desc.share(desc.ref(), inout & PDI_IN, inout & PDI_OUT); if (!(inout & PDI_OUT)) pybind11::detail::array_descriptor_proxy(result.ptr())->flags &= ~pybind11::detail::npy_api::NPY_ARRAY_WRITEABLE_; @@ -165,11 +165,11 @@ PYBIND11_MODULE(_pdi, m) m.def("release", [](const char* name) { Paraconf_wrapper fw; - Global_context::context()[name].release(); + Global_context::context().data()[name].release(); }, "Releases ownership of a data shared with PDI. PDI is then responsible to free the associated memory whenever necessary."); m.def("reclaim", [](const char* name) { Paraconf_wrapper fw; - Global_context::context()[name].reclaim(); + Global_context::context().data()[name].reclaim(); }, "Reclaims ownership of a data buffer shared with PDI. PDI does not manage the buffer memory anymore."); } diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index d1d22b453..b10dfc637 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -60,6 +60,7 @@ set(PDI_unit_tests_SRC PDI_array_datatype.cxx PDI_context.cxx PDI_data_descriptor.cxx + PDI_data_store.cxx PDI_error.cxx PDI_expression.cxx PDI_initialize_plugins.cxx diff --git a/tests/PDI_context.cxx b/tests/PDI_context.cxx index 58f0ff200..1d32f0d08 100644 --- a/tests/PDI_context.cxx +++ b/tests/PDI_context.cxx @@ -55,172 +55,6 @@ struct ContextTest : public ::testing::Test { unique_ptr<Context> test_context; }; -/* - * Name: ContextTest.desc_string_uninitialized - * - * Tested functions: PDI::Context::desc(string) - * - * Description: Checks if accessesing uninitialzied descriptor - * creates a new one. - */ -TEST_F(ContextTest, desc_string_uninitialized) -{ - string desc_name{"test_desc"}; - Data_descriptor& desc = this->test_context->desc(desc_name); - ASSERT_EQ(desc_name, desc.name()); -} - -/* - * Name: ContextTest.desc_string_initialized - * - * Tested functions: PDI::Context::desc(string) - * - * Description: Checks if accessesing a descriptor - * returns correct one. - */ -TEST_F(ContextTest, desc_string_initialized) -{ - string desc_name{"desc1"}; - //put desc1 first to check if the same desc is returned later - Data_descriptor& desc1 = this->test_context->desc(desc_name); - - Data_descriptor& desc = this->test_context->desc(desc_name); - ASSERT_EQ(desc_name, desc.name()); - //desc1 and desc should have the same address if they are the same desc - ASSERT_EQ(&desc1, &desc); -} - -/* - * Name: ContextTest.desc_cstring_uninitialized - * - * Tested functions: PDI::Context::desc(const char*) - * - * Description: Checks if accessesing uninitialzied descriptor - * creates a new one. - */ -TEST_F(ContextTest, desc_cstring_uninitialized) -{ - const char* desc_name = "test_desc"; - Data_descriptor& desc = this->test_context->desc(desc_name); - ASSERT_STREQ(desc_name, desc.name().c_str()); -} - -/* - * Name: ContextTest.desc_cstring_initialized - * - * Tested functions: PDI::Context::desc(const char*) - * - * Description: Checks if accessesing a descriptor - * returns correct one. - */ -TEST_F(ContextTest, desc_cstring_initialized) -{ - const char* desc_name = "desc1"; - //put desc1 first to check if the same desc is returned later - Data_descriptor& desc1 = this->test_context->desc(desc_name); - - Data_descriptor& desc = this->test_context->desc(desc_name); - ASSERT_STREQ(desc_name, desc.name().c_str()); - //desc1 and desc should have the same address if they are the same desc - ASSERT_EQ(&desc1, &desc); -} - -/* - * Name: ContextTest.operator_string_uninitialized - * - * Tested functions: PDI::Context::operator[](string) - * - * Description: Checks if accessesing uninitialzied descriptor - * creates a new one. - */ -TEST_F(ContextTest, operator_string_uninitialized) -{ - string desc_name{"test_desc"}; - Data_descriptor& desc = (*this->test_context)[desc_name]; - ASSERT_EQ(desc_name, desc.name()); -} - -/* - * Name: ContextTest.operator_string_initialized - * - * Tested functions: PDI::Context::operator[](string) - * - * Description: Checks if accessesing a descriptor - * returns correct one. - */ -TEST_F(ContextTest, operator_string_initialized) -{ - string desc_name{"desc1"}; - //put desc1 first to check if the same desc is returned later - Data_descriptor& desc1 = this->test_context->desc(desc_name); - - Data_descriptor& desc = (*this->test_context)[desc_name]; - ASSERT_EQ(desc_name, desc.name()); - //desc1 and desc should have the same address if they are the same desc - ASSERT_EQ(&desc1, &desc); -} - -/* - * Name: ContextTest.operator_cstring_uninitialized - * - * Tested functions: PDI::Context::operator[](const char*) - * - * Description: Checks if accessesing uninitialzied descriptor - * creates a new one. - */ -TEST_F(ContextTest, operator_cstring_uninitialized) -{ - const char* desc_name = "test_desc"; - Data_descriptor& desc = (*this->test_context)[desc_name]; - ASSERT_STREQ(desc_name, desc.name().c_str()); -} - -/* - * Name: ContextTest.operator_cstring_initialized - * - * Tested functions: PDI::Context::operator[](const char*) - * - * Description: Checks if accessesing a descriptor - * returns correct one. - */ -TEST_F(ContextTest, operator_cstring_initialized) -{ - const char* desc_name = "desc1"; - //put desc1 first to check if the same desc is returned later - Data_descriptor& desc1 = this->test_context->desc(desc_name); - - Data_descriptor& desc = (*this->test_context)[desc_name]; - ASSERT_STREQ(desc_name, desc.name().c_str()); - //desc1 and desc should have the same address if they are the same desc - ASSERT_EQ(&desc1, &desc); -} - -/* - * Name: ContextTest.iterator - * - * Tested functions: PDI::Context::begin(), - * PDI::Context::end() - * - * Description: Checks if tested functions - * return correct iterators. - */ -TEST_F(ContextTest, iterator) -{ - //put some descriptors inside context - set<string> desc_names{"desc1", "desc2", "desc3"}; - for (auto& desc_name: desc_names) { - this->test_context->desc(desc_name); - } - auto begin = this->test_context->begin(); - auto end = this->test_context->end(); - - for (auto it = begin; it != end; ++it) { - auto name = desc_names.find((*it).name()); - ASSERT_EQ(it->name(), (*it).name()); - ASSERT_TRUE(name != desc_names.end()); - } -} - /* * Name: ContextTest.add_event * @@ -319,306 +153,3 @@ TEST_F(ContextTest, add_remove_event) ASSERT_EQ(x, 126); ASSERT_EQ(y, 159); } - -/* - * Name: ContextTest.add_data_callback - * - * Tested functions: PDI::Context::add_data_callback - * - * - * Description: Checks if callback is - * correctly called on data share. - * - */ -TEST_F(ContextTest, add_data_callback) -{ - string data_x {"data_x"}; - this->test_context->desc(data_x).default_type(Scalar_datatype{Scalar_kind::SIGNED, sizeof(int)}.clone_type()); - int x = 0; - this->test_context->add_data_callback([](const std::string& name, Ref ref) { - Ref_w ref_write {ref}; - int* x = static_cast<int*>(ref_write.get()); - *x += 42; - ASSERT_STREQ(name.c_str(), "data_x"); - }); - ASSERT_EQ(x, 0); - this->test_context->desc("data_x").share(&x, true, true); - this->test_context->desc("data_x").reclaim(); - ASSERT_EQ(x, 42); -} - -/* - * Name: ContextTest.add_named_data_callback - * - * Tested functions: PDI::Context::add_data_callback - * - * - * Description: Checks if named callback is - * correctly called on data share. - * - */ -TEST_F(ContextTest, add_named_data_callback) -{ - string data_x {"data_x"}; - string data_y {"data_y"}; - this->test_context->desc(data_x).default_type(Scalar_datatype{Scalar_kind::SIGNED, sizeof(int)}.clone_type()); - this->test_context->desc(data_y).default_type(Scalar_datatype{Scalar_kind::SIGNED, sizeof(int)}.clone_type()); - int x = 0; - int y = 0; - this->test_context->add_data_callback([](const std::string& name, Ref ref) { - Ref_w ref_write {ref}; - int* x = static_cast<int*>(ref_write.get()); - *x += 42; - ASSERT_STREQ(name.c_str(), "data_x"); - }, "data_x"); - ASSERT_EQ(x, 0); - ASSERT_EQ(y, 0); - this->test_context->desc("data_x").share(&x, true, true); - this->test_context->desc("data_x").reclaim(); - ASSERT_EQ(x, 42); - ASSERT_EQ(y, 0); -} - -/* - * Name: ContextTest.remove_data_callback - * - * Tested functions: PDI::Context::add_data_callback - * - * - * Description: Checks if callback is - * correctly called on share - * and removes it. - */ -TEST_F(ContextTest, remove_data_callback) -{ - string data_x {"data_x"}; - this->test_context->desc(data_x).default_type(Scalar_datatype{Scalar_kind::SIGNED, sizeof(int)}.clone_type()); - int x = 0; - auto erase_x = this->test_context->add_data_callback([](const std::string& name, Ref ref) { - Ref_w ref_write {ref}; - int* x = static_cast<int*>(ref_write.get()); - *x += 42; - ASSERT_STREQ(name.c_str(), "data_x"); - }); - ASSERT_EQ(x, 0); - this->test_context->desc("data_x").share(&x, true, true); - this->test_context->desc("data_x").reclaim(); - ASSERT_EQ(x, 42); - erase_x(); - this->test_context->desc("data_x").share(&x, true, true); - this->test_context->desc("data_x").reclaim(); - ASSERT_EQ(x, 42); -} - -/* - * Name: ContextTest.remove_named_data_callback - * - * Tested functions: PDI::Context::add_data_callback - * - * - * Description: Checks if named callback is - * correctly called on data share. - * - */ -TEST_F(ContextTest, remove_named_data_callback) -{ - string data_x {"data_x"}; - string data_y {"data_y"}; - this->test_context->desc(data_x).default_type(Scalar_datatype{Scalar_kind::SIGNED, sizeof(int)}.clone_type()); - this->test_context->desc(data_y).default_type(Scalar_datatype{Scalar_kind::SIGNED, sizeof(int)}.clone_type()); - int x = 0; - int y = 0; - auto erase_x = this->test_context->add_data_callback([](const std::string& name, Ref ref) { - Ref_w ref_write {ref}; - int* x = static_cast<int*>(ref_write.get()); - *x += 42; - ASSERT_STREQ(name.c_str(), "data_x"); - }, "data_x"); - ASSERT_EQ(x, 0); - ASSERT_EQ(y, 0); - this->test_context->desc("data_x").share(&x, true, true); - this->test_context->desc("data_x").reclaim(); - ASSERT_EQ(x, 42); - ASSERT_EQ(y, 0); - erase_x(); - this->test_context->desc("data_x").share(&x, true, true); - this->test_context->desc("data_x").reclaim(); - ASSERT_EQ(x, 42); - ASSERT_EQ(y, 0); -} - -/* - * Name: ContextTest.add_remove_data_callback - * - * Tested functions: PDI::Context::add_data_callback - * - * - * Description: Checks if callback is - * correctly called on share - * and removes it several times. - * - */ -TEST_F(ContextTest, add_remove_data_callback) -{ - string data_x {"data_x"}; - string data_y {"data_y"}; - Data_descriptor& desc_x = this->test_context->desc(data_x); - Data_descriptor& desc_y = this->test_context->desc(data_y); - this->test_context->desc(data_x).default_type(Scalar_datatype{Scalar_kind::SIGNED, sizeof(int)}.clone_type()); - this->test_context->desc(data_y).default_type(Scalar_datatype{Scalar_kind::SIGNED, sizeof(int)}.clone_type()); - int x = 0; - int y = 0; - auto erase_x = this->test_context->add_data_callback([](const std::string& name, Ref ref) { - Ref_w ref_write {ref}; - int* x = static_cast<int*>(ref_write.get()); - *x += std::stoi(name); - }); - auto erase_y = this->test_context->add_data_callback([](const std::string& name, Ref ref) { - Ref_w ref_write {ref}; - int* y = static_cast<int*>(ref_write.get()); - *y += std::stoi(name) + 1; - }); - ASSERT_EQ(x, 0); - ASSERT_EQ(y, 0); - this->test_context->desc("1").share(&x, true, true); - this->test_context->desc("1").reclaim(); - ASSERT_EQ(x, 3); - ASSERT_EQ(y, 0); - this->test_context->desc("2").share(&y, true, true); - this->test_context->desc("2").reclaim(); - ASSERT_EQ(x, 3); - ASSERT_EQ(y, 5); - erase_x(); - this->test_context->desc("3").share(&x, true, true); - this->test_context->desc("3").reclaim(); - ASSERT_EQ(x, 7); - ASSERT_EQ(y, 5); - this->test_context->desc("4").share(&y, true, true); - this->test_context->desc("4").reclaim(); - ASSERT_EQ(x, 7); - ASSERT_EQ(y, 10); - erase_y(); - this->test_context->desc("5").share(&x, true, true); - this->test_context->desc("6").share(&y, true, true); - this->test_context->desc("5").reclaim(); - this->test_context->desc("6").reclaim(); - ASSERT_EQ(x, 7); - ASSERT_EQ(y, 10); -} - -/* - * Name: ContextTest.add_remove_named_data_callback - * - * Tested functions: PDI::Context::add_data_callback - * - * - * Description: Checks if named callback is - * correctly called on share - * and removes it several times. - * - */ -TEST_F(ContextTest, add_remove_named_data_callback) -{ - string data_x {"data_x"}; - string data_y {"data_y"}; - Data_descriptor& desc_x = this->test_context->desc(data_x); - Data_descriptor& desc_y = this->test_context->desc(data_y); - this->test_context->desc(data_x).default_type(Scalar_datatype{Scalar_kind::SIGNED, sizeof(int)}.clone_type()); - this->test_context->desc(data_y).default_type(Scalar_datatype{Scalar_kind::SIGNED, sizeof(int)}.clone_type()); - int x = 0; - int y = 0; - auto erase_x = this->test_context->add_data_callback([](const std::string& name, Ref ref) { - Ref_w ref_write {ref}; - int* x = static_cast<int*>(ref_write.get()); - *x += 42; - ASSERT_STREQ(name.c_str(), "data_x"); - }, "data_x"); - auto erase_y = this->test_context->add_data_callback([](const std::string& name, Ref ref) { - Ref_w ref_write {ref}; - int* y = static_cast<int*>(ref_write.get()); - *y += 53; - ASSERT_STREQ(name.c_str(), "data_y"); - }, "data_y"); - ASSERT_EQ(x, 0); - ASSERT_EQ(y, 0); - this->test_context->desc("data_x").share(&x, true, true); - this->test_context->desc("data_x").reclaim(); - ASSERT_EQ(x, 42); - ASSERT_EQ(y, 0); - this->test_context->desc("data_y").share(&y, true, true); - this->test_context->desc("data_y").reclaim(); - ASSERT_EQ(x, 42); - ASSERT_EQ(y, 53); - erase_x(); - this->test_context->desc("data_x").share(&x, true, true); - this->test_context->desc("data_x").reclaim(); - ASSERT_EQ(x, 42); - ASSERT_EQ(y, 53); - this->test_context->desc("data_y").share(&y, true, true); - this->test_context->desc("data_y").reclaim(); - ASSERT_EQ(x, 42); - ASSERT_EQ(y, 106); - erase_y(); - this->test_context->desc("data_y").share(&y, true, true); - this->test_context->desc("data_y").reclaim(); - ASSERT_EQ(x, 42); - ASSERT_EQ(y, 106); -} - -/* - * Name: ContextTest.add_empty_desc_callback - * - * Tested functions: PDI::Context::add_empty_desc_access_callback - * - * - * Description: Checks if callback is - * correctly called on empty desc access. - */ -TEST_F(ContextTest, add_empty_desc_callback) -{ - string data_x {"data_x"}; - this->test_context->desc(data_x).default_type(Scalar_datatype{Scalar_kind::SIGNED, sizeof(int)}.clone_type()); - this->test_context->add_empty_desc_access_callback([this](const std::string& name) { - int* x = new int; - *x = 42; - this->test_context->desc(name).share(x, true, true); - }); - Ref_r ref_read {this->test_context->desc(data_x).ref()}; - int x = *static_cast<const int*>(ref_read.get()); - ASSERT_EQ(x, 42); - int* data = static_cast<int*>(this->test_context->desc(data_x).reclaim()); - delete data; -} - -/* - * Name: ContextTest.remove_empty_desc_callback - * - * Tested functions: PDI::Context::add_empty_desc_access_callback - * - * - * Description: Checks if callback is - * correctly called on empty desc access - * and removes it. - */ -TEST_F(ContextTest, remove_empty_desc_callback) -{ - string data_x {"data_x"}; - this->test_context->desc(data_x).default_type(Scalar_datatype{Scalar_kind::SIGNED, sizeof(int)}.clone_type()); - auto erase_x = this->test_context->add_empty_desc_access_callback([this](const std::string& name) { - int* x = new int; - *x = 42; - this->test_context->desc(name).share(x, true, true); - }); - Ref_r ref_read {this->test_context->desc(data_x).ref()}; - int x = *static_cast<const int*>(ref_read.get()); - ASSERT_EQ(x, 42); - int* data = static_cast<int*>(this->test_context->desc(data_x).reclaim()); - delete data; - erase_x(); - try { - Ref ref_x {this->test_context->desc(data_x).ref()}; - FAIL(); - } catch (Error e) { - ASSERT_EQ(e.status(), PDI_ERR_VALUE); - } -} diff --git a/tests/PDI_data_store.cxx b/tests/PDI_data_store.cxx new file mode 100644 index 000000000..13ab681bd --- /dev/null +++ b/tests/PDI_data_store.cxx @@ -0,0 +1,534 @@ +/******************************************************************************* + * Copyright (C) 2019 Institute of Bioorganic Chemistry Polish Academy of Science (PSNC) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of CEA nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#include <gtest/gtest.h> + +#include <pdi/data_store.h> +#include <pdi/paraconf_wrapper.h> +#include <pdi/plugin.h> +#include <pdi/scalar_datatype.h> + +#include "mocks/context_mock.h" +#include "data_store_impl.h" + + +using namespace PDI; +using std::string; +using std::unique_ptr; +using std::set; + +/* + * Struct prepared for DataStoreTest. + */ +struct DataStoreTest : public ::testing::Test { + + void SetUp() override + { + test_data_store.reset(new Data_store_impl{context_mock}); + } + + Paraconf_wrapper fw; + MockContext context_mock; + unique_ptr<Data_store> test_data_store; +}; + +/* + * Name: DataStoreTest.desc_string_uninitialized + * + * Tested functions: PDI::Data_store::desc(string) + * + * Description: Checks if accessesing uninitialzied descriptor + * creates a new one. + */ +TEST_F(DataStoreTest, desc_string_uninitialized) +{ + string desc_name{"test_desc"}; + Data_descriptor& desc = this->test_data_store->desc(desc_name); + ASSERT_EQ(desc_name, desc.name()); +} + +/* + * Name: DataStoreTest.desc_string_initialized + * + * Tested functions: PDI::Data_store::desc(string) + * + * Description: Checks if accessesing a descriptor + * returns correct one. + */ +TEST_F(DataStoreTest, desc_string_initialized) +{ + string desc_name{"desc1"}; + //put desc1 first to check if the same desc is returned later + Data_descriptor& desc1 = this->test_data_store->desc(desc_name); + + Data_descriptor& desc = this->test_data_store->desc(desc_name); + ASSERT_EQ(desc_name, desc.name()); + //desc1 and desc should have the same address if they are the same desc + ASSERT_EQ(&desc1, &desc); +} + +/* + * Name: DataStoreTest.desc_cstring_uninitialized + * + * Tested functions: PDI::Data_store::desc(const char*) + * + * Description: Checks if accessesing uninitialzied descriptor + * creates a new one. + */ +TEST_F(DataStoreTest, desc_cstring_uninitialized) +{ + const char* desc_name = "test_desc"; + Data_descriptor& desc = this->test_data_store->desc(desc_name); + ASSERT_STREQ(desc_name, desc.name().c_str()); +} + +/* + * Name: DataStoreTest.desc_cstring_initialized + * + * Tested functions: PDI::Data_store::desc(const char*) + * + * Description: Checks if accessesing a descriptor + * returns correct one. + */ +TEST_F(DataStoreTest, desc_cstring_initialized) +{ + const char* desc_name = "desc1"; + //put desc1 first to check if the same desc is returned later + Data_descriptor& desc1 = this->test_data_store->desc(desc_name); + + Data_descriptor& desc = this->test_data_store->desc(desc_name); + ASSERT_STREQ(desc_name, desc.name().c_str()); + //desc1 and desc should have the same address if they are the same desc + ASSERT_EQ(&desc1, &desc); +} + +/* + * Name: DataStoreTest.operator_string_uninitialized + * + * Tested functions: PDI::Data_store::operator[](string) + * + * Description: Checks if accessesing uninitialzied descriptor + * creates a new one. + */ +TEST_F(DataStoreTest, operator_string_uninitialized) +{ + string desc_name{"test_desc"}; + Data_descriptor& desc = (*this->test_data_store)[desc_name]; + ASSERT_EQ(desc_name, desc.name()); +} + +/* + * Name: DataStoreTest.operator_string_initialized + * + * Tested functions: PDI::Data_store::operator[](string) + * + * Description: Checks if accessesing a descriptor + * returns correct one. + */ +TEST_F(DataStoreTest, operator_string_initialized) +{ + string desc_name{"desc1"}; + //put desc1 first to check if the same desc is returned later + Data_descriptor& desc1 = this->test_data_store->desc(desc_name); + + Data_descriptor& desc = (*this->test_data_store)[desc_name]; + ASSERT_EQ(desc_name, desc.name()); + //desc1 and desc should have the same address if they are the same desc + ASSERT_EQ(&desc1, &desc); +} + +/* + * Name: DataStoreTest.operator_cstring_uninitialized + * + * Tested functions: PDI::Data_store::operator[](const char*) + * + * Description: Checks if accessesing uninitialzied descriptor + * creates a new one. + */ +TEST_F(DataStoreTest, operator_cstring_uninitialized) +{ + const char* desc_name = "test_desc"; + Data_descriptor& desc = (*this->test_data_store)[desc_name]; + ASSERT_STREQ(desc_name, desc.name().c_str()); +} + +/* + * Name: DataStoreTest.operator_cstring_initialized + * + * Tested functions: PDI::Data_store::operator[](const char*) + * + * Description: Checks if accessesing a descriptor + * returns correct one. + */ +TEST_F(DataStoreTest, operator_cstring_initialized) +{ + const char* desc_name = "desc1"; + //put desc1 first to check if the same desc is returned later + Data_descriptor& desc1 = this->test_data_store->desc(desc_name); + + Data_descriptor& desc = (*this->test_data_store)[desc_name]; + ASSERT_STREQ(desc_name, desc.name().c_str()); + //desc1 and desc should have the same address if they are the same desc + ASSERT_EQ(&desc1, &desc); +} + +/* + * Name: DataStoreTest.iterator + * + * Tested functions: PDI::Data_store::begin(), + * PDI::Data_store::end() + * + * Description: Checks if tested functions + * return correct iterators. + */ +TEST_F(DataStoreTest, iterator) +{ + //put some descriptors inside Data_store + set<string> desc_names{"desc1", "desc2", "desc3"}; + + for (auto& desc_name: desc_names) { + this->test_data_store->desc(desc_name); + } + auto begin = this->test_data_store->begin(); + auto end = this->test_data_store->end(); + + for (auto it = begin; it != end; ++it) { + auto name = desc_names.find((*it).name()); + ASSERT_EQ(it->name(), (*it).name()); + ASSERT_TRUE(name != desc_names.end()); + } +} + +/* + * Name: DataStoreTest.add_data_callback + * + * Tested functions: PDI::Data_store::add_data_callback + * + * + * Description: Checks if callback is + * correctly called on data share. + * + */ +TEST_F(DataStoreTest, add_data_callback) +{ + string data_x {"data_x"}; + EXPECT_CALL(context_mock, data()).WillOnce(testing::ReturnRef(*test_data_store)); + this->test_data_store->desc(data_x).default_type(Scalar_datatype{Scalar_kind::SIGNED, sizeof(int)}.clone_type()); + int x = 0; + this->test_data_store->add_data_callback([](const std::string& name, Ref ref) { + Ref_w ref_write {ref}; + int* x = static_cast<int*>(ref_write.get()); + *x += 42; + ASSERT_STREQ(name.c_str(), "data_x"); + }); + ASSERT_EQ(x, 0); + this->test_data_store->desc("data_x").share(&x, true, true); + this->test_data_store->desc("data_x").reclaim(); + ASSERT_EQ(x, 42); +} + +/* + * Name: DataStoreTest.add_named_data_callback + * + * Tested functions: PDI::Data_store::add_data_callback + * + * + * Description: Checks if named callback is + * correctly called on data share. + * + */ +TEST_F(DataStoreTest, add_named_data_callback) +{ + string data_x {"data_x"}; + string data_y {"data_y"}; + EXPECT_CALL(context_mock, data()).WillOnce(testing::ReturnRef(*test_data_store)); + this->test_data_store->desc(data_x).default_type(Scalar_datatype{Scalar_kind::SIGNED, sizeof(int)}.clone_type()); + this->test_data_store->desc(data_y).default_type(Scalar_datatype{Scalar_kind::SIGNED, sizeof(int)}.clone_type()); + int x = 0; + int y = 0; + this->test_data_store->add_data_callback([](const std::string& name, Ref ref) { + Ref_w ref_write {ref}; + int* x = static_cast<int*>(ref_write.get()); + *x += 42; + ASSERT_STREQ(name.c_str(), "data_x"); + }, "data_x"); + ASSERT_EQ(x, 0); + ASSERT_EQ(y, 0); + this->test_data_store->desc("data_x").share(&x, true, true); + this->test_data_store->desc("data_x").reclaim(); + ASSERT_EQ(x, 42); + ASSERT_EQ(y, 0); +} + +/* + * Name: DataStoreTest.remove_data_callback + * + * Tested functions: PDI::Data_store::add_data_callback + * + * + * Description: Checks if callback is + * correctly called on share + * and removes it. + */ +TEST_F(DataStoreTest, remove_data_callback) +{ + string data_x {"data_x"}; + EXPECT_CALL(context_mock, data()).Times(2).WillRepeatedly(testing::ReturnRef(*test_data_store)); + this->test_data_store->desc(data_x).default_type(Scalar_datatype{Scalar_kind::SIGNED, sizeof(int)}.clone_type()); + int x = 0; + auto erase_x = this->test_data_store->add_data_callback([](const std::string& name, Ref ref) { + Ref_w ref_write {ref}; + int* x = static_cast<int*>(ref_write.get()); + *x += 42; + ASSERT_STREQ(name.c_str(), "data_x"); + }); + ASSERT_EQ(x, 0); + this->test_data_store->desc("data_x").share(&x, true, true); + this->test_data_store->desc("data_x").reclaim(); + ASSERT_EQ(x, 42); + erase_x(); + this->test_data_store->desc("data_x").share(&x, true, true); + this->test_data_store->desc("data_x").reclaim(); + ASSERT_EQ(x, 42); +} + +/* + * Name: DataStoreTest.remove_named_data_callback + * + * Tested functions: PDI::Data_store::add_data_callback + * + * + * Description: Checks if named callback is + * correctly called on data share. + * + */ +TEST_F(DataStoreTest, remove_named_data_callback) +{ + string data_x {"data_x"}; + string data_y {"data_y"}; + EXPECT_CALL(context_mock, data()).Times(2).WillRepeatedly(testing::ReturnRef(*test_data_store)); + this->test_data_store->desc(data_x).default_type(Scalar_datatype{Scalar_kind::SIGNED, sizeof(int)}.clone_type()); + this->test_data_store->desc(data_y).default_type(Scalar_datatype{Scalar_kind::SIGNED, sizeof(int)}.clone_type()); + int x = 0; + int y = 0; + auto erase_x = this->test_data_store->add_data_callback([](const std::string& name, Ref ref) { + Ref_w ref_write {ref}; + int* x = static_cast<int*>(ref_write.get()); + *x += 42; + ASSERT_STREQ(name.c_str(), "data_x"); + }, "data_x"); + ASSERT_EQ(x, 0); + ASSERT_EQ(y, 0); + this->test_data_store->desc("data_x").share(&x, true, true); + this->test_data_store->desc("data_x").reclaim(); + ASSERT_EQ(x, 42); + ASSERT_EQ(y, 0); + erase_x(); + this->test_data_store->desc("data_x").share(&x, true, true); + this->test_data_store->desc("data_x").reclaim(); + ASSERT_EQ(x, 42); + ASSERT_EQ(y, 0); +} + +/* + * Name: DataStoreTest.add_remove_data_callback + * + * Tested functions: PDI::Data_store::add_data_callback + * + * + * Description: Checks if callback is + * correctly called on share + * and removes it several times. + * + */ +TEST_F(DataStoreTest, add_remove_data_callback) +{ + string data_x {"data_x"}; + string data_y {"data_y"}; + Data_descriptor& desc_x = this->test_data_store->desc(data_x); + Data_descriptor& desc_y = this->test_data_store->desc(data_y); + this->test_data_store->desc(data_x).default_type(Scalar_datatype{Scalar_kind::SIGNED, sizeof(int)}.clone_type()); + this->test_data_store->desc(data_y).default_type(Scalar_datatype{Scalar_kind::SIGNED, sizeof(int)}.clone_type()); + int x = 0; + int y = 0; + auto erase_x = this->test_data_store->add_data_callback([](const std::string& name, Ref ref) { + Ref_w ref_write {ref}; + int* x = static_cast<int*>(ref_write.get()); + *x += std::stoi(name); + }); + auto erase_y = this->test_data_store->add_data_callback([](const std::string& name, Ref ref) { + Ref_w ref_write {ref}; + int* y = static_cast<int*>(ref_write.get()); + *y += std::stoi(name) + 1; + }); + ASSERT_EQ(x, 0); + ASSERT_EQ(y, 0); + EXPECT_CALL(context_mock, data()) + .Times(6).WillRepeatedly(testing::ReturnRef(*test_data_store)); + this->test_data_store->desc("1").share(&x, true, true); + this->test_data_store->desc("1").reclaim(); + ASSERT_EQ(x, 3); + ASSERT_EQ(y, 0); + this->test_data_store->desc("2").share(&y, true, true); + this->test_data_store->desc("2").reclaim(); + ASSERT_EQ(x, 3); + ASSERT_EQ(y, 5); + erase_x(); + this->test_data_store->desc("3").share(&x, true, true); + this->test_data_store->desc("3").reclaim(); + ASSERT_EQ(x, 7); + ASSERT_EQ(y, 5); + this->test_data_store->desc("4").share(&y, true, true); + this->test_data_store->desc("4").reclaim(); + ASSERT_EQ(x, 7); + ASSERT_EQ(y, 10); + erase_y(); + this->test_data_store->desc("5").share(&x, true, true); + this->test_data_store->desc("6").share(&y, true, true); + this->test_data_store->desc("5").reclaim(); + this->test_data_store->desc("6").reclaim(); + ASSERT_EQ(x, 7); + ASSERT_EQ(y, 10); +} + +/* + * Name: DataStoreTest.add_remove_named_data_callback + * + * Tested functions: PDI::Data_store::add_data_callback + * + * + * Description: Checks if named callback is + * correctly called on share + * and removes it several times. + * + */ +TEST_F(DataStoreTest, add_remove_named_data_callback) +{ + string data_x {"data_x"}; + string data_y {"data_y"}; + Data_descriptor& desc_x = this->test_data_store->desc(data_x); + Data_descriptor& desc_y = this->test_data_store->desc(data_y); + this->test_data_store->desc(data_x).default_type(Scalar_datatype{Scalar_kind::SIGNED, sizeof(int)}.clone_type()); + this->test_data_store->desc(data_y).default_type(Scalar_datatype{Scalar_kind::SIGNED, sizeof(int)}.clone_type()); + int x = 0; + int y = 0; + auto erase_x = this->test_data_store->add_data_callback([](const std::string& name, Ref ref) { + Ref_w ref_write {ref}; + int* x = static_cast<int*>(ref_write.get()); + *x += 42; + ASSERT_STREQ(name.c_str(), "data_x"); + }, "data_x"); + auto erase_y = this->test_data_store->add_data_callback([](const std::string& name, Ref ref) { + Ref_w ref_write {ref}; + int* y = static_cast<int*>(ref_write.get()); + *y += 53; + ASSERT_STREQ(name.c_str(), "data_y"); + }, "data_y"); + ASSERT_EQ(x, 0); + ASSERT_EQ(y, 0); + EXPECT_CALL(context_mock, data()) + .Times(5).WillRepeatedly(testing::ReturnRef(*test_data_store)); + this->test_data_store->desc("data_x").share(&x, true, true); + this->test_data_store->desc("data_x").reclaim(); + ASSERT_EQ(x, 42); + ASSERT_EQ(y, 0); + this->test_data_store->desc("data_y").share(&y, true, true); + this->test_data_store->desc("data_y").reclaim(); + ASSERT_EQ(x, 42); + ASSERT_EQ(y, 53); + erase_x(); + this->test_data_store->desc("data_x").share(&x, true, true); + this->test_data_store->desc("data_x").reclaim(); + ASSERT_EQ(x, 42); + ASSERT_EQ(y, 53); + this->test_data_store->desc("data_y").share(&y, true, true); + this->test_data_store->desc("data_y").reclaim(); + ASSERT_EQ(x, 42); + ASSERT_EQ(y, 106); + erase_y(); + this->test_data_store->desc("data_y").share(&y, true, true); + this->test_data_store->desc("data_y").reclaim(); + ASSERT_EQ(x, 42); + ASSERT_EQ(y, 106); +} + +/* + * Name: DataStoreTest.add_empty_desc_callback + * + * Tested functions: PDI::Data_store::add_empty_desc_access_callback + * + * + * Description: Checks if callback is + * correctly called on empty desc access. + */ +TEST_F(DataStoreTest, add_empty_desc_callback) +{ + string data_x {"data_x"}; + EXPECT_CALL(context_mock, data()).WillRepeatedly(testing::ReturnRef(*test_data_store)); + this->test_data_store->desc(data_x).default_type(Scalar_datatype{Scalar_kind::SIGNED, sizeof(int)}.clone_type()); + this->test_data_store->add_empty_desc_access_callback([this](const std::string& name) { + int* x = new int; + *x = 42; + this->test_data_store->desc(name).share(x, true, true); + }); + Ref_r ref_read {this->test_data_store->desc(data_x).ref()}; + int x = *static_cast<const int*>(ref_read.get()); + ASSERT_EQ(x, 42); + int* data = static_cast<int*>(this->test_data_store->desc(data_x).reclaim()); + delete data; +} + +/* + * Name: DataStoreTest.remove_empty_desc_callback + * + * Tested functions: PDI::Data_store::add_empty_desc_access_callback + * + * + * Description: Checks if callback is + * correctly called on empty desc access + * and removes it. + */ +TEST_F(DataStoreTest, remove_empty_desc_callback) +{ + string data_x {"data_x"}; + EXPECT_CALL(context_mock, data()).WillRepeatedly(testing::ReturnRef(*test_data_store)); + this->test_data_store->desc(data_x).default_type(Scalar_datatype{Scalar_kind::SIGNED, sizeof(int)}.clone_type()); + auto erase_x = this->test_data_store->add_empty_desc_access_callback([this](const std::string& name) { + int* x = new int; + *x = 42; + this->test_data_store->desc(name).share(x, true, true); + }); + Ref_r ref_read {this->test_data_store->desc(data_x).ref()}; + int x = *static_cast<const int*>(ref_read.get()); + ASSERT_EQ(x, 42); + int* data = static_cast<int*>(this->test_data_store->desc(data_x).reclaim()); + delete data; + erase_x(); + try { + Ref ref_x {this->test_data_store->desc(data_x).ref()}; + FAIL(); + } catch (Error e) { + ASSERT_EQ(e.status(), PDI_ERR_VALUE); + } +} diff --git a/tests/PDI_expression.cxx b/tests/PDI_expression.cxx index 810b7e9de..bbe50b6fd 100644 --- a/tests/PDI_expression.cxx +++ b/tests/PDI_expression.cxx @@ -35,6 +35,7 @@ #include "mocks/context_mock.h" #include "mocks/data_descriptor_mock.h" +#include "mocks/data_store_mock.h" using PDI::Expression; using PDI::Datatype_uptr; @@ -638,9 +639,11 @@ TEST_F(AdvancedExpressionTest, simple_reference) { MockDataDescriptor desc_mock; + MockDataStore data_store_mock; long value = 10l; EXPECT_CALL(desc_mock, ref()).WillOnce(Return(Ref_r{new long{value}, &free, Datatype_uptr{new Scalar_datatype{Scalar_kind::SIGNED, sizeof(long)}},true, true})); - EXPECT_CALL(context_mock, desc(Matcher<const char*>(StrEq("simple")))).WillOnce(ReturnRef(desc_mock)); + EXPECT_CALL(data_store_mock, desc(Matcher<const char*>(StrEq("simple")))).WillOnce(ReturnRef(desc_mock)); + EXPECT_CALL(context_mock, data()).WillOnce(ReturnRef(data_store_mock)); Expression exp{"$simple"}; ASSERT_EQ(value, exp.to_long(context_mock)); } @@ -678,12 +681,14 @@ TEST_F(AdvancedExpressionTest, invalid_identifiers) TEST_F(AdvancedExpressionTest, reference_in_operation) { MockDataDescriptor desc_mock; + MockDataStore data_store_mock; long value1 = 10l; long value2 = 20l; EXPECT_CALL(desc_mock, ref()).WillOnce(Return(Ref_r{new long{value1}, &free, Datatype_uptr{new Scalar_datatype{Scalar_kind::SIGNED, sizeof(long)}},true, true})) .WillOnce(Return(Ref_r{new long{value2}, &free, Datatype_uptr{new Scalar_datatype{Scalar_kind::SIGNED, sizeof(long)}},true, true})); - EXPECT_CALL(context_mock, desc(Matcher<const char*>(StrEq("value1")))).WillOnce(ReturnRef(desc_mock)); - EXPECT_CALL(context_mock, desc(Matcher<const char*>(StrEq("value2")))).WillOnce(ReturnRef(desc_mock)); + EXPECT_CALL(data_store_mock, desc(Matcher<const char*>(StrEq("value1")))).WillOnce(ReturnRef(desc_mock)); + EXPECT_CALL(data_store_mock, desc(Matcher<const char*>(StrEq("value2")))).WillOnce(ReturnRef(desc_mock)); + EXPECT_CALL(context_mock, data()).Times(2).WillRepeatedly(ReturnRef(data_store_mock)); Expression exp{"(${value1} + $value2) * 2"}; ASSERT_EQ((value1 + value2) * 2, exp.to_long(context_mock)); } diff --git a/tests/mocks/context_mock.h b/tests/mocks/context_mock.h index e08f9c922..5d0f2290e 100644 --- a/tests/mocks/context_mock.h +++ b/tests/mocks/context_mock.h @@ -33,34 +33,13 @@ struct MockContext : public PDI::Context { - MOCK_METHOD1(desc, PDI::Data_descriptor&(const std::string&)); - MOCK_METHOD1(desc, PDI::Data_descriptor&(const char*)); - - MOCK_METHOD1(BracketOp1, PDI::Data_descriptor&(const std::string&)); - PDI::Data_descriptor& operator [] (const std::string& str) override - { - return BracketOp1(str); - } - - MOCK_METHOD1(BracketOp2, PDI::Data_descriptor&(const char*)); - PDI::Data_descriptor& operator [] (const char* str) override - { - return BracketOp2(str); - } - - MOCK_METHOD0(begin, PDI::Context::Iterator()); - MOCK_METHOD0(end, PDI::Context::Iterator()); - + MOCK_METHOD0(data, PDI::Data_store&()); MOCK_METHOD1(event, void(const char*)); - MOCK_CONST_METHOD0(logger, PDI::Logger_sptr()); - MOCK_METHOD1(datatype, PDI::Datatype_template_uptr(PC_tree_t)); MOCK_METHOD2(add_datatype, void(const std::string&, Datatype_template_parser)); MOCK_METHOD1(add_init_callback, std::function<void()>(const std::function<void()>&)); - MOCK_METHOD2(add_data_callback, std::function<void()>(const std::function<void(const std::string&, PDI::Ref)>&, const std::string& name)); MOCK_METHOD2(add_event_callback,std::function<void()>(const std::function<void(const std::string&)>&, const std::string& name)); - MOCK_METHOD2(add_empty_desc_access_callback, std::function<void()>(const std::function<void(const std::string&)>&, const std::string& name)); }; diff --git a/tests/mocks/data_store_mock.h b/tests/mocks/data_store_mock.h new file mode 100644 index 000000000..4924b0e69 --- /dev/null +++ b/tests/mocks/data_store_mock.h @@ -0,0 +1,61 @@ +/******************************************************************************* + * Copyright (C) 201 Institute of Bioorganic Chemistry Polish Academy of Science (PSNC) + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of CEA nor the names of its contributors may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#ifndef PDI_DATA_STORE_MOCK_H_ +#define PDI_DATA_STORE_MOCK_H_ + +#include <memory> +#include <gmock/gmock.h> +#include <pdi/data_store.h> +#include <pdi/datatype_template.h> +#include <pdi/plugin.h> + + +struct MockDataStore : public PDI::Data_store { + MOCK_METHOD1(desc, PDI::Data_descriptor&(const std::string&)); + MOCK_METHOD1(desc, PDI::Data_descriptor&(const char*)); + + MOCK_METHOD1(BracketOp1, PDI::Data_descriptor&(const std::string&)); + PDI::Data_descriptor& operator [] (const std::string& str) override + { + return BracketOp1(str); + } + + MOCK_METHOD1(BracketOp2, PDI::Data_descriptor&(const char*)); + PDI::Data_descriptor& operator [] (const char* str) override + { + return BracketOp2(str); + } + + MOCK_METHOD0(begin, PDI::Data_store::Iterator()); + MOCK_METHOD0(end, PDI::Data_store::Iterator()); + + MOCK_METHOD2(add_data_callback, std::function<void()>(const std::function<void(const std::string&, PDI::Ref)>&, const std::string& name)); + MOCK_METHOD2(add_empty_desc_access_callback, std::function<void()>(const std::function<void(const std::string&)>&, const std::string& name)); + MOCK_METHOD2(trigger_data_callbacks, void(const std::string& name, PDI::Ref)); + MOCK_METHOD1(trigger_empty_desc_access_callbacks, void(const std::string& name)); +}; + + +#endif //PDI_DATA_STORE_MOCK_H_ diff --git a/tests/mocks/global_context_mock.h b/tests/mocks/global_context_mock.h index e9e9646c8..b31148dc1 100644 --- a/tests/mocks/global_context_mock.h +++ b/tests/mocks/global_context_mock.h @@ -39,32 +39,12 @@ struct MockGlobalContext : public PDI::Global_context { {} PDI::Paraconf_wrapper fw; - MOCK_METHOD1(desc, PDI::Data_descriptor&(const std::string&)); - MOCK_METHOD1(desc, PDI::Data_descriptor&(const char*)); - - MOCK_METHOD1(BracketOp1, PDI::Data_descriptor&(const std::string&)); - PDI::Data_descriptor& operator [] (const std::string& str) override - { - return BracketOp1(str); - } - - MOCK_METHOD1(BracketOp2, PDI::Data_descriptor&(const char*)); - PDI::Data_descriptor& operator [] (const char* str) override - { - return BracketOp2(str); - } - - MOCK_METHOD0(begin, PDI::Context::Iterator()); - MOCK_METHOD0(end, PDI::Context::Iterator()); - MOCK_METHOD1(event, void(const char*)); MOCK_METHOD1(datatype, PDI::Datatype_template_uptr(PC_tree_t)); MOCK_METHOD2(add_datatype, void(const std::string&, Datatype_template_parser)); MOCK_METHOD1(add_init_callback, std::function<void()>(const std::function<void()>&)); - MOCK_METHOD2(add_data_callback, std::function<void()>(const std::function<void(const std::string&, PDI::Ref)>&, const std::string& name)); MOCK_METHOD2(add_event_callback,std::function<void()>(const std::function<void(const std::string&)>&, const std::string& name)); - MOCK_METHOD2(add_empty_desc_access_callback, std::function<void()>(const std::function<void(const std::string&)>&, const std::string& name)); }; -- GitLab From 4fd740ef3b298a2bb293f8272989425921bd2e72 Mon Sep 17 00:00:00 2001 From: Tomasz Paluszkiewicz <tomaszp@man.poznan.pl> Date: Fri, 5 Jul 2019 14:17:06 +0200 Subject: [PATCH 2/3] Move named callbacks to Data_descriptor --- include/pdi/data_descriptor.h | 32 +-- include/pdi/data_store.h | 29 +-- plugins/flowvr/src/module.h | 20 +- .../src/payloads/payload_button_event.h | 8 +- plugins/flowvr/src/payloads/payload_chunk.h | 4 +- plugins/flowvr/src/payloads/payload_data.h | 16 +- .../flowvr/src/payloads/payload_mouse_event.h | 16 +- plugins/flowvr/src/port.h | 4 +- plugins/flowvr/src/stamps/stamp_desc.h | 20 +- plugins/flowvr/src/trace.h | 4 +- plugins/user_code/user_code.cxx | 4 +- src/data_descriptor.cxx | 12 +- src/data_descriptor_impl.cxx | 104 +++++++++- src/data_descriptor_impl.h | 28 ++- src/data_store.cxx | 2 + src/data_store_impl.cxx | 123 ++--------- src/data_store_impl.h | 23 +-- tests/PDI_data_descriptor.cxx | 194 +++++++++++++++++- tests/PDI_data_store.cxx | 138 ------------- tests/mocks/data_descriptor_mock.h | 3 + tests/mocks/data_store_mock.h | 6 +- 21 files changed, 409 insertions(+), 381 deletions(-) diff --git a/include/pdi/data_descriptor.h b/include/pdi/data_descriptor.h index 3af19680c..401aff8e6 100644 --- a/include/pdi/data_descriptor.h +++ b/include/pdi/data_descriptor.h @@ -25,6 +25,8 @@ #ifndef PDI_DATA_DESCRIPTOR_H_ #define PDI_DATA_DESCRIPTOR_H_ +#include <functional> + #include <paraconf.h> #include <pdi/pdi_fwd.h> @@ -36,20 +38,6 @@ namespace PDI { class PDI_EXPORT Data_descriptor { -protected: - /** Lets implementation of the Data_descriptor to call trigger_data_callbacks - * in Data_store class - * - * \param data_store the data store to trigger data callbacks on - */ - void trigger_data_callbacks(Data_store& data_store); - - /** Lets implementation of the Data_descriptor to call trigger_empty_desc_access_callbacks - * in Data_store class - * - * \param data_store the data store to trigger empty_desc_access callbacks on - */ - void trigger_empty_desc_access_callbacks(Data_store& data_store); public: virtual ~Data_descriptor(); @@ -117,6 +105,22 @@ public: */ virtual void* reclaim() = 0; + /** Adds new data callback to descriptor + * + * \param[in] callback function to call when data is being available + * + * \return function that removes callback + */ + virtual std::function<void()> add_data_callback(const std::function<void(const std::string&, Ref)>& callback) = 0; + + /** Adds new empty desc access callback to descriptor + * + * \param[in] callback function to call when event is called + * + * \return function that removes callback + */ + virtual std::function<void()> add_empty_desc_access_callback(const std::function<void(const std::string&)>& callback) = 0; + }; // class Data_descriptor } // namespace PDI diff --git a/include/pdi/data_store.h b/include/pdi/data_store.h index 3e7219bb2..97e5b59d9 100644 --- a/include/pdi/data_store.h +++ b/include/pdi/data_store.h @@ -27,12 +27,9 @@ #define PDI_DATA_STORE_H_ #include <functional> -#include <list> -#include <map> #include <memory> #include <string> #include <unordered_map> -#include <unordered_set> #include <pdi/pdi_fwd.h> #include <pdi/data_descriptor.h> @@ -45,8 +42,6 @@ namespace PDI { class PDI_EXPORT Data_store { public: - friend class Data_descriptor; - /** An iterator used to go through the descriptor store. */ class Iterator @@ -68,20 +63,6 @@ protected: Iterator get_iterator(std::unordered_map<std::string, std::unique_ptr<Data_descriptor>>::iterator&& data); -private: - /** Triggers data callbacks - * - * \param[in] name name of the descriptor that triggers callbacks - * \param[in] ref reference to the value of the data behind the descriptor - */ - virtual void trigger_data_callbacks(const std::string& name, Ref ref) = 0; - - /** Triggers empty_desc_access callbacks - * - * \param[in] name name of the descriptor that triggers callbacks - */ - virtual void trigger_empty_desc_access_callbacks(const std::string& name) = 0; - public: virtual ~Data_store(); @@ -109,23 +90,21 @@ public: */ virtual Iterator end() = 0; - /** Adds new data callback to context + /** Adds new data callback to data store * * \param[in] callback function to call when data is being available - * \param[in] name the name of the data on which call the callback, if not specified it's called on any data * * \return function that removes callback */ - virtual std::function<void()> add_data_callback(const std::function<void(const std::string&, Ref)>& callback, const std::string& name = {}) = 0; + virtual std::function<void()> add_data_callback(const std::function<void(const std::string&, Ref)>& callback) = 0; - /** Adds new empty desc access callback to context + /** Adds new empty desc access callback to data store * * \param[in] callback function to call when event is called - * \param[in] name the name of the data on which call the callback, if not specified it's called on any data * * \return function that removes callback */ - virtual std::function<void()> add_empty_desc_access_callback(const std::function<void(const std::string&)>& callback, const std::string& name = {}) = 0; + virtual std::function<void()> add_empty_desc_access_callback(const std::function<void(const std::string&)>& callback) = 0; }; diff --git a/plugins/flowvr/src/module.h b/plugins/flowvr/src/module.h index be3e3cfde..101d16077 100644 --- a/plugins/flowvr/src/module.h +++ b/plugins/flowvr/src/module.h @@ -83,9 +83,9 @@ private: if (!PC_status(wait_on_data_node)) { std::string wait_data = PDI::to_string(wait_on_data_node); context().logger()->debug("(FlowVR) Module: wait_on_data = {}", wait_data); - context().data().add_data_callback([this](const std::string& name, PDI::Ref ref) { + context().data()[wait_data].add_data_callback([this](const std::string& name, PDI::Ref ref) { this->wait(name, ref); - }, wait_data); + }); } PC_tree_t wait_on_node = PC_get(config, ".wait_on"); @@ -113,15 +113,15 @@ private: int nb_status = PDI::len(status_node); for (int status_id = 0; status_id < nb_status; status_id++) { std::string status_data = PDI::to_string(PC_get(status_node, "[%d]", status_id)); - context().data().add_data_callback([this](const std::string& name, PDI::Ref ref) { + context().data()[status_data].add_data_callback([this](const std::string& name, PDI::Ref ref) { this->status(ref); - }, status_data); + }); } } else { std::string status_data = PDI::to_string(status_node); - context().data().add_data_callback([this](const std::string& name, PDI::Ref ref) { + context().data()[status_data].add_data_callback([this](const std::string& name, PDI::Ref ref) { this->status(ref); - }, status_data); + }); } } @@ -150,18 +150,18 @@ private: if (!PC_status(get_rank_node)) { std::string get_parallel_rank_data = PDI::to_string(get_rank_node); context().logger()->debug("(FlowVR) Module: Parallel rank = {}", get_parallel_rank_data); - context().data().add_data_callback([this](const std::string& name, PDI::Ref ref) { + context().data()[get_parallel_rank_data].add_data_callback([this](const std::string& name, PDI::Ref ref) { this->get_parallel_rank(name, ref); - }, get_parallel_rank_data); + }); } PC_tree_t get_size_node = PC_get(parallel_node, ".get_size"); if (!PC_status(get_size_node)) { std::string get_parallel_size_data = PDI::to_string(get_size_node); context().logger()->debug("(FlowVR) Module: Parallel size = {}", get_parallel_size_data); - context().data().add_data_callback([this](const std::string& name, PDI::Ref ref) { + context().data()[get_parallel_size_data].add_data_callback([this](const std::string& name, PDI::Ref ref) { this->get_parallel_size(name, ref); - }, get_parallel_size_data); + }); } } diff --git a/plugins/flowvr/src/payloads/payload_button_event.h b/plugins/flowvr/src/payloads/payload_button_event.h index c16acff4f..92e602691 100644 --- a/plugins/flowvr/src/payloads/payload_button_event.h +++ b/plugins/flowvr/src/payloads/payload_button_event.h @@ -146,9 +146,9 @@ public: m_flowvr_input_port{parent_port} { for (const auto& desc_value : m_desc_value_map) { - m_ctx.data().add_data_callback([this](const std::string& name, PDI::Ref ref) { + m_ctx.data()[desc_value.first].add_data_callback([this](const std::string& name, PDI::Ref ref) { this->data(name, ref); - }, desc_value.first); + }); } m_ctx.logger()->debug("(FlowVR) Input Button Payload ({}): Created", m_name); } @@ -235,9 +235,9 @@ public: m_flowvr_output_port{parent_port} { for (const auto& desc_value : m_desc_value_map) { - m_ctx.data().add_data_callback([this](const std::string& name, PDI::Ref ref) { + m_ctx.data()[desc_value.first].add_data_callback([this](const std::string& name, PDI::Ref ref) { this->data(name, ref); - }, desc_value.first); + }); } m_ctx.logger()->debug("(FlowVR) Output Button Payload ({}): Created", m_name); } diff --git a/plugins/flowvr/src/payloads/payload_chunk.h b/plugins/flowvr/src/payloads/payload_chunk.h index f77930e9b..ebaad897b 100644 --- a/plugins/flowvr/src/payloads/payload_chunk.h +++ b/plugins/flowvr/src/payloads/payload_chunk.h @@ -77,9 +77,9 @@ protected: m_chunk_descs.emplace_back(PDI::to_string(PC_get(chunk_node, ".data"))); } for (const std::string& data_name : m_chunk_descs) { - m_ctx.data().add_empty_desc_access_callback([this](const std::string& name) { + m_ctx.data()[data_name].add_empty_desc_access_callback([this](const std::string& name) { this->empty_desc_access(name); - }, data_name); + }); } } diff --git a/plugins/flowvr/src/payloads/payload_data.h b/plugins/flowvr/src/payloads/payload_data.h index 4f078f4f5..21a9f8cce 100644 --- a/plugins/flowvr/src/payloads/payload_data.h +++ b/plugins/flowvr/src/payloads/payload_data.h @@ -120,12 +120,12 @@ public: { load_data_size_desc(config); if (!m_data_desc.empty()) { - m_ctx.data().add_data_callback([this](const std::string& name, PDI::Ref ref) { + m_ctx.data()[m_data_desc].add_data_callback([this](const std::string& name, PDI::Ref ref) { this->copy_data_to_ref(name, ref); - }, m_data_desc); - m_ctx.data().add_empty_desc_access_callback([this](const std::string& name) { + }); + m_ctx.data()[m_data_desc].add_empty_desc_access_callback([this](const std::string& name) { this->empty_desc_access(name); - }, m_data_desc); + }); } m_ctx.logger()->debug("(FlowVR) Input Data Payload ({}): Created", m_name); } @@ -295,12 +295,12 @@ public: } if (!m_data_desc.empty()) { - m_ctx.data().add_data_callback([this](const std::string& name, PDI::Ref ref) { + m_ctx.data()[m_data_desc].add_data_callback([this](const std::string& name, PDI::Ref ref) { this->copy_data_from_ref(name, ref); - }, m_data_desc); - m_ctx.data().add_empty_desc_access_callback([this](const std::string& name) { + }); + m_ctx.data()[m_data_desc].add_empty_desc_access_callback([this](const std::string& name) { this->empty_desc_access(name); - }, m_data_desc); + }); } m_ctx.logger()->debug("(FlowVR) Output Data Payload ({}): Created", m_name); } diff --git a/plugins/flowvr/src/payloads/payload_mouse_event.h b/plugins/flowvr/src/payloads/payload_mouse_event.h index 0247f4357..025029b69 100644 --- a/plugins/flowvr/src/payloads/payload_mouse_event.h +++ b/plugins/flowvr/src/payloads/payload_mouse_event.h @@ -143,13 +143,13 @@ public: Payload_mouse_event{ctx, name, config, parent_port}, m_flowvr_input_port{parent_port} { - m_ctx.data().add_data_callback([this](const std::string& name, PDI::Ref ref) { + m_ctx.data()[m_desc_pos_xy.first].add_data_callback([this](const std::string& name, PDI::Ref ref) { this->data_pos_xy(name, ref); - }, m_desc_pos_xy.first); + }); for (const auto& desc_value : m_desc_value_map) { - m_ctx.data().add_data_callback([this](const std::string& name, PDI::Ref ref) { + m_ctx.data()[desc_value.first].add_data_callback([this](const std::string& name, PDI::Ref ref) { this->data(name, ref); - }, desc_value.first); + }); } m_ctx.logger()->debug("(FlowVR) Input Mouse Payload ({}): Created", m_name); } @@ -268,13 +268,13 @@ public: Payload_mouse_event{ctx, name, config, parent_port}, m_flowvr_output_port{parent_port} { - m_ctx.data().add_data_callback([this](const std::string& name, PDI::Ref ref) { + m_ctx.data()[m_desc_pos_xy.first].add_data_callback([this](const std::string& name, PDI::Ref ref) { this->data_pos_xy(name, ref); - }, m_desc_pos_xy.first); + }); for (const auto& desc_value : m_desc_value_map) { - m_ctx.data().add_data_callback([this](const std::string& name, PDI::Ref ref) { + m_ctx.data()[desc_value.first].add_data_callback([this](const std::string& name, PDI::Ref ref) { this->data(name, ref); - }, desc_value.first); + }); } m_ctx.logger()->debug("(FlowVR) Output Mouse Payload ({}): Created", m_name); } diff --git a/plugins/flowvr/src/port.h b/plugins/flowvr/src/port.h index 37558f9b2..80ee72477 100644 --- a/plugins/flowvr/src/port.h +++ b/plugins/flowvr/src/port.h @@ -63,9 +63,9 @@ protected: { PC_tree_t isConnected_node = PC_get(config, ".isConnected"); if (!PC_status(isConnected_node)) { - m_ctx.data().add_data_callback([this](const std::string& name, PDI::Ref ref) { + m_ctx.data()[PDI::to_string(isConnected_node)].add_data_callback([this](const std::string& name, PDI::Ref ref) { this->get_status(name, ref); - }, PDI::to_string(isConnected_node)); + }); } } diff --git a/plugins/flowvr/src/stamps/stamp_desc.h b/plugins/flowvr/src/stamps/stamp_desc.h index 45ff82d76..8dfc14460 100644 --- a/plugins/flowvr/src/stamps/stamp_desc.h +++ b/plugins/flowvr/src/stamps/stamp_desc.h @@ -58,9 +58,9 @@ public: } else { m_stamp_info = new flowvr::StampInfo(m_name, flowvr::TypeInt::create()); } - m_ctx.data().add_data_callback([this](const std::string& name, PDI::Ref ref) { + m_ctx.data()[data_desc].add_data_callback([this](const std::string& name, PDI::Ref ref) { this->data(name, ref); - }, data_desc); + }); m_ctx.logger()->debug("(FlowVR) Int STAMP ({}): Created", m_name); } @@ -109,9 +109,9 @@ public: Stamp_base{ctx, parent_port, name} { m_stamp_info = new flowvr::StampInfo(m_name, flowvr::TypeFloat::create()); - m_ctx.data().add_data_callback([this](const std::string& name, PDI::Ref ref) { + m_ctx.data()[data_desc].add_data_callback([this](const std::string& name, PDI::Ref ref) { this->data(name, ref); - }, data_desc); + }); m_ctx.logger()->debug("(FlowVR) Float STAMP ({}): Created", m_name); } @@ -164,9 +164,9 @@ public: } else { m_stamp_info = new flowvr::StampInfo(m_name, flowvr::TypeString::create()); } - m_ctx.data().add_data_callback([this](const std::string& name, PDI::Ref ref) { + m_ctx.data()[data_desc].add_data_callback([this](const std::string& name, PDI::Ref ref) { this->data(name, ref); - }, data_desc); + }); m_ctx.logger()->debug("(FlowVR) String STAMP ({}): Created", m_name); } @@ -216,9 +216,9 @@ public: m_value(size) { m_stamp_info = new flowvr::StampInfo(m_name, flowvr::TypeArray::create(size, flowvr::TypeInt::create())); - m_ctx.data().add_data_callback([this](const std::string& name, PDI::Ref ref) { + m_ctx.data()[data_desc].add_data_callback([this](const std::string& name, PDI::Ref ref) { this->data(name, ref); - }, data_desc); + }); m_ctx.logger()->debug("(FlowVR) Int array STAMP ({}): Created with size = {}", m_name, size); } @@ -272,9 +272,9 @@ public: m_value(size) { m_stamp_info = new flowvr::StampInfo(m_name, flowvr::TypeArray::create(size, flowvr::TypeFloat::create())); - m_ctx.data().add_data_callback([this](const std::string& name, PDI::Ref ref) { + m_ctx.data()[data_desc].add_data_callback([this](const std::string& name, PDI::Ref ref) { this->data(name, ref); - }, data_desc); + }); m_ctx.logger()->debug("(FlowVR) Float array STAMP ({}): Created with size = {}", m_name, size); } diff --git a/plugins/flowvr/src/trace.h b/plugins/flowvr/src/trace.h index 180004263..92059d266 100644 --- a/plugins/flowvr/src/trace.h +++ b/plugins/flowvr/src/trace.h @@ -93,9 +93,9 @@ public: { load_on_data(config); load_trace(ctx, name); - ctx.data().add_data_callback([this](const std::string& name, PDI::Ref ref) { + ctx.data()[m_on_data].add_data_callback([this](const std::string& name, PDI::Ref ref) { this->write(name, ref); - }, m_on_data); + }); ctx.logger()->debug("(FlowVR) Trace ({}): On_data: {} ", name, m_on_data); } diff --git a/plugins/user_code/user_code.cxx b/plugins/user_code/user_code.cxx index 91bfe4cca..8a3fd5e78 100644 --- a/plugins/user_code/user_code.cxx +++ b/plugins/user_code/user_code.cxx @@ -209,9 +209,9 @@ struct user_code_plugin: Plugin { opt_each(datas, [&](PC_tree_t one_data) { each(one_data, [&](PC_tree_t function_name, PC_tree_t parameters) { Trigger data_trigger{to_string(function_name), parameters}; - ctx.data().add_data_callback([&ctx, data_trigger](const std::string& name, Ref ref) mutable { + ctx.data()[to_string(data_name)].add_data_callback([&ctx, data_trigger](const std::string& name, Ref ref) mutable { data_trigger.call(ctx); - }, to_string(data_name)); + }); }); }); }); diff --git a/src/data_descriptor.cxx b/src/data_descriptor.cxx index 61bfd3d79..fd77c87b2 100644 --- a/src/data_descriptor.cxx +++ b/src/data_descriptor.cxx @@ -22,23 +22,13 @@ * THE SOFTWARE. ******************************************************************************/ -#include "pdi/data_store.h" +#include "config.h" #include "pdi/data_descriptor.h" namespace PDI { -void Data_descriptor::trigger_data_callbacks(Data_store& data_store) -{ - data_store.trigger_data_callbacks(name(), ref()); -} - -void Data_descriptor::trigger_empty_desc_access_callbacks(Data_store& data_store) -{ - data_store.trigger_empty_desc_access_callbacks(name()); -} - Data_descriptor::~Data_descriptor() = default; } // namespace PDI diff --git a/src/data_descriptor_impl.cxx b/src/data_descriptor_impl.cxx index 9e79289c9..3c1171bb9 100644 --- a/src/data_descriptor_impl.cxx +++ b/src/data_descriptor_impl.cxx @@ -24,10 +24,6 @@ #include "config.h" -#include <functional> -#include <iostream> -#include <memory> - #include <spdlog/spdlog.h> #include "pdi/context.h" @@ -43,10 +39,15 @@ namespace PDI { using std::exception; +using std::function; +using std::list; using std::nothrow; +using std::reference_wrapper; using std::stack; using std::string; +using std::to_string; using std::unique_ptr; +using std::vector; struct Data_descriptor_impl::Ref_holder { @@ -75,14 +76,15 @@ struct Data_descriptor_impl::Ref_holder::Impl: Data_descriptor_impl::Ref_holder }; - -Data_descriptor_impl::Data_descriptor_impl(Context& ctx, const char* name): +Data_descriptor_impl::Data_descriptor_impl(Context& ctx, const list<function<void(const string&, Ref)>>& any_data_callbacks, + const list<function<void(const string&)>>& any_empty_desc_access_callbacks, const char* name): m_context{ctx}, + m_any_data_callbacks{any_data_callbacks}, + m_any_empty_desc_access_callbacks{any_empty_desc_access_callbacks}, m_type{UNDEF_TYPE.clone_type()}, m_name{name}, m_metadata{false} -{ -} +{} Data_descriptor_impl::Data_descriptor_impl(Data_descriptor_impl&&) = default; @@ -143,8 +145,40 @@ Ref Data_descriptor_impl::ref() { assert((!metadata() || !m_refs.empty()) && "metadata descriptors should always keep a placeholder"); if (m_refs.empty()) { + vector<reference_wrapper<const function<void(const string&)>>> empty_desc_callbacks; + //add descriptor callbacks + for (auto it = m_empty_desc_access_callbacks.begin(); it != m_empty_desc_access_callbacks.end(); it++) { + empty_desc_callbacks.emplace_back(std::cref(*it)); + } + //add data store callbacks + for (auto it = m_any_empty_desc_access_callbacks.begin(); it != m_any_empty_desc_access_callbacks.end(); it++) { + empty_desc_callbacks.emplace_back(std::cref(*it)); + } //trigger empty desc callbacks - Data_descriptor::trigger_empty_desc_access_callbacks(m_context.data()); + vector<Error> errors; + for (const function<void(const string&)>& callback : empty_desc_callbacks) { + try { + callback(name()); + //TODO: remove the faulty plugin in case of error? + } catch (const Error& e) { + errors.emplace_back(e); + } catch (const exception& e) { + errors.emplace_back(PDI_ERR_SYSTEM, e.what()); + } catch (...) { + errors.emplace_back(PDI_ERR_SYSTEM, "Not std::exception based error"); + } + } + + if (!errors.empty()) { + if (1 == errors.size()) { + throw Error{errors.front().status(), "Error while triggering empty desc access `%s': %s", name().c_str(), errors.front().what()}; + } + string errmsg = "Multiple (" + to_string(errors.size()) + ") errors while triggering empty desc access `" + name() + "':\n"; + for (auto&& err: errors) { + errmsg += string(err.what()) + "\n"; + } + throw Error{PDI_ERR_SYSTEM, "%s", errmsg.c_str()}; + } //at least one plugin should share a Ref if (m_refs.empty()) { @@ -208,8 +242,40 @@ void* Data_descriptor_impl::share(Ref data_ref, bool read, bool write) throw Error{PDI_ERR_RIGHT, "Unable to grant requested rights"}; } + vector<reference_wrapper<const function<void(const string&, Ref)>>> data_callbacks; + //add descriptor callbacks + for (auto it = m_data_callbacks.begin(); it != m_data_callbacks.end(); it++) { + data_callbacks.emplace_back(std::cref(*it)); + } + //add data store callbacks + for (auto it = m_any_data_callbacks.begin(); it != m_any_data_callbacks.end(); it++) { + data_callbacks.emplace_back(std::cref(*it)); + } //trigger data callbacks - Data_descriptor::trigger_data_callbacks(m_context.data()); + vector<Error> errors; + for (const function<void(const string&, Ref)>& callback : data_callbacks) { + try { + callback(name(), ref()); + //TODO: remove the faulty plugin in case of error? + } catch (const Error& e) { + errors.emplace_back(e); + } catch (const exception& e) { + errors.emplace_back(PDI_ERR_SYSTEM, e.what()); + } catch (...) { + errors.emplace_back(PDI_ERR_SYSTEM, "Not std::exception based error"); + } + } + + if (!errors.empty()) { + if (1 == errors.size()) { + throw Error{errors.front().status(), "Error while triggering empty desc access `%s': %s", name().c_str(), errors.front().what()}; + } + string errmsg = "Multiple (" + to_string(errors.size()) + ") errors while triggering empty desc access `" + name() + "':\n"; + for (auto&& err: errors) { + errmsg += string(err.what()) + "\n"; + } + throw Error{PDI_ERR_SYSTEM, "%s", errmsg.c_str()}; + } assert((!metadata() || !m_refs.empty()) && "metadata descriptors should always keep a placeholder"); return result; @@ -251,4 +317,22 @@ void* Data_descriptor_impl::reclaim() return oldref.release(); } +function<void()> Data_descriptor_impl::add_data_callback(const function<void(const string&, Ref)>& callback) +{ + m_data_callbacks.emplace_back(callback); + auto it = --m_data_callbacks.end(); + return [it, this]() { + this->m_data_callbacks.erase(it); + }; +} + +function<void()> Data_descriptor_impl::add_empty_desc_access_callback(const function<void(const string&)>& callback) +{ + m_empty_desc_access_callbacks.emplace_back(callback); + auto it = --m_empty_desc_access_callbacks.end(); + return [it, this]() { + this->m_empty_desc_access_callbacks.erase(it); + }; +} + } // namespace PDI diff --git a/src/data_descriptor_impl.h b/src/data_descriptor_impl.h index 99621a7ca..afa76a175 100644 --- a/src/data_descriptor_impl.h +++ b/src/data_descriptor_impl.h @@ -51,6 +51,26 @@ class PDI_EXPORT Data_descriptor_impl : public Data_descriptor /// The context this descriptor is part of Context& m_context; + /// Reference to data callbacks that triggers when any data becomes available + const std::list<std::function<void(const std::string&, Ref)>>& m_any_data_callbacks; + + /// Reference to empty desc access callbacks that triggers when any empty desc access occurs + const std::list<std::function<void(const std::string&)>>& m_any_empty_desc_access_callbacks; + + /** + * Callbacks called when data is available + * + * This must be a list, because valid iterators are needed to properly remove the callback by plugin + */ + std::list<std::function<void(const std::string&, Ref)>> m_data_callbacks; + + /** + * Callbacks called on empty desc access + * + * This must be a list, because valid iterators are needed to properly remove the callback by plugin + */ + std::list<std::function<void(const std::string&)>> m_empty_desc_access_callbacks; + /// References to the values of this descriptor std::stack<std::unique_ptr<Ref_holder>> m_refs; @@ -60,10 +80,10 @@ class PDI_EXPORT Data_descriptor_impl : public Data_descriptor bool m_metadata; - /** Create an empty descriptor */ - Data_descriptor_impl(Context& ctx, const char* name); + Data_descriptor_impl(Context& ctx, const std::list<std::function<void(const std::string&, Ref)>>& any_data_callbacks, + const std::list<std::function<void(const std::string&)>>& any_empty_desc_access_callbacks, const char* name); Data_descriptor_impl(const Data_descriptor_impl&) = delete; @@ -98,6 +118,10 @@ public: void* reclaim() override; + std::function<void()> add_data_callback(const std::function<void(const std::string&, Ref)>& callback) override; + + std::function<void()> add_empty_desc_access_callback(const std::function<void(const std::string&)>& callback) override; + }; // class Data_descriptor } // namespace PDI diff --git a/src/data_store.cxx b/src/data_store.cxx index 41b8603b3..3fa559ea8 100644 --- a/src/data_store.cxx +++ b/src/data_store.cxx @@ -23,6 +23,8 @@ * THE SOFTWARE. ******************************************************************************/ +#include "config.h" + #include "pdi/data_store.h" diff --git a/src/data_store_impl.cxx b/src/data_store_impl.cxx index 3a6989ddb..dca49507a 100644 --- a/src/data_store_impl.cxx +++ b/src/data_store_impl.cxx @@ -23,8 +23,8 @@ * THE SOFTWARE. ******************************************************************************/ -#include <iostream> -#include <memory> +#include "config.h" + #include <vector> #include "pdi/paraconf_wrapper.h" @@ -39,7 +39,6 @@ namespace PDI { - using std::exception; using std::function; using std::move; @@ -57,7 +56,9 @@ Data_store_impl::Data_store_impl(Context& ctx): Data_descriptor& Data_store_impl::desc(const char* name) { - return *(m_descriptors.emplace(name, unique_ptr<Data_descriptor> {new Data_descriptor_impl{m_context, name}}).first->second); + return *(m_descriptors.emplace(name, unique_ptr<Data_descriptor> { + new Data_descriptor_impl{m_context, m_data_callbacks, m_empty_desc_access_callbacks, name} + }).first->second); } Data_descriptor& Data_store_impl::desc(const string& name) @@ -85,112 +86,22 @@ Data_store::Iterator Data_store_impl::end() return Data_store::get_iterator(m_descriptors.end()); } -std::function<void()> Data_store_impl::add_data_callback(const std::function<void(const std::string&, Ref)>& callback, const std::string& name) -{ - if (name.empty()) { - m_data_callbacks.emplace_back(callback); - auto it = --m_data_callbacks.end(); - return [it, this]() { - this->m_data_callbacks.erase(it); - }; - } else { - auto it = m_named_data_callbacks.emplace(name, callback); - return [it, this]() { - this->m_named_data_callbacks.erase(it); - }; - } -} - -std::function<void()> Data_store_impl::add_empty_desc_access_callback(const std::function<void(const std::string&)>& callback, const std::string& name) -{ - if (name.empty()) { - m_empty_desc_access_callbacks.emplace_back(callback); - auto it = --m_empty_desc_access_callbacks.end(); - return [it, this]() { - this->m_empty_desc_access_callbacks.erase(it); - }; - } else { - auto it = m_named_empty_desc_access_callbacks.emplace(name, callback); - return [it, this]() { - this->m_named_empty_desc_access_callbacks.erase(it); - }; - } -} - -void Data_store_impl::trigger_data_callbacks(const string& name, Ref ref) +std::function<void()> Data_store_impl::add_data_callback(const std::function<void(const std::string&, Ref)>& callback) { - vector<reference_wrapper<const function<void(const string&, Ref)>>> data_callbacks; - //add named callbacks - auto callback_it_pair = m_named_data_callbacks.equal_range(name); - for (auto it = callback_it_pair.first; it != callback_it_pair.second; it++) { - data_callbacks.emplace_back(std::cref(it->second)); - } - //add the unnamed callbacks - for (auto it = m_data_callbacks.begin(); it != m_data_callbacks.end(); it++) { - data_callbacks.emplace_back(std::cref(*it)); - } - //call gathered callbacks - vector<Error> errors; - for (const function<void(const string&, Ref)>& callback : data_callbacks) { - try { - callback(name, ref); - //TODO: remove the faulty plugin in case of error? - } catch (const Error& e) { - errors.emplace_back(e); - } catch (const exception& e) { - errors.emplace_back(PDI_ERR_SYSTEM, e.what()); - } catch (...) { - errors.emplace_back(PDI_ERR_SYSTEM, "Not std::exception based error"); - } - } - if (!errors.empty()) { - if (1 == errors.size()) { - throw Error{errors.front().status(), "Error while triggering data share `%s': %s", name, errors.front().what()}; - } - string errmsg = "Multiple (" + to_string(errors.size()) + ") errors while triggering data share `" + name + "':\n"; - for (auto&& err: errors) { - errmsg += string(err.what()) + "\n"; - } - throw Error{PDI_ERR_SYSTEM, "%s", errmsg.c_str()}; - } + m_data_callbacks.emplace_back(callback); + auto it = --m_data_callbacks.end(); + return [it, this]() { + this->m_data_callbacks.erase(it); + }; } -void Data_store_impl::trigger_empty_desc_access_callbacks(const string& name) +std::function<void()> Data_store_impl::add_empty_desc_access_callback(const std::function<void(const std::string&)>& callback) { - vector<reference_wrapper<const function<void(const string&)>>> empty_desc_callbacks; - //add named callbacks - auto callback_it_pair = m_named_empty_desc_access_callbacks.equal_range(name); - for (auto it = callback_it_pair.first; it != callback_it_pair.second; it++) { - empty_desc_callbacks.emplace_back(std::cref(it->second)); - } - //add the unnamed callbacks - for (auto it = m_empty_desc_access_callbacks.begin(); it != m_empty_desc_access_callbacks.end(); it++) { - empty_desc_callbacks.emplace_back(std::cref(*it)); - } - //call gathered callbacks - vector<Error> errors; - for (const std::function<void(const std::string&)>& callback : empty_desc_callbacks) { - try { - callback(name); - //TODO: remove the faulty plugin in case of error? - } catch (const Error& e) { - errors.emplace_back(e); - } catch (const exception& e) { - errors.emplace_back(PDI_ERR_SYSTEM, e.what()); - } catch (...) { - errors.emplace_back(PDI_ERR_SYSTEM, "Not std::exception based error"); - } - } - if (!errors.empty()) { - if (1 == errors.size()) { - throw Error{errors.front().status(), "Error while triggering empty desc access `%s': %s", name.c_str(), errors.front().what()}; - } - string errmsg = "Multiple (" + to_string(errors.size()) + ") errors while triggering empty desc access `" + name + "':\n"; - for (auto&& err: errors) { - errmsg += string(err.what()) + "\n"; - } - throw Error{PDI_ERR_SYSTEM, "%s", errmsg.c_str()}; - } + m_empty_desc_access_callbacks.emplace_back(callback); + auto it = --m_empty_desc_access_callbacks.end(); + return [it, this]() { + this->m_empty_desc_access_callbacks.erase(it); + }; } } diff --git a/src/data_store_impl.h b/src/data_store_impl.h index 7bbe883b7..a21b472ce 100644 --- a/src/data_store_impl.h +++ b/src/data_store_impl.h @@ -28,7 +28,6 @@ #include <functional> #include <list> -#include <map> #include <memory> #include <string> #include <unordered_map> @@ -56,13 +55,6 @@ private: */ std::list<std::function<void(const std::string&, Ref)>> m_data_callbacks; - /** - * Callbacks called when specified data is available. - * - * This must be an ordered multimap, because valid iterators are needed to properly remove the callback by plugin - */ - std::multimap<std::string, std::function<void(const std::string&, Ref)>> m_named_data_callbacks; - /** * Callbacks called on any empty desc access * @@ -70,17 +62,6 @@ private: */ std::list<std::function<void(const std::string&)>> m_empty_desc_access_callbacks; - /** - * Callbacks called on specified empty desc access - * - * This must be an ordered multimap, because valid iterators are needed to properly remove the callback by plugin - */ - std::multimap<std::string, std::function<void(const std::string&)>> m_named_empty_desc_access_callbacks; - - void trigger_data_callbacks(const std::string& name, Ref ref) override; - - void trigger_empty_desc_access_callbacks(const std::string& name) override; - public: Data_store_impl(Context& ctx); @@ -96,9 +77,9 @@ public: Iterator end() override; - std::function<void()> add_data_callback(const std::function<void(const std::string&, Ref)>& callback, const std::string& name = {}) override; + std::function<void()> add_data_callback(const std::function<void(const std::string&, Ref)>& callback) override; - std::function<void()> add_empty_desc_access_callback(const std::function<void(const std::string&)>& callback, const std::string& name = {}) override; + std::function<void()> add_empty_desc_access_callback(const std::function<void(const std::string&)>& callback) override; }; diff --git a/tests/PDI_data_descriptor.cxx b/tests/PDI_data_descriptor.cxx index 416a5138b..abe9ac9db 100644 --- a/tests/PDI_data_descriptor.cxx +++ b/tests/PDI_data_descriptor.cxx @@ -44,9 +44,13 @@ using ::testing::Return; namespace PDI { //handler to private fields of Descriptor struct Descriptor_test_handler { - static unique_ptr<Data_descriptor> default_desc(MockGlobalContext& mockGlCtx) + static unique_ptr<Data_descriptor> default_desc(MockGlobalContext& mockGlCtx, const char* name = "default_desc") { - return unique_ptr<Data_descriptor> {new Data_descriptor_impl{mockGlCtx, "default_desc"}}; + //shouldn't be necessary for these tests + static list<function<void(const string&, Ref)>> data_callbacks; + static list<function<void(const string&)>> empty_desc_access_callbacks; + + return unique_ptr<Data_descriptor> {new Data_descriptor_impl{mockGlCtx, data_callbacks, empty_desc_access_callbacks, name}}; } static Datatype_uptr desc_get_type(unique_ptr<Data_descriptor>& desc, MockGlobalContext& mockGlCtx) @@ -343,3 +347,189 @@ TEST_F(DataDescTest, multi_read_share_meta) ptr = Ref_r{this->m_desc_default->ref()}.get(); ASSERT_NE(this->array, ptr); } + +/* + * Name: DataDescTest.add_data_callback + * + * Tested functions: PDI::Data_descriptor::add_data_callback + * + * + * Description: Checks if callback is + * correctly called on data share. + * + */ +TEST_F(DataDescTest, add_data_callback) +{ + auto desc_x = Descriptor_test_handler::default_desc(this->mockGlCtx, "data_x"); + auto desc_y = Descriptor_test_handler::default_desc(this->mockGlCtx, "data_y"); + desc_x->default_type(Scalar_datatype{Scalar_kind::SIGNED, sizeof(int)}.clone_type()); + desc_y->default_type(Scalar_datatype{Scalar_kind::SIGNED, sizeof(int)}.clone_type()); + int x = 0; + int y = 0; + desc_x->add_data_callback([](const std::string& name, Ref ref) { + Ref_w ref_write {ref}; + int* x = static_cast<int*>(ref_write.get()); + *x += 42; + ASSERT_STREQ(name.c_str(), "data_x"); + }); + ASSERT_EQ(x, 0); + ASSERT_EQ(y, 0); + desc_x->share(&x, true, true); + desc_x->reclaim(); + ASSERT_EQ(x, 42); + ASSERT_EQ(y, 0); +} + +/* + * Name: DataDescTest.remove_data_callback + * + * Tested functions: PDI::Data_descriptor::add_data_callback + * + * + * Description: Checks if callback is + * correctly called on data share. + * + */ +TEST_F(DataDescTest, remove_data_callback) +{ + auto desc_x = Descriptor_test_handler::default_desc(this->mockGlCtx, "data_x"); + auto desc_y = Descriptor_test_handler::default_desc(this->mockGlCtx, "data_y"); + desc_x->default_type(Scalar_datatype{Scalar_kind::SIGNED, sizeof(int)}.clone_type()); + desc_y->default_type(Scalar_datatype{Scalar_kind::SIGNED, sizeof(int)}.clone_type()); + int x = 0; + int y = 0; + auto erase_x = desc_x->add_data_callback([](const std::string& name, Ref ref) { + Ref_w ref_write {ref}; + int* x = static_cast<int*>(ref_write.get()); + *x += 42; + ASSERT_STREQ(name.c_str(), "data_x"); + }); + ASSERT_EQ(x, 0); + ASSERT_EQ(y, 0); + desc_x->share(&x, true, true); + desc_x->reclaim(); + ASSERT_EQ(x, 42); + ASSERT_EQ(y, 0); + erase_x(); + desc_x->share(&x, true, true); + desc_x->reclaim(); + ASSERT_EQ(x, 42); + ASSERT_EQ(y, 0); +} + +/* + * Name: DataDescTest.add_remove_data_callback + * + * Tested functions: PDI::Data_descriptor::add_data_callback + * + * + * Description: Checks if named callback is + * correctly called on share + * and removes it several times. + * + */ +TEST_F(DataDescTest, add_remove_named_data_callback) +{ + auto desc_x = Descriptor_test_handler::default_desc(this->mockGlCtx, "data_x"); + auto desc_y = Descriptor_test_handler::default_desc(this->mockGlCtx, "data_y"); + desc_x->default_type(Scalar_datatype{Scalar_kind::SIGNED, sizeof(int)}.clone_type()); + desc_y->default_type(Scalar_datatype{Scalar_kind::SIGNED, sizeof(int)}.clone_type()); + int x = 0; + int y = 0; + auto erase_x = desc_x->add_data_callback([](const std::string& name, Ref ref) { + Ref_w ref_write {ref}; + int* x = static_cast<int*>(ref_write.get()); + *x += 42; + ASSERT_STREQ(name.c_str(), "data_x"); + }); + auto erase_y = desc_y->add_data_callback([](const std::string& name, Ref ref) { + Ref_w ref_write {ref}; + int* y = static_cast<int*>(ref_write.get()); + *y += 53; + ASSERT_STREQ(name.c_str(), "data_y"); + }); + ASSERT_EQ(x, 0); + ASSERT_EQ(y, 0); + desc_x->share(&x, true, true); + desc_x->reclaim(); + ASSERT_EQ(x, 42); + ASSERT_EQ(y, 0); + desc_y->share(&y, true, true); + desc_y->reclaim(); + ASSERT_EQ(x, 42); + ASSERT_EQ(y, 53); + erase_x(); + desc_x->share(&x, true, true); + desc_x->reclaim(); + ASSERT_EQ(x, 42); + ASSERT_EQ(y, 53); + desc_y->share(&y, true, true); + desc_y->reclaim(); + ASSERT_EQ(x, 42); + ASSERT_EQ(y, 106); + erase_y(); + desc_y->share(&y, true, true); + desc_y->reclaim(); + ASSERT_EQ(x, 42); + ASSERT_EQ(y, 106); +} + +/* + * Name: DataDescTest.add_empty_desc_callback + * + * Tested functions: PDI::Data_descriptor::add_empty_desc_access_callback + * + * + * Description: Checks if callback is + * correctly called on empty desc access. + */ +TEST_F(DataDescTest, add_empty_desc_callback) +{ + auto desc_x = Descriptor_test_handler::default_desc(this->mockGlCtx, "data_x"); + desc_x->default_type(Scalar_datatype{Scalar_kind::SIGNED, sizeof(int)}.clone_type()); + desc_x->add_empty_desc_access_callback([&desc_x](const std::string& name) { + int* x = new int; + *x = 42; + desc_x->share(x, true, true); + ASSERT_STREQ(name.c_str(), "data_x"); + }); + Ref_r ref_read {desc_x->ref()}; + int x = *static_cast<const int*>(ref_read.get()); + ASSERT_EQ(x, 42); + int* data = static_cast<int*>(desc_x->reclaim()); + delete data; +} + +/* + * Name: DataDescTest.remove_empty_desc_callback + * + * Tested functions: PDI::Data_descriptor::add_empty_desc_access_callback + * + * + * Description: Checks if callback is + * correctly called on empty desc access + * and removes it. + */ +TEST_F(DataDescTest, remove_empty_desc_callback) +{ + auto desc_x = Descriptor_test_handler::default_desc(this->mockGlCtx, "data_x"); + desc_x->default_type(Scalar_datatype{Scalar_kind::SIGNED, sizeof(int)}.clone_type()); + auto erase_x = desc_x->add_empty_desc_access_callback([&desc_x](const std::string& name) { + int* x = new int; + *x = 42; + desc_x->share(x, true, true); + ASSERT_STREQ(name.c_str(), "data_x"); + }); + Ref_r ref_read {desc_x->ref()}; + int x = *static_cast<const int*>(ref_read.get()); + ASSERT_EQ(x, 42); + int* data = static_cast<int*>(desc_x->reclaim()); + delete data; + erase_x(); + try { + Ref ref_x {desc_x->ref()}; + FAIL(); + } catch (Error e) { + ASSERT_EQ(e.status(), PDI_ERR_VALUE); + } +} diff --git a/tests/PDI_data_store.cxx b/tests/PDI_data_store.cxx index 13ab681bd..3c3bcdbce 100644 --- a/tests/PDI_data_store.cxx +++ b/tests/PDI_data_store.cxx @@ -233,7 +233,6 @@ TEST_F(DataStoreTest, iterator) TEST_F(DataStoreTest, add_data_callback) { string data_x {"data_x"}; - EXPECT_CALL(context_mock, data()).WillOnce(testing::ReturnRef(*test_data_store)); this->test_data_store->desc(data_x).default_type(Scalar_datatype{Scalar_kind::SIGNED, sizeof(int)}.clone_type()); int x = 0; this->test_data_store->add_data_callback([](const std::string& name, Ref ref) { @@ -248,39 +247,6 @@ TEST_F(DataStoreTest, add_data_callback) ASSERT_EQ(x, 42); } -/* - * Name: DataStoreTest.add_named_data_callback - * - * Tested functions: PDI::Data_store::add_data_callback - * - * - * Description: Checks if named callback is - * correctly called on data share. - * - */ -TEST_F(DataStoreTest, add_named_data_callback) -{ - string data_x {"data_x"}; - string data_y {"data_y"}; - EXPECT_CALL(context_mock, data()).WillOnce(testing::ReturnRef(*test_data_store)); - this->test_data_store->desc(data_x).default_type(Scalar_datatype{Scalar_kind::SIGNED, sizeof(int)}.clone_type()); - this->test_data_store->desc(data_y).default_type(Scalar_datatype{Scalar_kind::SIGNED, sizeof(int)}.clone_type()); - int x = 0; - int y = 0; - this->test_data_store->add_data_callback([](const std::string& name, Ref ref) { - Ref_w ref_write {ref}; - int* x = static_cast<int*>(ref_write.get()); - *x += 42; - ASSERT_STREQ(name.c_str(), "data_x"); - }, "data_x"); - ASSERT_EQ(x, 0); - ASSERT_EQ(y, 0); - this->test_data_store->desc("data_x").share(&x, true, true); - this->test_data_store->desc("data_x").reclaim(); - ASSERT_EQ(x, 42); - ASSERT_EQ(y, 0); -} - /* * Name: DataStoreTest.remove_data_callback * @@ -294,7 +260,6 @@ TEST_F(DataStoreTest, add_named_data_callback) TEST_F(DataStoreTest, remove_data_callback) { string data_x {"data_x"}; - EXPECT_CALL(context_mock, data()).Times(2).WillRepeatedly(testing::ReturnRef(*test_data_store)); this->test_data_store->desc(data_x).default_type(Scalar_datatype{Scalar_kind::SIGNED, sizeof(int)}.clone_type()); int x = 0; auto erase_x = this->test_data_store->add_data_callback([](const std::string& name, Ref ref) { @@ -313,44 +278,6 @@ TEST_F(DataStoreTest, remove_data_callback) ASSERT_EQ(x, 42); } -/* - * Name: DataStoreTest.remove_named_data_callback - * - * Tested functions: PDI::Data_store::add_data_callback - * - * - * Description: Checks if named callback is - * correctly called on data share. - * - */ -TEST_F(DataStoreTest, remove_named_data_callback) -{ - string data_x {"data_x"}; - string data_y {"data_y"}; - EXPECT_CALL(context_mock, data()).Times(2).WillRepeatedly(testing::ReturnRef(*test_data_store)); - this->test_data_store->desc(data_x).default_type(Scalar_datatype{Scalar_kind::SIGNED, sizeof(int)}.clone_type()); - this->test_data_store->desc(data_y).default_type(Scalar_datatype{Scalar_kind::SIGNED, sizeof(int)}.clone_type()); - int x = 0; - int y = 0; - auto erase_x = this->test_data_store->add_data_callback([](const std::string& name, Ref ref) { - Ref_w ref_write {ref}; - int* x = static_cast<int*>(ref_write.get()); - *x += 42; - ASSERT_STREQ(name.c_str(), "data_x"); - }, "data_x"); - ASSERT_EQ(x, 0); - ASSERT_EQ(y, 0); - this->test_data_store->desc("data_x").share(&x, true, true); - this->test_data_store->desc("data_x").reclaim(); - ASSERT_EQ(x, 42); - ASSERT_EQ(y, 0); - erase_x(); - this->test_data_store->desc("data_x").share(&x, true, true); - this->test_data_store->desc("data_x").reclaim(); - ASSERT_EQ(x, 42); - ASSERT_EQ(y, 0); -} - /* * Name: DataStoreTest.add_remove_data_callback * @@ -384,8 +311,6 @@ TEST_F(DataStoreTest, add_remove_data_callback) }); ASSERT_EQ(x, 0); ASSERT_EQ(y, 0); - EXPECT_CALL(context_mock, data()) - .Times(6).WillRepeatedly(testing::ReturnRef(*test_data_store)); this->test_data_store->desc("1").share(&x, true, true); this->test_data_store->desc("1").reclaim(); ASSERT_EQ(x, 3); @@ -412,67 +337,6 @@ TEST_F(DataStoreTest, add_remove_data_callback) ASSERT_EQ(y, 10); } -/* - * Name: DataStoreTest.add_remove_named_data_callback - * - * Tested functions: PDI::Data_store::add_data_callback - * - * - * Description: Checks if named callback is - * correctly called on share - * and removes it several times. - * - */ -TEST_F(DataStoreTest, add_remove_named_data_callback) -{ - string data_x {"data_x"}; - string data_y {"data_y"}; - Data_descriptor& desc_x = this->test_data_store->desc(data_x); - Data_descriptor& desc_y = this->test_data_store->desc(data_y); - this->test_data_store->desc(data_x).default_type(Scalar_datatype{Scalar_kind::SIGNED, sizeof(int)}.clone_type()); - this->test_data_store->desc(data_y).default_type(Scalar_datatype{Scalar_kind::SIGNED, sizeof(int)}.clone_type()); - int x = 0; - int y = 0; - auto erase_x = this->test_data_store->add_data_callback([](const std::string& name, Ref ref) { - Ref_w ref_write {ref}; - int* x = static_cast<int*>(ref_write.get()); - *x += 42; - ASSERT_STREQ(name.c_str(), "data_x"); - }, "data_x"); - auto erase_y = this->test_data_store->add_data_callback([](const std::string& name, Ref ref) { - Ref_w ref_write {ref}; - int* y = static_cast<int*>(ref_write.get()); - *y += 53; - ASSERT_STREQ(name.c_str(), "data_y"); - }, "data_y"); - ASSERT_EQ(x, 0); - ASSERT_EQ(y, 0); - EXPECT_CALL(context_mock, data()) - .Times(5).WillRepeatedly(testing::ReturnRef(*test_data_store)); - this->test_data_store->desc("data_x").share(&x, true, true); - this->test_data_store->desc("data_x").reclaim(); - ASSERT_EQ(x, 42); - ASSERT_EQ(y, 0); - this->test_data_store->desc("data_y").share(&y, true, true); - this->test_data_store->desc("data_y").reclaim(); - ASSERT_EQ(x, 42); - ASSERT_EQ(y, 53); - erase_x(); - this->test_data_store->desc("data_x").share(&x, true, true); - this->test_data_store->desc("data_x").reclaim(); - ASSERT_EQ(x, 42); - ASSERT_EQ(y, 53); - this->test_data_store->desc("data_y").share(&y, true, true); - this->test_data_store->desc("data_y").reclaim(); - ASSERT_EQ(x, 42); - ASSERT_EQ(y, 106); - erase_y(); - this->test_data_store->desc("data_y").share(&y, true, true); - this->test_data_store->desc("data_y").reclaim(); - ASSERT_EQ(x, 42); - ASSERT_EQ(y, 106); -} - /* * Name: DataStoreTest.add_empty_desc_callback * @@ -485,7 +349,6 @@ TEST_F(DataStoreTest, add_remove_named_data_callback) TEST_F(DataStoreTest, add_empty_desc_callback) { string data_x {"data_x"}; - EXPECT_CALL(context_mock, data()).WillRepeatedly(testing::ReturnRef(*test_data_store)); this->test_data_store->desc(data_x).default_type(Scalar_datatype{Scalar_kind::SIGNED, sizeof(int)}.clone_type()); this->test_data_store->add_empty_desc_access_callback([this](const std::string& name) { int* x = new int; @@ -512,7 +375,6 @@ TEST_F(DataStoreTest, add_empty_desc_callback) TEST_F(DataStoreTest, remove_empty_desc_callback) { string data_x {"data_x"}; - EXPECT_CALL(context_mock, data()).WillRepeatedly(testing::ReturnRef(*test_data_store)); this->test_data_store->desc(data_x).default_type(Scalar_datatype{Scalar_kind::SIGNED, sizeof(int)}.clone_type()); auto erase_x = this->test_data_store->add_empty_desc_access_callback([this](const std::string& name) { int* x = new int; diff --git a/tests/mocks/data_descriptor_mock.h b/tests/mocks/data_descriptor_mock.h index 4ea431320..b1dd0a4f9 100644 --- a/tests/mocks/data_descriptor_mock.h +++ b/tests/mocks/data_descriptor_mock.h @@ -45,6 +45,9 @@ struct MockDataDescriptor : public PDI::Data_descriptor { MOCK_METHOD3(share, void* (PDI::Ref, bool, bool)); MOCK_METHOD0(release, void()); MOCK_METHOD0(reclaim, void* ()); + + MOCK_METHOD1(add_data_callback, std::function<void()>(const std::function<void(const std::string&, PDI::Ref)>&)); + MOCK_METHOD1(add_empty_desc_access_callback, std::function<void()>(const std::function<void(const std::string&)>&)); }; diff --git a/tests/mocks/data_store_mock.h b/tests/mocks/data_store_mock.h index 4924b0e69..064c37fd6 100644 --- a/tests/mocks/data_store_mock.h +++ b/tests/mocks/data_store_mock.h @@ -51,10 +51,8 @@ struct MockDataStore : public PDI::Data_store { MOCK_METHOD0(begin, PDI::Data_store::Iterator()); MOCK_METHOD0(end, PDI::Data_store::Iterator()); - MOCK_METHOD2(add_data_callback, std::function<void()>(const std::function<void(const std::string&, PDI::Ref)>&, const std::string& name)); - MOCK_METHOD2(add_empty_desc_access_callback, std::function<void()>(const std::function<void(const std::string&)>&, const std::string& name)); - MOCK_METHOD2(trigger_data_callbacks, void(const std::string& name, PDI::Ref)); - MOCK_METHOD1(trigger_empty_desc_access_callbacks, void(const std::string& name)); + MOCK_METHOD1(add_data_callback, std::function<void()>(const std::function<void(const std::string&, PDI::Ref)>&)); + MOCK_METHOD1(add_empty_desc_access_callback, std::function<void()>(const std::function<void(const std::string&)>&)); }; -- GitLab From 1609d89020c49e8fdbb706a0f4f1dbf682fa59bf Mon Sep 17 00:00:00 2001 From: Tomasz Paluszkiewicz <tomaszp@man.poznan.pl> Date: Wed, 10 Jul 2019 15:37:17 +0200 Subject: [PATCH 3/3] Make data_store more like a map with different iterator --- include/pdi/data_store.h | 73 +++++++++++++++++++++++++++++++++-- src/data_store.cxx | 65 ++++++++++++++++++++++++++++++- src/data_store_impl.cxx | 59 ++++++++++++++++++++++++++-- src/data_store_impl.h | 24 +++++++++++- tests/mocks/data_store_mock.h | 60 +++++++++++++++++++++++++++- 5 files changed, 269 insertions(+), 12 deletions(-) diff --git a/include/pdi/data_store.h b/include/pdi/data_store.h index 97e5b59d9..138544db6 100644 --- a/include/pdi/data_store.h +++ b/include/pdi/data_store.h @@ -27,6 +27,7 @@ #define PDI_DATA_STORE_H_ #include <functional> +#include <iterator> #include <memory> #include <string> #include <unordered_map> @@ -44,7 +45,7 @@ class PDI_EXPORT Data_store public: /** An iterator used to go through the descriptor store. */ - class Iterator + class Iterator : public std::iterator<std::forward_iterator_tag, Data_descriptor> { friend class Data_store; /// The iterator this wraps @@ -55,15 +56,53 @@ public: Data_descriptor* operator-> (); Data_descriptor& operator* (); Iterator& operator++ (); + Iterator operator++ (int); + bool operator== (const Iterator&); bool operator!= (const Iterator&); }; + /** A const_iterator used to go through the descriptor store. + */ + class Const_iterator : public std::iterator<std::forward_iterator_tag, Data_descriptor> + { + friend class Data_store; + /// The iterator this wraps + std::unordered_map<std::string, std::unique_ptr<Data_descriptor>>::const_iterator m_data; + Const_iterator(const std::unordered_map<std::string, std::unique_ptr<Data_descriptor>>::const_iterator& data); + Const_iterator(std::unordered_map<std::string, std::unique_ptr<Data_descriptor>>::const_iterator&& data); + public: + const Data_descriptor* operator-> (); + const Data_descriptor& operator* (); + Const_iterator& operator++ (); + Const_iterator operator++ (int); + bool operator== (const Const_iterator&); + bool operator!= (const Const_iterator&); + }; + protected: Iterator get_iterator(const std::unordered_map<std::string, std::unique_ptr<Data_descriptor>>::iterator& data); Iterator get_iterator(std::unordered_map<std::string, std::unique_ptr<Data_descriptor>>::iterator&& data); + Const_iterator get_const_iterator(const std::unordered_map<std::string, std::unique_ptr<Data_descriptor>>::const_iterator& data) const; + + Const_iterator get_const_iterator(std::unordered_map<std::string, std::unique_ptr<Data_descriptor>>::const_iterator&& data) const; + public: + using key_type = std::string; + using mapped_type = std::unique_ptr<Data_descriptor>; + using value_type = std::pair<std::string, std::unique_ptr<Data_descriptor>>; + using size_type = std::size_t; + using hasher = std::hash<key_type>; + using key_equal = std::equal_to<key_type>; + using allocator_type = std::allocator<std::pair<std::string, std::unique_ptr<Data_descriptor>>>; + using reference = mapped_type&; + using const_reference = const mapped_type&; + using pointer = typename std::allocator_traits<allocator_type>::pointer; + using const_pointer = typename std::allocator_traits<allocator_type>::const_pointer; + using iterator = Iterator; + using const_iterator = Const_iterator; + virtual ~Data_store(); /** Accesses the descriptor for a specific name. Might be uninitialized @@ -84,11 +123,39 @@ public: /** Returns an iterator on the first descriptor */ - virtual Iterator begin() = 0; + virtual Iterator begin() noexcept = 0; /** Returns an iterator past the last descriptor */ - virtual Iterator end() = 0; + virtual Iterator end() noexcept = 0; + + /** Returns a const_iterator on the first descriptor + */ + virtual Const_iterator begin() const noexcept = 0; + + /** Returns a const_iterator past the last descriptor + */ + virtual Const_iterator end() const noexcept = 0; + + /** Returns a const_iterator on the first descriptor + */ + virtual Const_iterator cbegin() const noexcept = 0; + + /** Returns a const_iterator past the last descriptor + */ + virtual Const_iterator cend() const noexcept = 0; + + virtual bool empty() const noexcept = 0; + + virtual std::size_t count(const std::string& name) const = 0; + + virtual Data_descriptor& at(const std::string& name) = 0; + + virtual Iterator find(const std::string& name) = 0; + + virtual std::size_t size() const noexcept = 0; + + virtual std::size_t max_size() const noexcept = 0; /** Adds new data callback to data store * diff --git a/src/data_store.cxx b/src/data_store.cxx index 3fa559ea8..030eda655 100644 --- a/src/data_store.cxx +++ b/src/data_store.cxx @@ -59,9 +59,62 @@ Data_store::Iterator& Data_store::Iterator::operator++ () return *this; } +Data_store::Iterator Data_store::Iterator::operator++ (int) +{ + auto tmp = *this; + ++(*this); + return tmp; +} + +bool Data_store::Iterator::operator== (const Iterator& o) +{ + return (m_data == o.m_data); +} + bool Data_store::Iterator::operator!= (const Iterator& o) { - return (m_data != o.m_data); + return !(*this == o); +} + +Data_store::Const_iterator::Const_iterator(const unordered_map<string, unique_ptr<Data_descriptor>>::const_iterator& data): + m_data(data) +{} + +Data_store::Const_iterator::Const_iterator(unordered_map<string, unique_ptr<Data_descriptor>>::const_iterator&& data): + m_data(move(data)) +{} + +const Data_descriptor* Data_store::Const_iterator::operator-> () +{ + return m_data->second.get(); +} + +const Data_descriptor& Data_store::Const_iterator::operator* () +{ + return *m_data->second; +} + +Data_store::Const_iterator& Data_store::Const_iterator::operator++ () +{ + ++m_data; + return *this; +} + +Data_store::Const_iterator Data_store::Const_iterator::operator++ (int) +{ + auto tmp = *this; + ++(*this); + return tmp; +} + +bool Data_store::Const_iterator::operator== (const Const_iterator& o) +{ + return (m_data == o.m_data); +} + +bool Data_store::Const_iterator::operator!= (const Const_iterator& o) +{ + return !(*this == o); } Data_store::Iterator Data_store::get_iterator(const std::unordered_map<std::string, unique_ptr<Data_descriptor>>::iterator& data) @@ -74,6 +127,16 @@ Data_store::Iterator Data_store::get_iterator(std::unordered_map<std::string, un return move(data); } +Data_store::Const_iterator Data_store::get_const_iterator(const std::unordered_map<std::string, unique_ptr<Data_descriptor>>::const_iterator& data) const +{ + return data; +} + +Data_store::Const_iterator Data_store::get_const_iterator(std::unordered_map<std::string, unique_ptr<Data_descriptor>>::const_iterator&& data) const +{ + return move(data); +} + Data_store::~Data_store() = default; } diff --git a/src/data_store_impl.cxx b/src/data_store_impl.cxx index dca49507a..fa821f7a7 100644 --- a/src/data_store_impl.cxx +++ b/src/data_store_impl.cxx @@ -43,6 +43,7 @@ using std::exception; using std::function; using std::move; using std::reference_wrapper; +using std::size_t; using std::string; using std::to_string; using std::unordered_map; @@ -76,17 +77,67 @@ Data_descriptor& Data_store_impl::operator[](const string& name) return desc(name.c_str()); } -Data_store::Iterator Data_store_impl::begin() +Data_store::Iterator Data_store_impl::begin() noexcept { return Data_store::get_iterator(m_descriptors.begin()); } -Data_store::Iterator Data_store_impl::end() +Data_store::Iterator Data_store_impl::end() noexcept { return Data_store::get_iterator(m_descriptors.end()); } -std::function<void()> Data_store_impl::add_data_callback(const std::function<void(const std::string&, Ref)>& callback) +Data_store::Const_iterator Data_store_impl::begin() const noexcept +{ + return cbegin(); +} + +Data_store::Const_iterator Data_store_impl::end() const noexcept +{ + return cend(); +} + +Data_store::Const_iterator Data_store_impl::cbegin() const noexcept +{ + return Data_store::get_const_iterator(m_descriptors.cbegin()); +} + +Data_store::Const_iterator Data_store_impl::cend() const noexcept +{ + return Data_store::get_const_iterator(m_descriptors.cend()); +} + +bool Data_store_impl::empty() const noexcept +{ + return m_descriptors.empty(); +} + +std::size_t Data_store_impl::count(const std::string& name) const +{ + return m_descriptors.empty(); +} + +Data_descriptor& Data_store_impl::at(const std::string& name) +{ + return *m_descriptors.at(name); +} + +Data_store::Iterator Data_store_impl::find(const std::string& name) +{ + return Data_store::get_iterator(m_descriptors.find(name)); +} + +size_t Data_store_impl::size() const noexcept +{ + return m_descriptors.size(); +} + +size_t Data_store_impl::max_size() const noexcept +{ + return m_descriptors.max_size(); +} + +function<void()> Data_store_impl::add_data_callback(const function<void(const string&, Ref)>& callback) { m_data_callbacks.emplace_back(callback); auto it = --m_data_callbacks.end(); @@ -95,7 +146,7 @@ std::function<void()> Data_store_impl::add_data_callback(const std::function<voi }; } -std::function<void()> Data_store_impl::add_empty_desc_access_callback(const std::function<void(const std::string&)>& callback) +function<void()> Data_store_impl::add_empty_desc_access_callback(const function<void(const string&)>& callback) { m_empty_desc_access_callbacks.emplace_back(callback); auto it = --m_empty_desc_access_callbacks.end(); diff --git a/src/data_store_impl.h b/src/data_store_impl.h index a21b472ce..107589e68 100644 --- a/src/data_store_impl.h +++ b/src/data_store_impl.h @@ -73,9 +73,29 @@ public: Data_descriptor& operator[](const char* name) override; - Iterator begin() override; + Iterator begin() noexcept override; - Iterator end() override; + Iterator end() noexcept override; + + Const_iterator begin() const noexcept override; + + Const_iterator end() const noexcept override; + + Const_iterator cbegin() const noexcept override; + + Const_iterator cend() const noexcept override; + + bool empty() const noexcept override; + + std::size_t count(const std::string& name) const override; + + Data_descriptor& at(const std::string& name) override; + + Iterator find(const std::string& name) override; + + std::size_t size() const noexcept override; + + std::size_t max_size() const noexcept override; std::function<void()> add_data_callback(const std::function<void(const std::string&, Ref)>& callback) override; diff --git a/tests/mocks/data_store_mock.h b/tests/mocks/data_store_mock.h index 064c37fd6..9da451c79 100644 --- a/tests/mocks/data_store_mock.h +++ b/tests/mocks/data_store_mock.h @@ -48,8 +48,64 @@ struct MockDataStore : public PDI::Data_store { return BracketOp2(str); } - MOCK_METHOD0(begin, PDI::Data_store::Iterator()); - MOCK_METHOD0(end, PDI::Data_store::Iterator()); + //each noexcept method must be used through proxy (no support from gmock) + MOCK_METHOD0(begin_proxy, PDI::Data_store::Iterator()); + PDI::Data_store::Iterator begin() noexcept override + { + return begin_proxy(); + } + + MOCK_METHOD0(end_proxy, PDI::Data_store::Iterator()); + PDI::Data_store::Iterator end() noexcept override + { + return end_proxy(); + } + + MOCK_CONST_METHOD0(begin_const_proxy, PDI::Data_store::Const_iterator()); + PDI::Data_store::Const_iterator begin() const noexcept override + { + return begin_const_proxy(); + } + + MOCK_CONST_METHOD0(end_const_proxy, PDI::Data_store::Const_iterator()); + PDI::Data_store::Const_iterator end() const noexcept override + { + return end_const_proxy(); + } + + MOCK_CONST_METHOD0(cbegin_proxy, PDI::Data_store::Const_iterator()); + PDI::Data_store::Const_iterator cbegin() const noexcept override + { + return cbegin_proxy(); + } + + MOCK_CONST_METHOD0(cend_proxy, PDI::Data_store::Const_iterator()); + PDI::Data_store::Const_iterator cend() const noexcept override + { + return cend_proxy(); + } + + MOCK_CONST_METHOD0(empty_proxy, bool()); + bool empty() const noexcept override + { + return empty_proxy(); + } + + MOCK_CONST_METHOD0(size_proxy, std::size_t()); + std::size_t size() const noexcept override + { + return size_proxy(); + } + + MOCK_CONST_METHOD0(max_size_proxy, std::size_t()); + std::size_t max_size() const noexcept override + { + return max_size_proxy(); + } + + MOCK_CONST_METHOD1(count, std::size_t(const std::string&)); + MOCK_METHOD1(at, PDI::Data_descriptor&(const std::string&)); + MOCK_METHOD1(find, PDI::Data_store::Iterator(const std::string&)); MOCK_METHOD1(add_data_callback, std::function<void()>(const std::function<void(const std::string&, PDI::Ref)>&)); MOCK_METHOD1(add_empty_desc_access_callback, std::function<void()>(const std::function<void(const std::string&)>&)); -- GitLab