Program Listing for File AgentInstance.h

Return to documentation for file (include/flamegpu/runtime/agent/AgentInstance.h)

#ifndef INCLUDE_FLAMEGPU_RUNTIME_AGENT_AGENTINSTANCE_H_
#define INCLUDE_FLAMEGPU_RUNTIME_AGENT_AGENTINSTANCE_H_

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


#include "flamegpu/model/AgentData.h"
#include "flamegpu/simulation/AgentVector.h"
#include "flamegpu/detail/Any.h"

namespace flamegpu {

class AgentDescription;

class AgentInstance {
    friend AgentVector::iterator AgentVector::insert(AgentVector::const_iterator pos, flamegpu::size_type count, const AgentInstance& value);
    friend AgentVector::iterator AgentVector::insert(flamegpu::size_type pos, flamegpu::size_type count, const AgentInstance& value);

 public:
    explicit AgentInstance(const CAgentDescription &agent_desc);

    AgentInstance(const AgentInstance& other);
    explicit AgentInstance(const AgentVector::CAgent& other);

    AgentInstance(AgentInstance&& other) noexcept;

    AgentInstance& operator=(const AgentInstance& other);
    AgentInstance& operator=(const AgentVector::CAgent& other);
    AgentInstance& operator=(AgentInstance&& other) noexcept;

    template <typename T>
    T getVariable(const std::string& variable_name) const;
    template <typename T, unsigned int N>
    std::array<T, N> getVariable(const std::string& variable_name) const;
    template <typename T, unsigned int N = 0>
    T getVariable(const std::string& variable_name, unsigned int index) const;
#ifdef SWIG
    template <typename T>
    std::vector<T> getVariableArray(const std::string& variable_name) const;
#endif

    template <typename T>
    void setVariable(const std::string& variable_name, T value);
    template <typename T, unsigned int N>
    void setVariable(const std::string& variable_name, const std::array<T, N>& value);
    template <typename T, unsigned int N = 0>
    void setVariable(const std::string& variable_name, unsigned int index, T value);
#ifdef SWIG
    template <typename T>
    void setVariableArray(const std::string& variable_name, const std::vector<T>& value);
#endif

