.. _program_listing_file_include_flamegpu_simulation_detail_EnvironmentManager.cuh: Program Listing for File EnvironmentManager.cuh =============================================== |exhale_lsh| :ref:`Return to documentation for file ` (``include/flamegpu/simulation/detail/EnvironmentManager.cuh``) .. |exhale_lsh| unicode:: U+021B0 .. UPWARDS ARROW WITH TIP LEFTWARDS .. code-block:: cpp #ifndef INCLUDE_FLAMEGPU_SIMULATION_DETAIL_ENVIRONMENTMANAGER_CUH_ #define INCLUDE_FLAMEGPU_SIMULATION_DETAIL_ENVIRONMENTMANAGER_CUH_ #include #include #include #include #include #include #include #include #include #include "flamegpu/defines.h" #include "flamegpu/exception/FLAMEGPUException.h" #include "flamegpu/runtime/detail/curve/HostCurve.cuh" #include "flamegpu/detail/type_decode.h" #include "flamegpu/detail/Any.h" namespace flamegpu { struct SubEnvironmentData; struct EnvironmentData; class CUDASimulation; namespace detail { class EnvironmentManager : public std::enable_shared_from_this { friend class flamegpu::CUDASimulation; private: struct EnvProp { EnvProp(const ptrdiff_t& _offset, const size_t _length, const bool _isConst, const size_type _elements, const std::type_index& _type) : offset(_offset), length(_length), isConst(_isConst), elements(_elements), type(_type) {} ptrdiff_t offset; size_t length; bool isConst; size_type elements; const std::type_index type; }; struct MappedProp { MappedProp(const std::string& _remoteName, const std::shared_ptr &_remoteEnv, bool _isConst = false) : remoteName(_remoteName) , remoteEnv(_remoteEnv) , isConst(_isConst) {} const std::string remoteName; const std::weak_ptr remoteEnv; const bool isConst; }; struct DefragProp { DefragProp(void *_data, const size_t _length, bool _isConst, const size_type _elements, const std::type_index &_type) : data(_data), length(_length), isConst(_isConst), elements(_elements), type(_type), offset(0) { } void *data; size_t length; bool isConst; size_type elements; const std::type_index type; ptrdiff_t offset; }; friend bool operator<(const std::pair& fk, const size_t lk) { return fk.first < lk; } friend bool operator<(const size_t lk, const std::pair& fk) { return lk < fk.first; } friend bool operator<(const std::pair& fk1, const std::pair& fk2) { if (fk1.first == fk2.first) { // If size is equal, order by name return fk1.second < fk2.second; } return fk1.first < fk2.first; } typedef std::multimap, DefragProp, std::less<>> DefragMap; public: [[nodiscard]] static std::shared_ptr create(const EnvironmentData& desc) { std::shared_ptr rtn(new EnvironmentManager()); // Can't use make_shared with private constructor! rtn->init(desc); return rtn; } [[nodiscard]] static std::shared_ptr create(const EnvironmentData& desc, const std::shared_ptr& parent_environment, const SubEnvironmentData& mapping) { std::shared_ptr rtn(new EnvironmentManager()); // Can't use make_shared with private constructor! rtn->init(desc, parent_environment, mapping); return rtn; } ~EnvironmentManager(); EnvironmentManager(EnvironmentManager const&) = delete; void operator=(EnvironmentManager const&) = delete; template T setProperty(const std::string& name, T value); template std::array setProperty(const std::string& name, const std::array& value); template T setProperty(const std::string& name, size_type index, T value); #ifdef SWIG template std::vector setPropertyArray(const std::string& name, const std::vector& value); #endif template T getProperty(const std::string& name); template std::array getProperty(const std::string& name); template T getProperty(const std::string& name, size_type index); #ifdef SWIG template std::vector getPropertyArray(const std::string& name); #endif void resetModel(const EnvironmentData& desc); void updateDevice_async(cudaStream_t stream) const; size_t getBufferLen() const { return h_buffer_len; } const void* getHostBuffer() const { return h_buffer; } const void* getDeviceBuffer() const { return d_buffer; } const std::unordered_map &getPropertiesMap() const { return properties; } private: void init(const EnvironmentData& desc); void init(const EnvironmentData& desc, const std::shared_ptr& parent_environment, const SubEnvironmentData& mapping); void linkMappedProperty(const std::string &parent_name, const std::string& sub_name, const std::shared_ptr& sub_environment); void propagateMappedPropertyValue(const std::string &property_name, const char *src_ptr); void setPropertyDirect(const std::string& property_name, const char * src_ptr); template const EnvProp &findProperty(const std::string& property_name, bool setter, size_type length) const; detail::Any getPropertyAny(const std::string &property_name) const; char *h_buffer = nullptr; char *d_buffer = nullptr; mutable bool d_buffer_ready = false; size_t h_buffer_len = 0; std::unordered_map properties{}; std::multimap mapped_child_properties{}; std::map mapped_parent_properties{}; EnvironmentManager() = default; }; template const EnvironmentManager::EnvProp& EnvironmentManager::findProperty(const std::string& property_name, const bool setter, const size_type length) const { // Limited to Arithmetic types // Compound types would allow host pointers inside structs to be passed static_assert(std::is_arithmetic::type_t>::value || std::is_enum::type_t>::value || std::is_void::type_t>::value, "Only arithmetic types can be used as environmental properties"); const auto a = properties.find(property_name); if (a != properties.end()) { if (std::type_index(typeid(T)) != std::type_index(typeid(void)) && a->second.type != std::type_index(typeid(typename detail::type_decode::type_t))) { THROW exception::InvalidEnvPropertyType("Environmental property with name '%s', type (%s) does not match template argument T (%s), " "in EnvironmentManager::setProperty().", property_name.c_str(), a->second.type.name(), typeid(typename detail::type_decode::type_t).name()); } else if (length && a->second.elements != detail::type_decode::len_t * length) { THROW exception::OutOfBoundsException("Environmental property with name '%s', base length (%u) does not match provided base length (%u), " "in EnvironmentManager::setProperty().", property_name.c_str(), a->second.elements, detail::type_decode::len_t * length); } else if (setter && a->second.isConst) { THROW exception::ReadOnlyEnvProperty("Environmental property with name '%s' is marked as const and cannot be changed, " "in EnvironmentManager::setProperty().", property_name.c_str()); } // Check this here, rather than in 4 separate methods if (setter) d_buffer_ready = false; return a->second; } THROW exception::InvalidEnvProperty("Environmental property with name '%s' does not exist, " "in EnvironmentManager::find().", property_name.c_str()); } template T EnvironmentManager::setProperty(const std::string &name, const T value) { const EnvProp &prop = findProperty(name, true, 1); // Copy old data to return T rtn; char* const dest_ptr = h_buffer + prop.offset; memcpy(&rtn, dest_ptr, sizeof(T)); // Store data memcpy(dest_ptr, &value, sizeof(T)); // Notify children propagateMappedPropertyValue(name, dest_ptr); return rtn; } template std::array EnvironmentManager::setProperty(const std::string &name, const std::array &value) { const EnvProp& prop = findProperty(name, true, N); // Copy old data to return std::array rtn; char* const dest_ptr = h_buffer + prop.offset; memcpy(rtn.data(), dest_ptr, sizeof(T) * N); // Store data memcpy(dest_ptr, value.data(), sizeof(T) * N); // Notify children propagateMappedPropertyValue(name, dest_ptr); return rtn; } template T EnvironmentManager::setProperty(const std::string &name, const size_type index, const T value) { const EnvProp& prop = findProperty(name, true, 0); if (N && N != prop.elements / detail::type_decode::len_t) { THROW exception::OutOfBoundsException("Environmental property with name '%s', array length mismatch (%u != %u), " "in EnvironmentManager::setProperty().", name.c_str(), N, prop.elements / detail::type_decode::len_t); } else if (index >= prop.elements / detail::type_decode::len_t) { THROW exception::OutOfBoundsException("Environmental property with name '%s', index (%u) exceeds named environmental property array's length (%u), " "in EnvironmentManager::setProperty().", name.c_str(), index, prop.elements / detail::type_decode::len_t); } // Copy old data to return T rtn; char* const dest_ptr = h_buffer + prop.offset; memcpy(&rtn, dest_ptr + index * sizeof(T), sizeof(T)); // Store data memcpy(dest_ptr + index * sizeof(T), &value, sizeof(T)); // Notify children propagateMappedPropertyValue(name, dest_ptr); return rtn; } #ifdef SWIG template std::vector EnvironmentManager::setPropertyArray(const std::string& name, const std::vector& value) { const EnvProp& prop = findProperty(name, true, static_cast(value.size())); // Copy old data to return std::vector rtn; rtn.resize(value.size()); char* const dest_ptr = h_buffer + prop.offset; memcpy(rtn.data(), dest_ptr, sizeof(T) * value.size()); // Store data memcpy(dest_ptr, value.data(), sizeof(T) * value.size()); // Notify children propagateMappedPropertyValue(name, dest_ptr); return rtn; } #endif template T EnvironmentManager::getProperty(const std::string &name) { const EnvProp& prop = findProperty(name, false, 1); // Copy data to return T rtn; memcpy(&rtn, h_buffer + prop.offset, sizeof(T)); return rtn; } template std::array EnvironmentManager::getProperty(const std::string &name) { const EnvProp& prop = findProperty(name, false, N); // Copy old data to return std::array rtn; memcpy(rtn.data(), h_buffer + prop.offset, sizeof(T) * N); return rtn; } template T EnvironmentManager::getProperty(const std::string &name, const size_type index) { const EnvProp& prop = findProperty(name, false, 0); if (N && N != prop.elements / detail::type_decode::len_t) { THROW exception::OutOfBoundsException("Environmental property with name '%s', array length mismatch (%u != %u), " "in EnvironmentManager::getProperty().", name.c_str(), N, prop.elements / detail::type_decode::len_t); } else if (index >= prop.elements / detail::type_decode::len_t) { THROW exception::OutOfBoundsException("Environmental property with name '%s', index (%u) exceeds named environmental property array's length (%u), " "in EnvironmentManager::getProperty().", name.c_str(), index, prop.elements / detail::type_decode::len_t); } // Copy old data to return T rtn; memcpy(&rtn, h_buffer + prop.offset + index * sizeof(T), sizeof(T)); return rtn; } #ifdef SWIG template std::vector EnvironmentManager::getPropertyArray(const std::string &name) { const EnvProp& prop = findProperty(name, false, 0); // Copy old data to return const unsigned int N = prop.elements / detail::type_decode::len_t; std::vector rtn; rtn.resize(N); memcpy(rtn.data(), h_buffer + prop.offset, sizeof(T) * N); return rtn; } #endif } // namespace detail } // namespace flamegpu #endif // INCLUDE_FLAMEGPU_SIMULATION_DETAIL_ENVIRONMENTMANAGER_CUH_