Program Listing for File EnvironmentManager.cuh
↰ Return to documentation for file (include/flamegpu/simulation/detail/EnvironmentManager.cuh
)
#ifndef INCLUDE_FLAMEGPU_SIMULATION_DETAIL_ENVIRONMENTMANAGER_CUH_
#define INCLUDE_FLAMEGPU_SIMULATION_DETAIL_ENVIRONMENTMANAGER_CUH_
#include <cuda_runtime.h>
#include <map>
#include <string>
#include <memory>
#include <set>
#include <unordered_map>
#include <functional>
#include <utility>
#include <vector>
#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<EnvironmentManager> {
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<EnvironmentManager> &_remoteEnv, bool _isConst = false)
: remoteName(_remoteName)
, remoteEnv(_remoteEnv)
, isConst(_isConst) {}
const std::string remoteName;
const std::weak_ptr<EnvironmentManager> 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<size_t, std::string>& fk, const size_t lk) { return fk.first < lk; }
friend bool operator<(const size_t lk, const std::pair<size_t, std::string>& fk) { return lk < fk.first; }
friend bool operator<(const std::pair<size_t, std::string>& fk1, const std::pair<size_t, std::string>& 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<std::pair<size_t, std::string>, DefragProp, std::less<>> DefragMap;
public:
[[nodiscard]] static std::shared_ptr<EnvironmentManager> create(const EnvironmentData& desc) {
std::shared_ptr<EnvironmentManager> rtn(new EnvironmentManager()); // Can't use make_shared with private constructor!
rtn->init(desc);
return rtn;
}
[[nodiscard]] static std::shared_ptr<EnvironmentManager> create(const EnvironmentData& desc, const std::shared_ptr<EnvironmentManager>& parent_environment, const SubEnvironmentData& mapping) {
std::shared_ptr<EnvironmentManager> 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<typename T>
T setProperty(const std::string& name, T value);
template<typename T, size_type N>
std::array<T, N> setProperty(const std::string& name, const std::array<T, N>& value);
template<typename T, size_type N = 0>
T setProperty(const std::string& name, size_type index, T value);
#ifdef SWIG
template<typename T>
std::vector<T> setPropertyArray(const std::string& name, const std::vector<T>& value);
#endif
template<typename T>
T getProperty(const std::string& name);
template<typename T, size_type N>
std::array<T, N> getProperty(const std::string& name);
template<typename T, size_type N = 0>
T getProperty(const std::string& name, size_type index);
#ifdef SWIG
template<typename T>
std::vector<T> 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<std::string, EnvProp> &getPropertiesMap() const {
return properties;
}
private:
void init(const EnvironmentData& desc);
void init(const EnvironmentData& desc, const std::shared_ptr<EnvironmentManager>& parent_environment, const SubEnvironmentData& mapping);
void linkMappedProperty(const std::string &parent_name, const std::string& sub_name, const std::shared_ptr<EnvironmentManager>& 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<typename T>
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<std::string, EnvProp> properties{};
std::multimap<std::string, MappedProp> mapped_child_properties{};
std::map<std::string, MappedProp> mapped_parent_properties{};
EnvironmentManager() = default;
};
template<typename T>
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<typename detail::type_decode<T>::type_t>::value || std::is_enum<typename detail::type_decode<T>::type_t>::value || std::is_void<typename detail::type_decode<T>::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<T>::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<T>::type_t).name());
} else if (length && a->second.elements != detail::type_decode<T>::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<T>::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<typename T>
T EnvironmentManager::setProperty(const std::string &name, const T value) {
const EnvProp &prop = findProperty<T>(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<typename T, flamegpu::size_type N>
std::array<T, N> EnvironmentManager::setProperty(const std::string &name, const std::array<T, N> &value) {
const EnvProp& prop = findProperty<T>(name, true, N);
// Copy old data to return
std::array<T, N> 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<typename T, flamegpu::size_type N>
T EnvironmentManager::setProperty(const std::string &name, const size_type index, const T value) {
const EnvProp& prop = findProperty<T>(name, true, 0);
if (N && N != prop.elements / detail::type_decode<T>::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<T>::len_t);
} else if (index >= prop.elements / detail::type_decode<T>::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<T>::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<typename T>
std::vector<T> EnvironmentManager::setPropertyArray(const std::string& name, const std::vector<T>& value) {
const EnvProp& prop = findProperty<T>(name, true, static_cast<unsigned int>(value.size()));
// Copy old data to return
std::vector<T> 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<typename T>
T EnvironmentManager::getProperty(const std::string &name) {
const EnvProp& prop = findProperty<T>(name, false, 1);
// Copy data to return
T rtn;
memcpy(&rtn, h_buffer + prop.offset, sizeof(T));
return rtn;
}
template<typename T, flamegpu::size_type N>
std::array<T, N> EnvironmentManager::getProperty(const std::string &name) {
const EnvProp& prop = findProperty<T>(name, false, N);
// Copy old data to return
std::array<T, N> rtn;
memcpy(rtn.data(), h_buffer + prop.offset, sizeof(T) * N);
return rtn;
}
template<typename T, flamegpu::size_type N>
T EnvironmentManager::getProperty(const std::string &name, const size_type index) {
const EnvProp& prop = findProperty<T>(name, false, 0);
if (N && N != prop.elements / detail::type_decode<T>::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<T>::len_t);
} else if (index >= prop.elements / detail::type_decode<T>::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<T>::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<typename T>
std::vector<T> EnvironmentManager::getPropertyArray(const std::string &name) {
const EnvProp& prop = findProperty<T>(name, false, 0);
// Copy old data to return
const unsigned int N = prop.elements / detail::type_decode<T>::len_t;
std::vector<T> 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_