Program Listing for File AgentVector.h
↰ Return to documentation for file (include/flamegpu/simulation/AgentVector.h
)
#ifndef INCLUDE_FLAMEGPU_SIMULATION_AGENTVECTOR_H_
#define INCLUDE_FLAMEGPU_SIMULATION_AGENTVECTOR_H_
#include <string>
#include <utility>
#include <memory>
#include <map>
#include "flamegpu/defines.h"
#include "flamegpu/simulation/detail/MemoryVector.h"
#include "flamegpu/model/AgentData.h"
namespace flamegpu {
namespace detail {
class CUDAAgentStateList;
} // namespace detail
class AgentInstance;
class AgentDescription;
class AgentVector_CAgent;
class AgentVector_Agent;
struct AgentData;
class AgentVector {
static const float RESIZE_FACTOR;
friend class detail::CUDAAgentStateList;
friend class AgentVector_CAgent;
friend class AgentVector_Agent;
public:
typedef AgentVector_Agent Agent;
typedef AgentVector_CAgent CAgent;
typedef std::map<std::string, std::unique_ptr<detail::GenericMemoryVector>> AgentDataMap;
// They might all be wrong
class const_iterator;
class const_reverse_iterator;
class iterator {
typedef std::input_iterator_tag iterator_category;
typedef Agent value_type;
typedef size_type difference_type;
typedef const Agent* pointer;
typedef Agent reference;
friend class AgentVector;
const std::shared_ptr<const AgentData>& _agent;
const std::weak_ptr<AgentDataMap> _data;
size_type _pos;
AgentVector* _parent;
public:
operator AgentVector::const_iterator() const {
return const_iterator(_parent, _agent, _data, _pos);
}
iterator(AgentVector* parent, const std::shared_ptr<const AgentData>& agent, std::weak_ptr<AgentDataMap> data, size_type pos = 0)
: _agent(agent), _data(std::move(data)), _pos(pos), _parent(parent) { }
iterator& operator++() { ++_pos; return *this; }
iterator operator++(int) { iterator retval = *this; ++(*this); return retval; }
bool operator==(iterator other) const { return _pos == other._pos &&
(_data.lock() == other._data.lock() || (_data.lock() && other._data.lock() && *_data.lock() == *other._data.lock()));
}
bool operator!=(iterator other) const { return !(*this == other); }
Agent operator*() const;
};
class const_iterator {
typedef std::input_iterator_tag iterator_category;
typedef CAgent value_type;
typedef size_type difference_type;
typedef const CAgent* pointer;
typedef CAgent reference;
friend class AgentVector;
const std::shared_ptr<const AgentData> &_agent;
const std::weak_ptr<AgentDataMap> _data;
size_type _pos;
AgentVector* _parent;
public:
const_iterator(AgentVector* parent, const std::shared_ptr<const AgentData>& agent, std::weak_ptr<AgentDataMap> data, size_type pos = 0)
: _agent(agent), _data(std::move(data)), _pos(pos), _parent(parent) { }
const_iterator& operator++() { ++_pos; return *this; }
const_iterator operator++(int) { const_iterator retval = *this; ++(*this); return retval; }
bool operator==(const_iterator other) const { return _pos == other._pos &&
(_data.lock() == other._data.lock() || (_data.lock() && other._data.lock() && *_data.lock() == *other._data.lock()));
}
bool operator!=(const_iterator other) const { return !(*this == other); }
CAgent operator*() const;
};
class reverse_iterator {
typedef std::input_iterator_tag iterator_category;
typedef Agent value_type;
typedef size_type difference_type;
typedef const Agent* pointer;
typedef Agent reference;
friend class AgentVector;
const std::shared_ptr<const AgentData> &_agent;
const std::weak_ptr<AgentDataMap> _data;
size_type _pos;
AgentVector* _parent;
public:
operator AgentVector::const_reverse_iterator() const {
return const_reverse_iterator(_parent, _agent, _data, _pos);
}
explicit reverse_iterator(AgentVector* parent, const std::shared_ptr<const AgentData>& agent, std::weak_ptr<AgentDataMap> data, size_type pos = 0)
: _agent(agent), _data(std::move(data)), _pos(pos), _parent(parent) { }
reverse_iterator& operator++() { --_pos; return *this; }
reverse_iterator operator++(int) { reverse_iterator retval = *this; ++(*this); return retval; }
bool operator==(reverse_iterator other) const { return _pos == other._pos &&
(_data.lock() == other._data.lock() || (_data.lock() && other._data.lock() && *_data.lock() == *other._data.lock()));
}
bool operator!=(reverse_iterator other) const { return !(*this == other); }
Agent operator*() const;
};
class const_reverse_iterator {
typedef std::input_iterator_tag iterator_category;
typedef CAgent value_type;
typedef size_type difference_type;
typedef const CAgent* pointer;
typedef CAgent reference;
friend class AgentVector;
const std::shared_ptr<const AgentData>& _agent;
const std::weak_ptr<AgentDataMap> _data;
size_type _pos;
AgentVector* _parent;
public:
explicit const_reverse_iterator(AgentVector* parent, const std::shared_ptr<const AgentData>& agent, std::weak_ptr<AgentDataMap> data, size_type pos = 0)
: _agent(agent), _data(std::move(data)), _pos(pos), _parent(parent) { }
const_reverse_iterator& operator++() { --_pos; return *this; }
const_reverse_iterator operator++(int) { const_reverse_iterator retval = *this; ++(*this); return retval; }
bool operator==(const_reverse_iterator other) const { return _pos == other._pos &&
(_data.lock() == other._data.lock() || (_data.lock() && other._data.lock() && *_data.lock() == *other._data.lock()));
}
bool operator!=(const_reverse_iterator other) const { return !(*this == other); }
CAgent operator*() const;
};
explicit AgentVector(const CAgentDescription &agent_desc, size_type count = 0);
explicit AgentVector(const AgentData &agent_desc, size_type count = 0);
AgentVector(const AgentVector &other);
AgentVector(AgentVector &&other) noexcept;
AgentVector& operator=(const AgentVector &other);
AgentVector& operator=(AgentVector &&other) noexcept;
virtual ~AgentVector() = default;
// Element access
Agent at(size_type pos);
CAgent at(size_type pos) const;
Agent operator[](size_type pos);
CAgent operator[](size_type pos) const;
Agent front();
CAgent front() const;
Agent back();
CAgent back() const;
template<typename T>
T *data(const std::string &variable_name);
template<typename T>
const T* data(const std::string &variable_name) const;
void* data(const std::string& variable_name);
const void* data(const std::string& variable_name) const;
// Iterators
iterator begin() noexcept;
const_iterator begin() const noexcept;
const_iterator cbegin() const noexcept;
iterator end() noexcept;
const_iterator end() const noexcept;
const_iterator cend() const noexcept;
reverse_iterator rbegin() noexcept;
const_reverse_iterator rbegin() const noexcept;
const_reverse_iterator crbegin() const noexcept;
reverse_iterator rend() noexcept;
const_reverse_iterator rend() const noexcept;
const_reverse_iterator crend() const noexcept;
// Capacity
bool empty() const;
size_type size() const;
static size_type max_size();
void reserve(size_type new_cap);
size_type capacity() const;
void shrink_to_fit();
// Modifiers
void clear();
void resetAllIDs();
iterator insert(const_iterator pos, const AgentInstance& value);
iterator insert(size_type pos, const AgentInstance& value);
iterator insert(const_iterator pos, const Agent& value);
iterator insert(size_type pos, const Agent& value);
#ifdef SWIG
void py_insert(size_type pos, const AgentInstance& value);
void py_insert(size_type pos, const Agent& value);
#endif
iterator insert(const_iterator pos, size_type count, const AgentInstance& value);
iterator insert(size_type pos, size_type count, const AgentInstance& value);
iterator insert(const_iterator pos, size_type count, const Agent& value);
iterator insert(size_type pos, size_type count, const Agent& value);
#ifdef SWIG
void py_insert(size_type pos, size_type count, const AgentInstance& value);
void py_insert(size_type pos, size_type count, const Agent& value);
#endif
template<class InputIt>
iterator insert(const_iterator pos, InputIt first, InputIt last);
template<class InputIt>
iterator insert(size_type pos, InputIt first, InputIt last);
iterator erase(const_iterator pos);
iterator erase(size_type pos);
#ifdef SWIG
void py_erase(size_type pos);
#endif
iterator erase(const_iterator first, const_iterator last);
iterator erase(size_type first, size_type last);
#ifdef SWIG
void py_erase(size_type first, size_type last);
#endif
void push_back(const AgentInstance& value);
void push_back();
void pop_back();
void resize(size_type count);
void swap(AgentVector& other) noexcept;
bool operator==(const AgentVector &other) const;
bool operator!=(const AgentVector &other) const;
// Util
std::string getAgentName() const { return agent->name; }
bool matchesAgentType(const AgentData &other) const;
bool matchesAgentType(const CAgentDescription& other) const;
std::type_index getVariableType(const std::string& variable_name) const;
const VariableMap &getVariableMetaData() const;
std::string getInitialState() const;
protected:
virtual void _insert(size_type pos, size_type count) { }
virtual void _erase(size_type pos, size_type count) { }
virtual void _changed(const std::string& variable_name, size_type pos) { }
virtual void _changedAfter(const std::string &variable_name, size_type pos) { }
virtual void _require(const std::string& variable_name) const { }
virtual void _requireAll() const { }
virtual void _requireLength() const { }
void internal_resize(size_type count, bool init);
void init(size_type first, size_type last);
std::shared_ptr<const AgentData> agent;
// Mutable, incase size is increased by DeviceAgentVector hidden application of HostAgentBirth
mutable size_type _size;
mutable size_type _capacity;
std::shared_ptr<AgentDataMap> _data;
};
} // namespace flamegpu
// @todo - why is this include part way down?
#include "flamegpu/simulation/AgentVector_Agent.h"
namespace flamegpu {
template<typename T>
T* AgentVector::data(const std::string& variable_name) {
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::data().");
}
// Is variable name found
const auto &var = agent->variables.find(variable_name);
if (var == agent->variables.end()) {
THROW exception::InvalidAgentVar("Variable with name '%s' was not found in agent '%s', "
"in AgentVector::data().",
variable_name.c_str(), agent->name.c_str());
}
if (std::type_index(typeid(T)) != var->second.type) {
THROW exception::InvalidVarType("Variable '%s' is of a different type. "
"'%s' was expected, but '%s' was requested,"
"in AgentVector::data().",
variable_name.c_str(), var->second.type.name(), typeid(T).name());
}
// Does the map have a vector
const auto& map_it = _data->find(variable_name);
if (map_it != _data->end()) {
_requireLength();
_require(variable_name);
_changedAfter(variable_name, 0);
return static_cast<T*>(map_it->second->getDataPtr());
}
return nullptr;
}
template<typename T>
const T* AgentVector::data(const std::string& variable_name) const {
// Is variable name found
const auto& var = agent->variables.find(variable_name);
if (var == agent->variables.end()) {
THROW exception::InvalidAgentVar("Variable with name '%s' was not found in agent '%s', "
"in AgentVector::data().",
variable_name.c_str(), agent->name.c_str());
}
if (std::type_index(typeid(T)) != var->second.type) {
THROW exception::InvalidVarType("Variable '%s' is of a different type. "
"'%s' was expected, but '%s' was requested,"
"in AgentVector::data().",
variable_name.c_str(), var->second.type.name(), typeid(T).name());
}
// Does the map have a vector
const auto& map_it = _data->find(variable_name);
if (map_it != _data->end()) {
_requireLength();
_require(variable_name);
return static_cast<T*>(map_it->second->getDataPtr());
}
return nullptr;
}
template<class InputIt>
AgentVector::iterator AgentVector::insert(const_iterator pos, InputIt first, InputIt last) {
if (pos._agent != agent && *pos._agent != *agent) {
THROW exception::InvalidAgent("Agent description mismatch, '%' provided to pos, '%' required, "
"in AgentVector::push_back().\n",
last._agent->name.c_str(), agent->name.c_str());
}
return insert(pos._pos, first, last);
}
template<class InputIt>
AgentVector::iterator AgentVector::insert(size_type pos, InputIt first, InputIt last) {
// Insert elements inrange first-last before pos
if (first == last)
return iterator(this, agent, _data, pos);
// Confirm they are for the same agent type
if (first._agent != agent && *first._agent != *agent) {
THROW exception::InvalidAgent("Agent description mismatch, '%' provided to first, '%' required, "
"in AgentVector::push_back().\n",
first._agent->name.c_str(), agent->name.c_str());
}
if (last._agent != agent && *last._agent != *agent) {
THROW exception::InvalidAgent("Agent description mismatch, '%' provided to last, '%' required, "
"in AgentVector::push_back().\n",
last._agent->name.c_str(), agent->name.c_str());
}
// Expand capacity if required
const size_type first_copy_index = first._pos < last._pos ? first._pos : last._pos;
const size_type end_copy_index = first._pos < last._pos ? last._pos : first._pos;
const size_type copy_count = end_copy_index - first_copy_index;
{
_requireLength();
size_type new_capacity = _capacity;
assert((_capacity * RESIZE_FACTOR) + 1 > _capacity);
while (_size + copy_count > new_capacity) {
new_capacity = static_cast<size_type>(new_capacity * RESIZE_FACTOR) + 1;
}
internal_resize(new_capacity, true);
}
// Get first index;
const size_type insert_index = pos;
// Fix each variable
auto first_data = first._data.lock();
if (!first_data) {
THROW exception::ExpiredWeakPtr("The AgentVector which owns the passed iterators has been deallocated, "
"in AgentVector::insert().\n");
}
// If we are not appending, ensure we have upto date device data
if (pos < _size)
_requireAll();
const id_t ID_DEFAULT = ID_NOT_SET;
for (const auto& v : agent->variables) {
const auto it = _data->find(v.first);
char* t_data = static_cast<char*>(it->second->getDataPtr());
const size_t variable_size = v.second.type_size * v.second.elements;
// Move all items after this index backwards count places
if (_size) {
for (unsigned int i = _size - 1; i >= insert_index; --i) {
// Copy items individually, incase the src and destination overlap
memcpy(t_data + (i + copy_count) * variable_size, t_data + i * variable_size, variable_size);
}
}
// Copy across item data, ID has a special case, where it is default init instead of being copied
if (v.first == ID_VARIABLE_NAME) {
if (v.second.elements != 1 || v.second.type != std::type_index(typeid(id_t))) {
THROW exception::InvalidOperation("Agent's internal ID variable is not type %s[1], "
"in AgentVector::insert()\n", std::type_index(typeid(id_t)).name());
}
for (unsigned int i = insert_index; i < insert_index + copy_count; ++i) {
memcpy(t_data + i * variable_size, &ID_DEFAULT, sizeof(id_t));
}
} else {
const auto other_it = first_data->find(v.first);
const char* o_data = static_cast<const char*>(other_it->second->getReadOnlyDataPtr());
memcpy(t_data + insert_index * variable_size, o_data + first_copy_index * variable_size, copy_count * variable_size);
}
}
// Increase size
_size += copy_count;
// Notify subclasses
_insert(pos, copy_count);
// Return iterator to first inserted item
return iterator(this, agent, _data, insert_index);
}
#ifdef SWIG
void AgentVector::py_insert(size_type pos, const AgentInstance& value) {
insert(pos, value);
}
void AgentVector::py_insert(size_type pos, const Agent& value) {
insert(pos, value);
}
void AgentVector::py_insert(size_type pos, size_type count, const AgentInstance& value) {
insert(pos, count, value);
}
void AgentVector::py_insert(size_type pos, size_type count, const Agent& value) {
insert(pos, count, value);
}
void AgentVector::py_erase(size_type pos) {
erase(pos);
}
void AgentVector::py_erase(size_type first, size_type last) {
erase(first, last);
}
#endif // ifdef SWIG
} // namespace flamegpu
#endif // INCLUDE_FLAMEGPU_SIMULATION_AGENTVECTOR_H_