Program Listing for File AgentVector_Agent.h

Return to documentation for file (include/flamegpu/simulation/AgentVector_Agent.h)

#ifndef INCLUDE_FLAMEGPU_SIMULATION_AGENTVECTOR_AGENT_H_
#define INCLUDE_FLAMEGPU_SIMULATION_AGENTVECTOR_AGENT_H_

#include <vector>
#include <string>
#include <utility>
#include <memory>

#include "flamegpu/simulation/AgentVector.h"
#include "flamegpu/detail/type_decode.h"

namespace flamegpu {

class AgentInstance;

class AgentVector_CAgent {
    friend AgentVector::CAgent AgentVector::at(flamegpu::size_type) const;
    friend AgentVector::CAgent AgentVector::const_iterator::operator*() const;
    friend AgentVector::CAgent AgentVector::const_reverse_iterator::operator*() const;
    friend AgentVector::iterator AgentVector::insert(flamegpu::size_type pos, flamegpu::size_type count, const AgentVector::Agent&);
    friend class AgentInstance;
    // friend AgentInstance::AgentInstance(const AgentVector::CAgent&);
    // friend AgentInstance& AgentInstance::operator=(const AgentVector::CAgent&);

 public:
    virtual ~AgentVector_CAgent();
    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
    id_t getID() const;
    unsigned int getIndex() const;

 protected:
    AgentVector_CAgent(AgentVector* parent, const std::shared_ptr<const AgentData> &agent, const std::weak_ptr<AgentVector::AgentDataMap> &data, flamegpu::size_type pos);
    const unsigned int index;
    const std::weak_ptr<AgentVector::AgentDataMap> _data;
    std::shared_ptr<const AgentData> _agent;
    AgentVector * const _parent;
};

class AgentVector_Agent : public AgentVector_CAgent {
    friend AgentVector::Agent AgentVector::at(flamegpu::size_type);
    friend AgentVector::Agent AgentVector::iterator::operator*() const;
    friend AgentVector::Agent AgentVector::reverse_iterator::operator*() const;

 public:
    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);
    void setData(const AgentVector_Agent & other) {
        const auto data = _data.lock();
        if (!data) {
            THROW exception::ExpiredWeakPtr("The AgentVector which owns this AgentVector::Agent has been deallocated, "
                "in AgentVector_Agent::setVariable().\n");
        }
        const auto other_data = other._data.lock();
        if (!other_data) {
            THROW exception::ExpiredWeakPtr("The AgentVector which owns the passed AgentVector::Agent has been deallocated, "
                "in AgentVector_Agent::setVariable().\n");
        }
        if (_agent == other._agent || *_agent == *other._agent) {
            if (index != other.index) {
                // Copy individual members as they point to different items    const auto v_it = _data.find(variable_name);
                for (const auto &it : *data) {
                    auto& src_buff = other_data->at(it.first);
                    auto& dst_buff = it.second;
                    const char* src_ptr = static_cast<const char*>(src_buff->getReadOnlyDataPtr()) + (index * dst_buff->getVariableSize());
                    char* dest_ptr = static_cast<char*>(dst_buff->getDataPtr()) + (index * dst_buff->getVariableSize());
                    memcpy(dest_ptr, src_ptr, dst_buff->getVariableSize());
                }
            }
        } else {
            THROW exception::InvalidAgent("Agent description mismatch, '%' provided, '%' required, "
                "in AgentVector_Agent::setData().\n",
                other._agent->name.c_str(), _agent->name.c_str());
        }
    }
#endif
    void resetID();

 private:
    AgentVector_Agent(AgentVector* parent, const std::shared_ptr<const AgentData> &agent, const std::weak_ptr<AgentVector::AgentDataMap> &data, flamegpu::size_type pos);
};

