Program Listing for File AgentFunctionData.cpp

Return to documentation for file (src/flamegpu/model/AgentFunctionData.cpp)

#include "flamegpu/model/AgentFunctionData.cuh"

#include <string>
#include <memory>

#include "flamegpu/model/AgentDescription.h"
#include "flamegpu/model/AgentFunctionDescription.h"
#include "flamegpu/runtime/detail/curve/curve_rtc.cuh"
#include "flamegpu/detail/cxxname.hpp"

namespace flamegpu {

AgentFunctionData::AgentFunctionData(std::shared_ptr<AgentData> _parent, const std::string &function_name, AgentFunctionWrapper *agent_function, const std::string &in_type, const std::string &out_type)
    : model(_parent->model)
    , func(agent_function)
    , initial_state(_parent->initial_state)
    , end_state(_parent->initial_state)
    , message_output_optional(false)
    , has_agent_death(false)
    , condition(nullptr)
    , parent(_parent)
    , name(function_name)
    , message_in_type(in_type)
    , message_out_type(out_type) { }
AgentFunctionData::AgentFunctionData(std::shared_ptr<AgentData> _parent, const std::string& function_name, const std::string &rtc_function_src, const std::string &in_type, const std::string& out_type, const std::string& code_func_name)
    : model(_parent->model)
    , func(nullptr)
    , rtc_source(rtc_function_src)
    , rtc_func_name(code_func_name)
    , initial_state(_parent->initial_state)
    , end_state(_parent->initial_state)
    , message_output_optional(false)
    , has_agent_death(false)
    , condition(nullptr)
    , parent(_parent)
    , name(function_name)
    , message_in_type(in_type)
    , message_out_type(out_type) { }

AgentFunctionData::AgentFunctionData(const std::shared_ptr<const ModelData> &_model, std::shared_ptr<AgentData> _parent, const AgentFunctionData &other)
    : model(_model)
    , func(other.func)
    , rtc_source(other.rtc_source)
    , rtc_func_name(other.rtc_func_name)
    , initial_state(other.initial_state)
    , end_state(other.end_state)
    , message_output_optional(other.message_output_optional)
    , agent_output_state(other.agent_output_state)
    , has_agent_death(other.has_agent_death)
    , condition(other.condition)
    , rtc_condition_source(other.rtc_condition_source)
    , rtc_func_condition_name(other.rtc_func_condition_name)
    , parent(_parent)
    , name(other.name)
    , message_in_type(other.message_in_type)
    , message_out_type(other.message_out_type) {
    // Manually perform lookup copies
    if (_model) {
        if (auto a = other.message_input.lock()) {
            auto _m = _model->messages.find(a->name);
            if (_m != _model->messages.end()) {
                message_input = _m->second;
            }
        } else if (detail::cxxname::getUnqualifiedName(other.message_in_type) != detail::cxxname::getUnqualifiedName(detail::curve::CurveRTCHost::demangle(std::type_index(typeid(MessageNone))))) {
            THROW exception::InvalidMessageType(
                "Function '%s' is missing bound input message of type '%s', type provided was '%s'.", other.name.c_str(),
                detail::cxxname::getUnqualifiedName(other.message_in_type).c_str(),
                detail::cxxname::getUnqualifiedName(detail::curve::CurveRTCHost::demangle(std::type_index(typeid(MessageNone)))).c_str());
        }
        if (auto a = other.message_output.lock()) {
            auto _m = _model->messages.find(a->name);
            if (_m != _model->messages.end()) {
                message_output = _m->second;
            }
        } else if (detail::cxxname::getUnqualifiedName(other.message_out_type) != detail::cxxname::getUnqualifiedName(detail::curve::CurveRTCHost::demangle(std::type_index(typeid(MessageNone))))) {
            THROW exception::InvalidMessageType(
                "Function '%s' is missing bound output message of type '%s', type provided was '%s'.", other.name.c_str(),
                detail::cxxname::getUnqualifiedName(other.message_out_type).c_str(),
                detail::cxxname::getUnqualifiedName(detail::curve::CurveRTCHost::demangle(std::type_index(typeid(MessageNone)))).c_str());
        }
        if (auto a = other.agent_output.lock()) {
            auto _a = _model->agents.find(a->name);
            if (_a != _model->agents.end()) {
                agent_output = _a->second;
            }
        }
    }
}

bool AgentFunctionData::operator==(const AgentFunctionData &rhs) const {
    if (this == &rhs)  // They point to same object
        return true;
    if ((name == rhs.name)
        //  && (model.lock() == rhs.model.lock())  // Don't check weak pointers
        && (func == rhs.func)
        && (rtc_source == rhs.rtc_source)
        && (rtc_func_name == rhs.rtc_func_name)
        && (initial_state == rhs.initial_state)
        && (end_state == rhs.end_state)
        && (message_output_optional == rhs.message_output_optional)
        && (agent_output_state == rhs.agent_output_state)
        && (has_agent_death == rhs.has_agent_death)
        && (condition == rhs.condition)
        && (rtc_condition_source == rhs.rtc_condition_source)
        && (rtc_func_condition_name == rhs.rtc_func_condition_name)) {
        // Test weak pointers
        {   // parent
            auto a = parent.lock();
            auto b = rhs.parent.lock();
            if (a && b) {
                // We can't call equality here, as that would be infinite recursion
                if (a->name != b->name ||
                    a->functions.size() != b->functions.size()) {
                    return false;
                }
            } else {
                return false;
            }
        }
        {  // message_input
            auto a = message_input.lock();
            auto b = rhs.message_input.lock();
            if (a && b) {
                if (*a != *b)
                    return false;
            } else if ((a && !b) || (!a && b)) {
                return false;
            }
        }
        {  // message_output
            auto a = message_output.lock();
            auto b = rhs.message_output.lock();
            if (a && b) {
                if (*a != *b)
                    return false;
            } else if ((a && !b) || (!a && b)) {
                return false;
            }
        }
        {  // agent_output
            auto a = agent_output.lock();
            auto b = rhs.agent_output.lock();
            if (a && b) {  // Comparing agents here is unsafe, as agent might link back to this same function, so do a reduced comparison
                if (a->name != b->name
                || a->initial_state != b->initial_state
                || a->agent_outputs != b->agent_outputs
                || a->keepDefaultState != b->keepDefaultState
                || a->states.size() != b->states.size()
                || a->functions.size() != b->functions.size()
                || a->variables.size() != b->variables.size()
                || a->states != b->states)
                    return false;
                {  // Compare agent variables
                    for (auto &v : a->variables) {
                        auto _v = b->variables.find(v.first);
                        if (_v == b->variables.end())
                            return false;
                        if (v.second.type_size != _v->second.type_size || v.second.type != _v->second.type || v.second.elements != _v->second.elements)
                            return false;
                    }
                }
                {  // Compare agent functions (compare name only)
                    for (auto &v : a->functions) {
                        auto _v = b->functions.find(v.first);
                        if (_v == b->functions.end())
                            return false;
                    }
                }
            } else if ((a && !b) || (!a && b)) {
                return false;
            }
        }
        return true;
    }
    return false;
}
bool AgentFunctionData::operator==(const CAgentFunctionDescription& rhs) const {
    return *this == *rhs.function;
}
bool AgentFunctionData::operator!=(const AgentFunctionData &rhs) const {
    return !operator==(rhs);
}

}  // namespace flamegpu