Program Listing for File AgentDescription.h

Return to documentation for file (include/flamegpu/model/AgentDescription.h)

#ifndef INCLUDE_FLAMEGPU_MODEL_AGENTDESCRIPTION_H_
#define INCLUDE_FLAMEGPU_MODEL_AGENTDESCRIPTION_H_

#include <string>
#include <map>
#include <typeinfo>
#include <memory>
#include <vector>
#include <set>

#include "flamegpu/model/Variable.h"
#include "flamegpu/model/ModelDescription.h"
#include "flamegpu/simulation/AgentVector.h"
#include "flamegpu/runtime/agent/AgentInstance.h"
#include "flamegpu/model/AgentData.h"
#include "flamegpu/detail/type_decode.h"

namespace flamegpu {

class CAgentFunctionDescription;
class AgentFunctionDescription;
class AgentDescription;
namespace visualiser {
struct AgentVisData;
}

class CAgentDescription {
    friend struct AgentData;
    friend AgentVector::AgentVector(const CAgentDescription& agent_desc, flamegpu::size_type);
    friend AgentInstance::AgentInstance(const CAgentDescription& agent_desc);
    friend bool AgentVector::matchesAgentType(const CAgentDescription& other) const;
    friend struct visualiser::AgentVisData;

 public:
    explicit CAgentDescription(std::shared_ptr<AgentData> data);
    explicit CAgentDescription(std::shared_ptr<const AgentData> data);
    CAgentDescription(const CAgentDescription& other_agent) = default;
    CAgentDescription(CAgentDescription&& other_agent) = default;
    CAgentDescription& operator=(const CAgentDescription& other_agent) = default;
    CAgentDescription& operator=(CAgentDescription&& other_agent) = default;
    bool operator==(const CAgentDescription& rhs) const;
    bool operator!=(const CAgentDescription& rhs) const;

    std::string getName() const;
    flamegpu::size_type getStatesCount() const;
    std::string getInitialState() const;
    const std::type_index& getVariableType(const std::string& variable_name) const;
    size_t getVariableSize(const std::string& variable_name) const;
    flamegpu::size_type getVariableLength(const std::string& variable_name) const;
    flamegpu::size_type getVariablesCount() const;
    CAgentFunctionDescription getFunction(const std::string& function_name) const;
    flamegpu::size_type getFunctionsCount() const;
    flamegpu::size_type getAgentOutputsCount() const;
    bool hasState(const std::string& state_name) const;
    bool hasVariable(const std::string& variable_name) const;
    bool hasFunction(const std::string& function_name) const;
    bool isOutputOnDevice() const;
    const std::set<std::string>& getStates() const;

 protected:
     std::shared_ptr<AgentData> agent;
};
class AgentDescription : public CAgentDescription {
    friend struct AgentFunctionData;
    friend class DependencyGraph;
    friend class AgentFunctionDescription;

 public:
    explicit AgentDescription(std::shared_ptr<AgentData> data);
    AgentDescription(const AgentDescription& other_agent) = default;
    AgentDescription(AgentDescription&& other_agent) = default;
    AgentDescription& operator=(const AgentDescription& other_agent) = default;
    AgentDescription& operator=(AgentDescription&& other_agent) = default;

    void newState(const std::string &state_name);
    void setInitialState(const std::string &initial_state);

    template<typename T, flamegpu::size_type N>
    void newVariable(const std::string &variable_name, const std::array<T, N> &default_value = {});
#ifndef SWIG
    template<typename T>
    void newVariable(const std::string& variable_name, T default_value = {});
#else
    template<typename T>
    void newVariable(const std::string& variable_name, T default_value = 0);
    template<typename T>
    void newVariableArray(const std::string &variable_name, const flamegpu::size_type &length, const std::vector<T>&default_value = {});
#endif

    template<typename AgentFunction>
    AgentFunctionDescription newFunction(const std::string &function_name, AgentFunction a = AgentFunction());
    AgentFunctionDescription newRTCFunction(const std::string& function_name, const std::string& func_src);
    AgentFunctionDescription newRTCFunctionFile(const std::string& function_name, const std::string& file_path);
    AgentFunctionDescription Function(const std::string &function_name);

