.. _program_listing_file_include_flamegpu_model_LayerDescription.h: Program Listing for File LayerDescription.h =========================================== |exhale_lsh| :ref:`Return to documentation for file ` (``include/flamegpu/model/LayerDescription.h``) .. |exhale_lsh| unicode:: U+021B0 .. UPWARDS ARROW WITH TIP LEFTWARDS .. code-block:: cpp #ifndef INCLUDE_FLAMEGPU_MODEL_LAYERDESCRIPTION_H_ #define INCLUDE_FLAMEGPU_MODEL_LAYERDESCRIPTION_H_ #include #include #include "flamegpu/model/ModelDescription.h" #include "flamegpu/model/AgentDescription.h" #include "flamegpu/model/ModelData.h" #include "flamegpu/model/LayerData.h" #include "flamegpu/runtime/AgentFunction.cuh" #include "flamegpu/model/AgentFunctionData.cuh" namespace flamegpu { class CLayerDescription { friend struct LayerData; friend class DependencyGraph; public: explicit CLayerDescription(std::shared_ptr data); explicit CLayerDescription(std::shared_ptr data); CLayerDescription(const CLayerDescription& other_layer) = default; CLayerDescription(CLayerDescription&& other_layer) = default; CLayerDescription& operator=(const CLayerDescription& other_layer) = default; CLayerDescription& operator=(CLayerDescription&& other_layer) = default; bool operator==(const CLayerDescription& rhs) const; bool operator!=(const CLayerDescription& rhs) const; std::string getName() const; flamegpu::size_type getIndex() const; flamegpu::size_type getAgentFunctionsCount() const; flamegpu::size_type getHostFunctionsCount() const; #ifdef SWIG inline flamegpu::size_type getHostFunctionCallbackCount() const; #endif CAgentFunctionDescription getAgentFunction(unsigned int index) const; FLAMEGPU_HOST_FUNCTION_POINTER getHostFunction(unsigned int index) const; #ifdef SWIG inline HostFunctionCallback* getHostFunctionCallback(unsigned int index) const; #endif protected: std::shared_ptr layer; }; class LayerDescription : public CLayerDescription { friend class DependencyGraph; public: explicit LayerDescription(std::shared_ptr data); LayerDescription(const LayerDescription& other_layer) = default; LayerDescription(LayerDescription&& other_layer) = default; LayerDescription& operator=(const LayerDescription& other_layer) = default; LayerDescription& operator=(LayerDescription&& other_layer) = default; template void addAgentFunction(AgentFn a = AgentFn()); void addAgentFunction(const CAgentFunctionDescription& afd); void addAgentFunction(const AgentFunctionDescription &afd); void addAgentFunction(const std::string &agentName, const std::string &functionName); void addAgentFunction(const char *agentName, const char *functionName); void addHostFunction(FLAMEGPU_HOST_FUNCTION_POINTER func_p); void addSubModel(const std::string &name); void addSubModel(const CSubModelDescription &submodel); #ifdef SWIG inline void addHostFunction(HostFunctionCallback *func_callback); #endif private: void _addHostFunction(HostFunctionCallback* func_callback); AgentFunctionDescription AgentFunction(unsigned int index); }; template void LayerDescription::addAgentFunction(AgentFn /*af*/) { if (layer->sub_model) { THROW exception::InvalidLayerMember("A layer containing agent functions and/or host functions, may not also contain a submodel, " "in LayerDescription::addAgentFunction()\n"); } if (layer->host_functions.size() || layer->host_functions_callbacks.size()) { THROW exception::InvalidLayerMember("A layer containing host functions, may not also contain agent functions, " "in LayerDescription::addAgentFunction()\n"); } AgentFunctionWrapper * func_compare = AgentFn::fnPtr(); // Find the matching agent function in model hierarchy auto mdl = layer->model.lock(); if (!mdl) { THROW exception::ExpiredWeakPtr(); } unsigned int matches = 0; std::shared_ptr match_ptr; for (auto a : mdl->agents) { for (auto f : a.second->functions) { if (f.second->func == func_compare) { auto a_agent_out = f.second->agent_output.lock(); auto a_message_out = f.second->message_output.lock(); auto a_message_in = f.second->message_input.lock(); for (const auto &b : layer->agent_functions) { if (auto parent = b->parent.lock()) { // Check that layer does not already contain function with same agent + states // If agent matches if (parent->name == a.second->name) { // If they share a state if (b->initial_state == f.second->initial_state || b->initial_state == f.second->end_state || b->end_state == f.second->initial_state || b->end_state == f.second->end_state) { THROW exception::InvalidAgentFunc("Agent functions '%s' cannot be added to this layer as agent function '%s' " "within the layer shares an input or output state, this is not permitted, " "in LayerDescription::addAgentFunction().", f.second->name.c_str(), b->name.c_str()); } } // Check that the layer does not already contain function for the agent + state being output to if (a_agent_out) { // If agent matches if (parent->name == a_agent_out->name) { // If state matches if (b->initial_state == f.second->agent_output_state) { THROW exception::InvalidLayerMember("Agent functions '%s' cannot be added to this layer as agent function '%s' " "within the layer requires the same agent state as an input, as this agent function births, " "in LayerDescription::addAgentFunction().", f.second->name.c_str(), b->name.c_str()); } } } // Also check the inverse auto b_agent_out = b->agent_output.lock(); if (b_agent_out) { // If agent matches if (a.second->name == b_agent_out->name) { // If state matches if (f.second->initial_state == b->agent_output_state) { THROW exception::InvalidLayerMember("Agent functions '%s' cannot be added to this layer as agent function '%s' " "within the layer agent births to the same agent state as this agent function requires as an input, " "in LayerDescription::addAgentFunction().", f.second->name.c_str(), b->name.c_str()); } } } } // Check the layer does not already contain function which outputs to same message list auto b_message_out = b->message_output.lock(); auto b_message_in = b->message_input.lock(); if ((a_message_out && b_message_out && a_message_out == b_message_out) || (a_message_out && b_message_in && a_message_out == b_message_in) || (a_message_in && b_message_out && a_message_in == b_message_out)) { // Pointer comparison should be fine here THROW exception::InvalidLayerMember("Agent functions '%s' cannot be added to this layer as agent function '%s' " "within the layer also inputs or outputs to the same messagelist, this is not permitted, " "in LayerDescription::addAgentFunction().", f.second->name.c_str(), b->name.c_str()); } } match_ptr = f.second; ++matches; } } } if (matches == 1) { // Add it and check it succeeded if (layer->agent_functions.emplace(match_ptr).second) return; THROW exception::InvalidAgentFunc("Attempted to add same agent function to same layer twice, " "in LayerDescription::addAgentFunction()."); } if (matches > 1) { THROW exception::InvalidAgentFunc("There are %u possible agent functions to add to layer, please use a more specific method for adding this agent function to a layer, " "in LayerDescription::addAgentFunction().", matches); } THROW exception::InvalidAgentFunc("Agent function was not found, " "in LayerDescription::addAgentFunction()."); } #ifdef SWIG void LayerDescription::addHostFunction(HostFunctionCallback* func_callback) { this->_addHostFunction(func_callback); } flamegpu::size_type CLayerDescription::getHostFunctionCallbackCount() const { // Safe down-cast return static_cast(layer->host_functions_callbacks.size()); } HostFunctionCallback* CLayerDescription::getHostFunctionCallback(unsigned int index) const { if (index < layer->host_functions_callbacks.size()) { auto it = layer->host_functions_callbacks.begin(); for (unsigned int i = 0; i < index; ++i) ++it; return *it; } THROW exception::OutOfBoundsException("Index %d is out of bounds (only %d items exist) " "in LayerDescription.getHostFunctionCallback()\n", index, layer->host_functions_callbacks.size()); } #endif // SWIG } // namespace flamegpu #endif // INCLUDE_FLAMEGPU_MODEL_LAYERDESCRIPTION_H_