 private:
    std::map<std::string, detail::Any> _data;
    std::shared_ptr<const AgentData> _agent;
};


template <typename T>
T AgentInstance::getVariable(const std::string& variable_name) const {
    const auto v_it = _data.find(variable_name);
    if (v_it == _data.end()) {
        THROW exception::InvalidAgentVar("Variable with name '%s' was not found in agent, "
            "in AgentInstance::getVariable().",
            variable_name.c_str());
    }
    const auto& v_buff = v_it->second;
    if (v_buff.elements != detail::type_decode<T>::len_t) {
        THROW exception::InvalidVarType("Variable '%s' is an array variable, use the array method instead, "
            "in AgentInstance::getVariable().",
            variable_name.c_str());
    }
    if (v_buff.type != std::type_index(typeid(typename detail::type_decode<T>::type_t))) {
        THROW exception::InvalidVarType("Variable '%s' is of a different type. "
            "'%s' was expected, but '%s' was requested,"
            "in AgentInstance::getVariable().",
            variable_name.c_str(), v_buff.type.name(), typeid(typename detail::type_decode<T>::type_t).name());
    }
    return *static_cast<const T*>(v_buff.ptr);
}
template <typename T, unsigned int N>
std::array<T, N> AgentInstance::getVariable(const std::string& variable_name) const {
    const auto v_it = _data.find(variable_name);
    if (v_it == _data.end()) {
        THROW exception::InvalidAgentVar("Variable with name '%s' was not found in agent, "
            "in AgentInstance::getVariable().",
            variable_name.c_str());
    }
    const auto& v_buff = v_it->second;
    if (v_buff.elements != N * detail::type_decode<T>::len_t) {
        THROW exception::InvalidVarType("Variable '%s' has '%u' elements, but an array of length %u was passed, "
            "in AgentInstance::getVariable().",
            variable_name.c_str(), v_buff.elements / detail::type_decode<T>::len_t, N);
    }
    if (v_buff.type != std::type_index(typeid(typename detail::type_decode<T>::type_t))) {
        THROW exception::InvalidVarType("Variable '%s' is of a different type. "
            "'%s' was expected, but '%s' was requested,"
            "in AgentInstance::getVariable().",
            variable_name.c_str(), v_buff.type.name(), typeid(typename detail::type_decode<T>::type_t).name());
    }
    std::array<T, N> rtn;
    memcpy(rtn.data(), v_buff.ptr, sizeof(T) * N);
    return rtn;
}
template <typename T, unsigned int N>
T AgentInstance::getVariable(const std::string& variable_name, const unsigned int index) const {
    const auto v_it = _data.find(variable_name);
    if (v_it == _data.end()) {
        THROW exception::InvalidAgentVar("Variable with name '%s' was not found in agent, "
            "in AgentInstance::getVariable().",
            variable_name.c_str());
    }
    const auto& v_buff = v_it->second;
    if (N && N != v_buff.elements) {
        THROW exception::OutOfBoundsException("Variable array '%s' length mismatch '%u' != '%u', "
            "in AgentInstance::getVariable()\n",
            variable_name.c_str(), N, v_buff.elements);
    }
    if (v_buff.elements % detail::type_decode<T>::len_t != 0) {
        THROW exception::InvalidVarType("Variable array length (%u) is not visible by vector length (%u),  "
            "in AgentInstance::getVariable().",
            v_buff.elements, detail::type_decode<T>::len_t, variable_name.c_str());
    }
    const unsigned int t_index = detail::type_decode<T>::len_t * index + detail::type_decode<T>::len_t;
    if (t_index > v_buff.elements || t_index < index) {
        THROW exception::OutOfBoundsException("Index '%u' exceeds array bounds [0-%u) of variable '%s',  "
            "in AgentInstance::getVariable().",
            index, v_buff.elements, variable_name.c_str());
    }
    if (v_buff.type != std::type_index(typeid(typename detail::type_decode<T>::type_t))) {
        THROW exception::InvalidVarType("Variable '%s' is of a different type. "
            "'%s' was expected, but '%s' was requested,"
            "in AgentInstance::getVariable().",
            variable_name.c_str(), v_buff.type.name(), typeid(typename detail::type_decode<T>::type_t).name());
    }
    return static_cast<T*>(v_buff.ptr)[index];
}
#ifdef SWIG
template <typename T>
std::vector<T> AgentInstance::getVariableArray(const std::string& variable_name) const {
    const auto v_it = _data.find(variable_name);
    if (v_it == _data.end()) {
        THROW exception::InvalidAgentVar("Variable with name '%s' was not found in agent, "
            "in AgentInstance::getVariableArray().",
            variable_name.c_str());
    }
    const auto& v_buff = v_it->second;
    if (v_buff.elements % detail::type_decode<T>::len_t != 0) {
        THROW exception::InvalidVarType("Variable array length (%u) is not visible by vector length (%u),  "
            "in AgentInstance::getVariableArray().",
            v_buff.elements, detail::type_decode<T>::len_t, variable_name.c_str());
    }
    if (v_buff.type != std::type_index(typeid(typename detail::type_decode<T>::type_t))) {
        THROW exception::InvalidVarType("Variable '%s' is of a different type. "
            "'%s' was expected, but '%s' was requested,"
            "in AgentInstance::getVariableArray().",
            variable_name.c_str(), v_buff.type.name(), typeid(typename detail::type_decode<T>::type_t).name());
    }
    std::vector<T> rtn(static_cast<size_t>(v_buff.elements / detail::type_decode<T>::len_t));
    memcpy(rtn.data(), static_cast<T*>(v_buff.ptr), sizeof(T) * v_buff.elements);
    return rtn;
}
#endif
template <typename T>
void AgentInstance::setVariable(const std::string& variable_name, T value) {
    const auto v_it = _data.find(variable_name);
    if (v_it == _data.end()) {
        THROW exception::InvalidAgentVar("Variable with name '%s' was not found in agent, "
            "in AgentInstance::setVariable().",
            variable_name.c_str());
    }
    auto& v_buff = v_it->second;
    if (v_buff.elements != detail::type_decode<T>::len_t) {
        THROW exception::InvalidVarType("Variable '%s' is an array variable, use the array method instead, "
            "in AgentInstance::setVariable().",
            variable_name.c_str());
    }
    if (v_buff.type != std::type_index(typeid(typename detail::type_decode<T>::type_t))) {
        THROW exception::InvalidVarType("Variable '%s' is of a different type. "
            "'%s' was expected, but '%s' was requested,"
            "in AgentInstance::setVariable().",
            variable_name.c_str(), v_buff.type.name(), typeid(typename detail::type_decode<T>::type_t).name());
    }
    // do the replace
    *static_cast<T*>(v_buff.ptr) = value;
}
template <typename T, unsigned int N>
void AgentInstance::setVariable(const std::string& variable_name, const std::array<T, N>& value) {
    const auto v_it = _data.find(variable_name);
    if (v_it == _data.end()) {
        THROW exception::InvalidAgentVar("Variable with name '%s' was not found in agent, "
            "in AgentInstance::setVariable().",
            variable_name.c_str());
    }
    auto& v_buff = v_it->second;
    if (v_buff.elements != N * detail::type_decode<T>::len_t) {
        THROW exception::InvalidVarType("Variable '%s' has '%u' elements, but an array of length %u was passed, "
            "in AgentInstance::setVariable().",
            variable_name.c_str(), v_buff.elements, N);
    }
    if (v_buff.type != std::type_index(typeid(typename detail::type_decode<T>::type_t))) {
        THROW exception::InvalidVarType("Variable '%s' is of a different type. "
            "'%s' was expected, but '%s' was requested,"
            "in AgentInstance::setVariable().",
            variable_name.c_str(), v_buff.type.name(), typeid(typename detail::type_decode<T>::type_t).name());
    }
    memcpy(static_cast<T*>(v_buff.ptr), value.data(), sizeof(T) * N);
}
template <typename T, unsigned int N>
void AgentInstance::setVariable(const std::string& variable_name, const unsigned int index, T value) {
    const auto v_it = _data.find(variable_name);
    if (v_it == _data.end()) {
        THROW exception::InvalidAgentVar("Variable with name '%s' was not found in agent, "
            "in AgentInstance::setVariable().",
            variable_name.c_str());
    }
    auto& v_buff = v_it->second;
    if (N && N != v_buff.elements) {
        THROW exception::OutOfBoundsException("Variable array '%s' length mismatch '%u' != '%u', "
            "in AgentInstance::setVariable()\n",
            variable_name.c_str(), N, v_buff.elements);
    }
    if (v_buff.elements % detail::type_decode<T>::len_t != 0) {
        THROW exception::InvalidVarType("Variable array length (%u) is not visible by vector length (%u),  "
            "in AgentInstance::setVariable().",
           v_buff.elements, detail::type_decode<T>::len_t, variable_name.c_str());
    }
    const unsigned int t_index = detail::type_decode<T>::len_t * index + detail::type_decode<T>::len_t;
    if (t_index > v_buff.elements || t_index < index) {
        THROW exception::OutOfBoundsException("Index '%u' exceeds array bounds [0-%u) of variable '%s',  "
            "in AgentInstance::setVariable().",
            index, v_buff.elements, variable_name.c_str());
    }
    if (v_buff.type != std::type_index(typeid(typename detail::type_decode<T>::type_t))) {
        THROW exception::InvalidVarType("Variable '%s' is of a different type. "
            "'%s' was expected, but '%s' was requested,"
            "in AgentInstance::setVariable().",
            variable_name.c_str(), v_buff.type.name(), typeid(typename detail::type_decode<T>::type_t).name());
    }
    static_cast<T*>(v_buff.ptr)[index] = value;
}
#ifdef SWIG
template <typename T>
void AgentInstance::setVariableArray(const std::string& variable_name, const std::vector<T>& value) {
    const auto v_it = _data.find(variable_name);
    if (v_it == _data.end()) {
        THROW exception::InvalidAgentVar("Variable with name '%s' was not found in agent, "
            "in AgentInstance::setVariableArray().",
            variable_name.c_str());
    }
    auto& v_buff = v_it->second;
    if (v_buff.elements != value.size() * detail::type_decode<T>::len_t) {
        THROW exception::InvalidVarType("Variable '%s' has '%u' elements, but an array of length %u was passed, "
            "in AgentInstance::setVariableArray().",
            variable_name.c_str(), v_buff.elements, value.size() * detail::type_decode<T>::len_t);
    }
    if (v_buff.type != std::type_index(typeid(typename detail::type_decode<T>::type_t))) {
        THROW exception::InvalidVarType("Variable '%s' is of a different type. "
            "'%s' was expected, but '%s' was requested,"
            "in AgentInstance::setVariableArray().",
            variable_name.c_str(), v_buff.type.name(), typeid(typename detail::type_decode<T>::type_t).name());
    }
    memcpy(static_cast<T*>(v_buff.ptr), value.data(), sizeof(T) * v_buff.elements);
}
#endif  // SWIG

}  // namespace flamegpu

#endif  // INCLUDE_FLAMEGPU_RUNTIME_AGENT_AGENTINSTANCE_H_