    void setSortPeriod(const unsigned int sortPeriod);
};

template <typename T, flamegpu::size_type N>
void AgentDescription::newVariable(const std::string &variable_name, const std::array<T, N> &default_value) {
    if (!variable_name.empty() && variable_name[0] == '_') {
        THROW exception::ReservedName("Agent variable names cannot begin with '_', this is reserved for internal usage, "
            "in AgentDescription::newVariable().");
    }
    std::string lower_variable_name = variable_name;
    for (auto& c : lower_variable_name)
        c = static_cast<char>(tolower(c));
    if (lower_variable_name == "name" || lower_variable_name == "state") {
        THROW exception::ReservedName("Agent variables cannot be named 'name' or 'state', these are reserved for backwards compatibility reasons, "
            "in AgentDescription::newVariable().");
    }
    if (lower_variable_name == "_auto_sort_bin_index") {
        THROW exception::ReservedName("The variable name '_auto_sort_bin_index' is reserved for internal usage, "
            "in AgentDescription::newVariable().");
    }
    // Array length 0 makes no sense
    static_assert(detail::type_decode<T>::len_t * N > 0, "A variable cannot have 0 elements.");
    if (agent->variables.find(variable_name) == agent->variables.end()) {
        const std::array<typename detail::type_decode<T>::type_t, detail::type_decode<T>::len_t * N> *casted_default =
        reinterpret_cast<const std::array<typename detail::type_decode<T>::type_t, detail::type_decode<T>::len_t* N>*>(&default_value);
        agent->variables.emplace(variable_name, Variable(*casted_default));
        return;
    }
    THROW exception::InvalidAgentVar("Agent ('%s') already contains variable '%s', "
        "in AgentDescription::newVariable().",
        agent->name.c_str(), variable_name.c_str());
}
template <typename T>
void AgentDescription::newVariable(const std::string &variable_name, const T default_value) {
    newVariable<T, 1>(variable_name, { default_value });
}
#ifdef SWIG
template<typename T>
void AgentDescription::newVariableArray(const std::string& variable_name, const flamegpu::size_type& length, const std::vector<T>& default_value) {
    if (!variable_name.empty() && variable_name[0] == '_') {
        THROW exception::ReservedName("Agent variable names cannot begin with '_', this is reserved for internal usage, "
            "in AgentDescription::newVariable().");
    }
    std::string lower_variable_name = variable_name;
    for (auto& c : lower_variable_name)
        c = static_cast<char>(tolower(c));
    if (lower_variable_name == "name" || lower_variable_name == "state") {
        THROW exception::ReservedName("Agent variables cannot be named 'name' or 'state', these are reserved for backwards compatibility reasons, "
            "in AgentDescription::newVariable().");
    }
    if (length == 0) {
        THROW exception::InvalidAgentVar("Agent variable arrays must have a length greater than 0."
            "in AgentDescription::newVariable().");
    }
    if (default_value.size() && default_value.size() != length) {
        THROW exception::InvalidAgentVar("Agent variable array length specified as %d, but default value provided with %llu elements, "
            "in AgentDescription::newVariable().",
            length, static_cast<unsigned int>(default_value.size()));
    }
    if (agent->variables.find(variable_name) == agent->variables.end()) {
        std::vector<typename detail::type_decode<T>::type_t> temp(static_cast<size_t>(detail::type_decode<T>::len_t * length));
        if (default_value.size()) {
            memcpy(temp.data(), default_value.data(), sizeof(typename detail::type_decode<T>::type_t) * detail::type_decode<T>::len_t * length);
        }
        agent->variables.emplace(variable_name, Variable(detail::type_decode<T>::len_t* length, temp));
        return;
    }
    THROW exception::InvalidAgentVar("Agent ('%s') already contains variable '%s', "
        "in AgentDescription::newVariable().",
        agent->name.c_str(), variable_name.c_str());
}
#endif
// Found in "flamegpu/model/AgentFunctionDescription.h"
// template<typename AgentFunction>
// AgentFunctionDescription &AgentDescription::newFunction(const std::string &function_name, AgentFunction)

}  // namespace flamegpu

#endif  // INCLUDE_FLAMEGPU_MODEL_AGENTDESCRIPTION_H_