template <typename T>
void AgentVector_Agent::setVariable(const std::string &variable_name, const T value) {
    if (!variable_name.empty() && variable_name[0] == '_') {
        THROW exception::ReservedName("Agent variable names that begin with '_' are reserved for internal usage and cannot be changed directly, "
            "in AgentVector::Agent::setVariable().");
    }
    const auto data = _data.lock();
    if (!data) {
        THROW exception::ExpiredWeakPtr("The AgentVector which owns this AgentVector::Agent has been deallocated, "
            "in AgentVector_Agent::setVariable().\n");
    }
    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 AgentVector_Agent::setVariable().",
            variable_name.c_str());
    }
    auto& v_buff = v_it->second;
    if (v_buff->getElements() != detail::type_decode<T>::len_t) {
        THROW exception::InvalidVarType("Variable '%s' is an array variable, use the array method instead, "
            "in AgentVector_Agent::setVariable().",
            variable_name.c_str());
    }
    if (v_buff->getType() != 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 AgentVector_Agent::setVariable().",
            variable_name.c_str(), v_buff->getType().name(), typeid(typename detail::type_decode<T>::type_t).name());
    }
    _parent->_require(variable_name);
    // do the replace
    static_cast<T*>(v_buff->getDataPtr())[index] = value;
    // Notify (_data was locked above)
    _parent->_changed(variable_name, index);
}
template <typename T, unsigned int N>
void AgentVector_Agent::setVariable(const std::string &variable_name, const std::array<T, N> &value) {
    if (!variable_name.empty() && variable_name[0] == '_') {
        THROW exception::ReservedName("Agent variable names that begin with '_' are reserved for internal usage and cannot be changed directly, "
            "in AgentVector::Agent::setVariable().");
    }
    const auto data = _data.lock();
    if (!data) {
        THROW exception::ExpiredWeakPtr("The AgentVector which owns this AgentVector::Agent has been deallocated, "
            "in AgentVector_Agent::setVariable().\n");
    }
    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 AgentVector_Agent::setVariable().",
            variable_name.c_str());
    }
    auto& v_buff = v_it->second;
    if (v_buff->getElements() % detail::type_decode<T>::len_t != 0) {
        THROW exception::InvalidVarType("Variable array length (%u) is not divisible by vector type length (%u) for variable '%s',  "
            "in AgentVector_Agent::getVariable().",
            v_buff->getElements(), detail::type_decode<T>::len_t, variable_name.c_str());
    }
    if (v_buff->getElements() != N * detail::type_decode<T>::len_t) {
        THROW exception::InvalidVarType("Variable '%s' has '%u' elements, but an array of length %u was passed, "
            "in AgentVector_Agent::setVariable().",
            variable_name.c_str(), v_buff->getElements(), N);
    }
    if (v_buff->getType() != 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 AgentVector_Agent::setVariable().",
            variable_name.c_str(), v_buff->getType().name(), typeid(typename detail::type_decode<T>::type_t).name());
    }
    _parent->_require(variable_name);
    memcpy(static_cast<T*>(v_buff->getDataPtr()) + (index * N), value.data(), sizeof(T) * N);
    // Notify (_data was locked above)
    _parent->_changed(variable_name, index);
}
template <typename T, unsigned int N>
void AgentVector_Agent::setVariable(const std::string &variable_name, const unsigned int array_index, const T value) {
    if (!variable_name.empty() && variable_name[0] == '_') {
        THROW exception::ReservedName("Agent variable names that begin with '_' are reserved for internal usage and cannot be changed directly, "
            "in AgentVector::Agent::setVariable().");
    }
    const auto data = _data.lock();
    if (!data) {
        THROW exception::ExpiredWeakPtr("The AgentVector which owns this AgentVector::Agent has been deallocated, "
          "in AgentVector_Agent::setVariable().\n");
    }
    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 AgentVector_Agent::setVariable().",
            variable_name.c_str());
    }
    auto& v_buff = v_it->second;
    if (N && N != v_buff->getElements()) {
        THROW exception::OutOfBoundsException("Variable array '%s' length mismatch '%u' != '%u', "
            "in AgentVector_Agent::setVariable()\n",
            variable_name.c_str(), N, v_buff->getElements());
    }
    if (v_buff->getElements() % detail::type_decode<T>::len_t != 0) {
        THROW exception::InvalidVarType("Variable array length (%u) is not divisible by vector type length (%u) for variable '%s',  "
            "in AgentVector_Agent::setVariable().",
            v_buff->getElements(), detail::type_decode<T>::len_t, variable_name.c_str());
    }
    if (v_buff->getType() != 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 AgentVector_Agent::setVariable().",
            variable_name.c_str(), v_buff->getType().name(), typeid(typename detail::type_decode<T>::type_t).name());
    }
    const unsigned int t_index = detail::type_decode<T>::len_t * array_index + detail::type_decode<T>::len_t;
    if (t_index > v_buff->getElements() || t_index < array_index) {
        THROW exception::OutOfBoundsException("Index '%u' exceeds array bounds [0-%u) of variable '%s',  "
            "in AgentVector_Agent::setVariable().",
            array_index, v_buff->getElements() / detail::type_decode<T>::len_t, variable_name.c_str());
    }
    _parent->_require(variable_name);
    static_cast<T*>(v_buff->getDataPtr())[(index * (v_buff->getElements() / detail::type_decode<T>::len_t)) + array_index] = value;
}
#ifdef SWIG
template <typename T>
void AgentVector_Agent::setVariableArray(const std::string &variable_name, const std::vector<T> &value) {
    if (!variable_name.empty() && variable_name[0] == '_') {
        THROW exception::ReservedName("Agent variable names that begin with '_' are reserved for internal usage and cannot be changed directly, "
            "in AgentVector::Agent::setVariableArray().");
    }
    const auto data = _data.lock();
    if (!data) {
        THROW exception::ExpiredWeakPtr("The AgentVector which owns this AgentVector::Agent has been deallocated, "
            "in AgentVector_Agent::setVariableArray().\n");
    }
    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 AgentVector_Agent::setVariableArray().",
            variable_name.c_str());
    }
    auto& v_buff = v_it->second;
    if (v_buff->getElements() != 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 AgentVector_Agent::setVariableArray().",
            variable_name.c_str(), v_buff->getElements(), value.size() * detail::type_decode<T>::len_t);
    }
    if (v_buff->getType() != 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 AgentVector_Agent::setVariableArray().",
            variable_name.c_str(), v_buff->getType().name(), typeid(typename detail::type_decode<T>::type_t).name());
    }
    _parent->_require(variable_name);
    memcpy(static_cast<T*>(v_buff->getDataPtr()) + (index * v_buff->getElements()), value.data(), sizeof(T) * v_buff->getElements());
    // Notify (_data was locked above)
    _parent->_changed(variable_name, index);
}
#endif

