.. _program_listing_file_include_flamegpu_runtime_agent_HostNewAgentAPI.h: Program Listing for File HostNewAgentAPI.h ========================================== |exhale_lsh| :ref:`Return to documentation for file ` (``include/flamegpu/runtime/agent/HostNewAgentAPI.h``) .. |exhale_lsh| unicode:: U+021B0 .. UPWARDS ARROW WITH TIP LEFTWARDS .. code-block:: cpp #ifndef INCLUDE_FLAMEGPU_RUNTIME_AGENT_HOSTNEWAGENTAPI_H_ #define INCLUDE_FLAMEGPU_RUNTIME_AGENT_HOSTNEWAGENTAPI_H_ #include #include #include #include "flamegpu/model/Variable.h" #include "flamegpu/defines.h" #include "flamegpu/detail/type_decode.h" namespace flamegpu { struct VarOffsetStruct { struct OffsetLen { const ptrdiff_t offset; const size_t len; const std::type_index type; OffsetLen(const ptrdiff_t &_offset, const size_t _len, const std::type_index _type) : offset(_offset) , len(_len) , type(_type) { } bool operator==(const OffsetLen& other) const { return offset == other.offset && len == other.len && type == other.type; } }; std::unordered_map vars; const size_t totalSize; char *const default_data; explicit VarOffsetStruct(const VariableMap &vmap) : totalSize(buildVars(vmap)) , default_data(reinterpret_cast(malloc(totalSize))) { // Fill default_data with default struct memset(default_data, 0, totalSize); for (const auto &a : vmap) { const auto &b = vars.at(a.first); if (a.second.default_value) memcpy(default_data + b.offset, a.second.default_value, b.len); } } explicit VarOffsetStruct(const VarOffsetStruct &other) : vars(other.vars) , totalSize(other.totalSize) , default_data(reinterpret_cast(malloc(other.totalSize))) { memcpy(default_data, other.default_data, totalSize); } ~VarOffsetStruct() { free(default_data); } private: size_t buildVars(const VariableMap &vmap) { size_t _totalAgentSize = 0; for (const auto &a : vmap) { vars.emplace(a.first, OffsetLen(_totalAgentSize, a.second.type_size * a.second.elements, a.second.type)); _totalAgentSize += a.second.type_size * a.second.elements; } return _totalAgentSize; } }; struct NewAgentStorage { explicit NewAgentStorage(const VarOffsetStruct &v, id_t id) : data(reinterpret_cast(malloc(v.totalSize))) , offsets(v) { memcpy(data, offsets.default_data, offsets.totalSize); // Overwrite _id value const auto& var = offsets.vars.find(ID_VARIABLE_NAME); if (var == offsets.vars.end()) { THROW exception::InvalidOperation("Internal agent ID variable was not found, " "in NewAgentStorage.NewAgentStorage()."); } // Don't bother checking type/len memcpy(data + var->second.offset, &id, sizeof(id_t)); } NewAgentStorage(const NewAgentStorage &other) = delete; NewAgentStorage(NewAgentStorage &&other) noexcept : data(other.data) , offsets(other.offsets) { other.data = nullptr; } NewAgentStorage& operator=(const NewAgentStorage& hna) { if (offsets.vars == hna.offsets.vars) { // Iterate and copy all vars individually, skip those marked as internal for (const auto &off : offsets.vars) { if (off.first[0] != '_') { memcpy(this->data + off.second.offset, hna.data + off.second.offset, off.second.len); } } } else { THROW exception::InvalidArgument("Attempting to assign data from agent of different type, in NewAgentStorage::operator=()\n"); } return *this; } ~NewAgentStorage() { if (data) free(data); } template void setVariable(const std::string &var_name, const T val) { const auto &var = offsets.vars.find(var_name); if (var == offsets.vars.end()) { THROW exception::InvalidAgentVar("Variable '%s' not found, " "in NewAgentStorage::setVariable().", var_name.c_str()); } const auto t_type = std::type_index(typeid(typename detail::type_decode::type_t)); if (var->second.type != t_type) { THROW exception::InvalidVarType("Variable '%s' has type '%s', incorrect type '%s' was requested, " "in NewAgentStorage::setVariable().", var_name.c_str(), var->second.type.name(), t_type.name()); } if (var->second.len != sizeof(typename detail::type_decode::type_t) * detail::type_decode::len_t) { THROW exception::InvalidAgentVar("This method is not suitable for agent array variables, " " variable '%s' was passed, " "in NewAgentStorage::setVariable().", var_name.c_str()); } memcpy(data + var->second.offset, &val, var->second.len); } template void setVariable(const std::string &var_name, const unsigned int index, const T val) { const auto &var = offsets.vars.find(var_name); if (var == offsets.vars.end()) { THROW exception::InvalidAgentVar("Variable '%s' not found, " "in NewAgentStorage::setVariable().", var_name.c_str()); } if (N && N != var->second.len / sizeof(typename detail::type_decode::type_t)) { THROW exception::InvalidAgentVar("Agent variable '%s' length mismatch %u != %u, " "in NewAgentStorage::setVariable().", var_name.c_str(), N, var->second.len / sizeof(typename detail::type_decode::type_t)); } const auto t_type = std::type_index(typeid(typename detail::type_decode::type_t)); if (var->second.type != t_type) { THROW exception::InvalidVarType("Variable '%s' has type '%s, incorrect type '%s' was requested, " "in NewAgentStorage::setVariable().", var_name.c_str(), var->second.type.name(), t_type.name()); } if (var->second.len < (sizeof(typename detail::type_decode::type_t) * detail::type_decode::len_t) * (index + 1)) { THROW exception::OutOfRangeVarArray("Variable '%s' is an array with %u elements, index %u is out of range, " "in NewAgentStorage::setVariable().", var_name.c_str(), var->second.len / (sizeof(typename detail::type_decode::type_t) * detail::type_decode::len_t), index); } memcpy(data + var->second.offset + (index * sizeof(typename detail::type_decode::type_t) * detail::type_decode::len_t), &val, sizeof(typename detail::type_decode::type_t) * detail::type_decode::len_t); } #ifndef SWIG template void setVariable(const std::string &var_name, const std::array &val) { const auto &var = offsets.vars.find(var_name); if (var == offsets.vars.end()) { THROW exception::InvalidAgentVar("Variable '%s' not found, " "in NewAgentStorage::setVariable().", var_name.c_str()); } // if (var.second.len == 1 || N == 1) { // THROW exception::InvalidAgentVar("Agent variable '%s' in not an array variable, " // "in NewAgentStorage::setVariable().", // var_name.c_str()); // } const auto t_type = std::type_index(typeid(typename detail::type_decode::type_t)); if (var->second.type != t_type) { THROW exception::InvalidVarType("Variable '%s' has type '%s, incorrect type '%s' was requested, " "in NewAgentStorage::setVariable().", var_name.c_str(), var->second.type.name(), t_type.name()); } if (var->second.len != sizeof(typename detail::type_decode::type_t) * detail::type_decode::len_t * N) { THROW exception::InvalidVarArrayLen("Variable '%s' is an array with %u elements, incorrect array of length %u was provided, " "in NewAgentStorage::setVariable().", var_name.c_str(), var->second.len / (sizeof(typename detail::type_decode::type_t) * detail::type_decode::len_t), N); } memcpy(data + var->second.offset, val.data(), var->second.len); } #else template void setVariableArray(const std::string &var_name, const std::vector &val) { const auto &var = offsets.vars.find(var_name); if (var == offsets.vars.end()) { THROW exception::InvalidAgentVar("Variable '%s' not found, " "in NewAgentStorage::setVariableArray().", var_name.c_str()); } // if (var.second.len == 1 || N == 1) { // THROW exception::InvalidAgentVar("Agent variable '%s' in not an array variable, " // "in NewAgentStorage::setVariableArray().", // var_name.c_str()); // } const auto t_type = std::type_index(typeid(typename detail::type_decode::type_t)); if (var->second.type != t_type) { THROW exception::InvalidVarType("Variable '%s' has type '%s, incorrect type '%s' was requested, " "in NewAgentStorage::setVariableArray().", var_name.c_str(), var->second.type.name(), t_type.name()); } if (var->second.len != sizeof(typename detail::type_decode::type_t) * detail::type_decode::len_t * val.size()) { THROW exception::InvalidVarArrayLen("Variable '%s' is an array with %u elements, incorrect array of length %u was provided, " "in NewAgentStorage::setVariableArray().", var_name.c_str(), var->second.len / (sizeof(typename detail::type_decode::type_t) * detail::type_decode::len_t), val.size()); } memcpy(data + var->second.offset, val.data(), var->second.len); } #endif template T getVariable(const std::string &var_name) const { const auto &var = offsets.vars.find(var_name); if (var == offsets.vars.end()) { THROW exception::InvalidAgentVar("Variable '%s' not found, " "in NewAgentStorage::getVariable()", var_name.c_str()); } const auto t_type = std::type_index(typeid(typename detail::type_decode::type_t)); if (var->second.type != t_type) { THROW exception::InvalidVarType("Variable '%s' has type '%s, incorrect type '%s' was requested, " "in NewAgentStorage::getVariable().", var_name.c_str(), var->second.type.name(), t_type.name()); } if (var->second.len != sizeof(typename detail::type_decode::type_t) * detail::type_decode::len_t) { THROW exception::InvalidAgentVar("This method is not suitable for agent array variables, " " variable '%s' was passed, " "in NewAgentStorage::getVariable().", var_name.c_str()); } return *reinterpret_cast(data + var->second.offset); } template T getVariable(const std::string &var_name, const unsigned int index) { const auto &var = offsets.vars.find(var_name); if (var == offsets.vars.end()) { THROW exception::InvalidAgentVar("Variable '%s' not found, " "in NewAgentStorage::getVariable().", var_name.c_str()); } if (N && N != var->second.len / sizeof(typename detail::type_decode::type_t)) { THROW exception::InvalidAgentVar("Agent variable '%s' length mismatch %u != %u, " "in NewAgentStorage::getVariable().", var_name.c_str(), N, var->second.len / sizeof(typename detail::type_decode::type_t)); } const auto t_type = std::type_index(typeid(typename detail::type_decode::type_t)); if (var->second.type != t_type) { THROW exception::InvalidVarType("Variable '%s' has type '%s, incorrect type '%s' was requested, " "in NewAgentStorage::getVariable().", var_name.c_str(), var->second.type.name(), t_type.name()); } if (var->second.len < sizeof(typename detail::type_decode::type_t) * detail::type_decode::len_t * (index + 1)) { THROW exception::OutOfRangeVarArray("Variable '%s' is an array with %u elements, index %u is out of range, " "in NewAgentStorage::getVariable().", var_name.c_str(), var->second.len / (sizeof(typename detail::type_decode::type_t) * detail::type_decode::len_t), index); } return *reinterpret_cast(data + var->second.offset + (index * sizeof(typename detail::type_decode::type_t) * detail::type_decode::len_t)); } #ifndef SWIG template std::array getVariable(const std::string &var_name) { const auto &var = offsets.vars.find(var_name); if (var == offsets.vars.end()) { THROW exception::InvalidAgentVar("Variable '%s' not found, " "in NewAgentStorage::getVariable().", var_name.c_str()); } // if (var.second.len == 1 || N == 1) { // THROW exception::InvalidAgentVar("Agent variable '%s' in not an array variable, " // "in NewAgentStorage::getVariable().", // var_name.c_str()); // } const auto t_type = std::type_index(typeid(typename detail::type_decode::type_t)); if (var->second.type != t_type) { THROW exception::InvalidVarType("Variable '%s' has type '%s, incorrect type '%s' was requested, " "in NewAgentStorage::getVariable().", var_name.c_str(), var->second.type.name(), t_type.name()); } if (var->second.len != sizeof(typename detail::type_decode::type_t) * detail::type_decode::len_t * N) { THROW exception::InvalidVarArrayLen("Variable '%s' is an array with %u elements, incorrect array of length %u was specified, " "in NewAgentStorage::getVariable().", var_name.c_str(), var->second.len / (sizeof(typename detail::type_decode::type_t) * detail::type_decode::len_t), N); } std::array rtn; memcpy(rtn.data(), data + var->second.offset, var->second.len); return rtn; } #else template std::vector getVariableArray(const std::string &var_name) { const auto &var = offsets.vars.find(var_name); if (var == offsets.vars.end()) { THROW exception::InvalidAgentVar("Variable '%s' not found, " "in NewAgentStorage::getVariableArray().", var_name.c_str()); } const auto t_type = std::type_index(typeid(typename detail::type_decode::type_t)); if (var->second.type != t_type) { THROW exception::InvalidVarType("Variable '%s' has type '%s, incorrect type '%s' was requested, " "in NewAgentStorage::getVariableArray().", var_name.c_str(), var->second.type.name(), t_type.name()); } if (var->second.len % (sizeof(typename detail::type_decode::type_t) * detail::type_decode::len_t) != 0) { THROW exception::InvalidVarType("Variable '%s' has length (%llu) is not divisible by vector length (%u), " "in NewAgentStorage::getVariableArray().", var_name.c_str(), var->second.len / sizeof(typename detail::type_decode::type_t), detail::type_decode::len_t); } const size_t elements = var->second.len / (sizeof(typename detail::type_decode::type_t) * detail::type_decode::len_t); std::vector rtn(elements); memcpy(rtn.data(), data + var->second.offset, var->second.len); return rtn; } #endif friend class CUDASimulation; friend class DeviceAgentVector_impl; private: char *data; const VarOffsetStruct &offsets; }; class HostNewAgentAPI { public: explicit HostNewAgentAPI(NewAgentStorage &_s) : s(&_s) { } HostNewAgentAPI(const HostNewAgentAPI &hna) : s(hna.s) { } HostNewAgentAPI& operator=(const HostNewAgentAPI &hna) { if (&hna != this) *s = *hna.s; return *this; } template void setVariable(const std::string &var_name, const T val) { if (!var_name.empty() && var_name[0] == '_') { THROW exception::ReservedName("Agent variable names cannot begin with '_', this is reserved for internal usage, " "in HostNewAgentAPI::setVariable()."); } s->setVariable(var_name, val); } template void setVariable(const std::string &var_name, const unsigned int index, const T val) { if (!var_name.empty() && var_name[0] == '_') { THROW exception::ReservedName("Agent variable names cannot begin with '_', this is reserved for internal usage, " "in HostNewAgentAPI::setVariable()."); } s->setVariable(var_name, index, val); } #ifndef SWIG template void setVariable(const std::string& var_name, const std::array& val) { if (!var_name.empty() && var_name[0] == '_') { THROW exception::ReservedName("Agent variable names cannot begin with '_', this is reserved for internal usage, " "in HostNewAgentAPI::setVariable()."); } s->setVariable(var_name, val); } #else template void setVariableArray(const std::string &var_name, const std::vector &val) { if (!var_name.empty() && var_name[0] == '_') { THROW exception::ReservedName("Agent variable names cannot begin with '_', this is reserved for internal usage, " "in HostNewAgentAPI::setVariable()."); } s->setVariableArray(var_name, val); } #endif template T getVariable(const std::string &var_name) const { return s->getVariable(var_name); } template T getVariable(const std::string &var_name, const unsigned int index) { return s->getVariable(var_name, index); } #ifndef SWIG template std::array getVariable(const std::string& var_name) { return s->getVariable(var_name); } #else template std::vector getVariableArray(const std::string &var_name) { return s->getVariableArray(var_name); } #endif id_t getID() const { try { return s->getVariable(ID_VARIABLE_NAME); } catch (...) { // Rewrite all exceptions THROW exception::UnknownInternalError("Internal Error: Unable to read internal ID variable, in HostNewAgentAPI::getID()\n"); } } private: // Can't use reference here, makes it non-assignable NewAgentStorage *s; }; } // namespace flamegpu #endif // INCLUDE_FLAMEGPU_RUNTIME_AGENT_HOSTNEWAGENTAPI_H_