.. _program_listing_file_include_flamegpu_simulation_AgentVector.h: Program Listing for File AgentVector.h ====================================== |exhale_lsh| :ref:`Return to documentation for file ` (``include/flamegpu/simulation/AgentVector.h``) .. |exhale_lsh| unicode:: U+021B0 .. UPWARDS ARROW WITH TIP LEFTWARDS .. code-block:: cpp #ifndef INCLUDE_FLAMEGPU_SIMULATION_AGENTVECTOR_H_ #define INCLUDE_FLAMEGPU_SIMULATION_AGENTVECTOR_H_ #include #include #include #include #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> 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& _agent; const std::weak_ptr _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& agent, std::weak_ptr 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 &_agent; const std::weak_ptr _data; size_type _pos; AgentVector* _parent; public: const_iterator(AgentVector* parent, const std::shared_ptr& agent, std::weak_ptr 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 &_agent; const std::weak_ptr _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& agent, std::weak_ptr 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& _agent; const std::weak_ptr _data; size_type _pos; AgentVector* _parent; public: explicit const_reverse_iterator(AgentVector* parent, const std::shared_ptr& agent, std::weak_ptr 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 T *data(const std::string &variable_name); template 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 iterator insert(const_iterator pos, InputIt first, InputIt last); template 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 agent; // Mutable, incase size is increased by DeviceAgentVector hidden application of HostAgentBirth mutable size_type _size; mutable size_type _capacity; std::shared_ptr _data; }; } // namespace flamegpu // @todo - why is this include part way down? #include "flamegpu/simulation/AgentVector_Agent.h" namespace flamegpu { template 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(map_it->second->getDataPtr()); } return nullptr; } template 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(map_it->second->getDataPtr()); } return nullptr; } template 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 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(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(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(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_