template <typename T>
T AgentVector_CAgent::getVariable(const std::string &variable_name) const {
    const auto data = _data.lock();
    if (!data) {
        THROW exception::ExpiredWeakPtr("The AgentVector which owns this AgentVector::Agent has been deallocated, "
            "in AgentVector_Agent::getVariable().\n");
    }
    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 AgentVector_Agent::getVariable().",
            variable_name.c_str());
    }
    const auto &v_buff = v_it->second;
    if (v_buff->getElements() != detail::type_decode<T>::len_t) {
        THROW exception::InvalidVarType("Variable '%s' is an array variable, use the array method instead, "
            "in AgentVector_Agent::getVariable().",
            variable_name.c_str());
    }
    if (v_buff->getType() != 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 AgentVector_Agent::getVariable().",
            variable_name.c_str(), v_buff->getType().name(), typeid(typename detail::type_decode<T>::type_t).name());
    }
    _parent->_require(variable_name);
    return static_cast<const T*>(v_buff->getReadOnlyDataPtr())[index];
}
template <typename T, unsigned int N>
std::array<T, N> AgentVector_CAgent::getVariable(const std::string &variable_name) const {
    const auto data = _data.lock();
    if (!data) {
        THROW exception::ExpiredWeakPtr("The AgentVector which owns this AgentVector::Agent has been deallocated, "
            "in AgentVector_Agent::getVariable().\n");
    }
    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 AgentVector_Agent::getVariable().",
            variable_name.c_str());
    }
    const auto& v_buff = v_it->second;
    if (v_buff->getElements() % detail::type_decode<T>::len_t != 0) {
        THROW exception::InvalidVarType("Variable array length (%u) is not divisible by vector type length (%u) for variable '%s',  "
            "in AgentVector_Agent::getVariable().",
            v_buff->getElements(), detail::type_decode<T>::len_t, variable_name.c_str());
    }
    if (v_buff->getElements() != N * detail::type_decode<T>::len_t) {
        THROW exception::InvalidVarType("Variable '%s' has '%u' elements, but an array of length %u was passed, "
            "in AgentVector_Agent::getVariable().",
            variable_name.c_str(), v_buff->getElements() / detail::type_decode<T>::len_t, N);
    }
    if (v_buff->getType() != 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 AgentVector_Agent::getVariable().",
            variable_name.c_str(), v_buff->getType().name(), typeid(typename detail::type_decode<T>::type_t).name());
    }
    _parent->_require(variable_name);
    std::array<T, N> rtn;
    memcpy(rtn.data(), static_cast<const T*>(v_buff->getReadOnlyDataPtr()) + (index * N), sizeof(T) * N);
    return rtn;
}
template <typename T, unsigned int N>
T AgentVector_CAgent::getVariable(const std::string &variable_name, const unsigned int array_index) const {
    const auto data = _data.lock();
    if (!data) {
        THROW exception::ExpiredWeakPtr("The AgentVector which owns this AgentVector::Agent has been deallocated, "
            "in AgentVector_Agent::getVariable().\n");
    }
    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 AgentVector_Agent::getVariable().",
            variable_name.c_str());
    }
    const auto& v_buff = v_it->second;
    if (N && N != v_buff->getElements()) {
        THROW exception::OutOfBoundsException("Variable array '%s' length mismatch '%u' != '%u', "
            "in AgentVector_Agent::getVariable()\n",
            variable_name.c_str(), N, v_buff->getElements());
    }
    if (v_buff->getElements() % detail::type_decode<T>::len_t != 0) {
        THROW exception::InvalidVarType("Variable array length (%u) is not divisible by vector type length (%u) for variable '%s',  "
            "in AgentVector_Agent::getVariable().",
            v_buff->getElements(), detail::type_decode<T>::len_t,  variable_name.c_str());
    }
    const unsigned int t_index = detail::type_decode<T>::len_t * array_index + detail::type_decode<T>::len_t;
    if (t_index > v_buff->getElements() || t_index < array_index) {
        THROW exception::OutOfBoundsException("Index '%u' exceeds array bounds [0-%u) of variable '%s',  "
            "in AgentVector_Agent::getVariable().",
            array_index, v_buff->getElements() / detail::type_decode<T>::len_t, variable_name.c_str());
    }
    if (v_buff->getType() != 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 AgentVector_Agent::getVariable().",
            variable_name.c_str(), v_buff->getType().name(), typeid(typename detail::type_decode<T>::type_t).name());
    }
    _parent->_require(variable_name);
    return static_cast<const T*>(v_buff->getReadOnlyDataPtr())[(index * (v_buff->getElements() / detail::type_decode<T>::len_t)) + array_index];
}
#ifdef SWIG
template <typename T>
std::vector<T> AgentVector_CAgent::getVariableArray(const std::string& variable_name) const {
    const auto data = _data.lock();
    if (!data) {
        THROW exception::ExpiredWeakPtr("The AgentVector which owns this AgentVector::Agent has been deallocated, "
            "in AgentVector_Agent::getVariableArray().\n");
    }
    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 AgentVector_Agent::getVariableArray().",
            variable_name.c_str());
    }
    const auto& v_buff = v_it->second;
    if (v_buff->getType() != 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 AgentVector_Agent::getVariableArray().",
            variable_name.c_str(), v_buff->getType().name(), typeid(typename detail::type_decode<T>::type_t).name());
    }
    _parent->_require(variable_name);
    std::vector<T> rtn(static_cast<size_t>(v_buff->getElements() / detail::type_decode<T>::len_t));
    memcpy(rtn.data(), static_cast<T*>(v_buff->getDataPtr()) + (index * (v_buff->getElements() / detail::type_decode<T>::len_t)), sizeof(typename detail::type_decode<T>::type_t) * v_buff->getElements());
    return rtn;
}
#endif  // IFDEF SWIG

}  // namespace flamegpu

#endif  // INCLUDE_FLAMEGPU_SIMULATION_AGENTVECTOR_AGENT_H_