NEURON
|
Utility for generating SOA data structures. More...
#include <neuron/container/soa_container.hpp>
Public Types | |
using | frozen_token_type = state_token< Storage > |
Return type of issue_frozen_token() More... | |
Public Member Functions | |
soa () | |
Construct with default-constructed tag type instances. More... | |
soa (Tags... tag_instances) | |
Construct with specific tag instances. More... | |
soa (soa &&)=delete | |
soa is not movable More... | |
soa (soa const &)=delete | |
soa is not copiable More... | |
soa & | operator= (soa &&)=delete |
soa is not move assignable More... | |
soa & | operator= (soa const &)=delete |
soa is not copy assignable More... | |
std::size_t | size () const |
Get the size of the container. More... | |
bool | empty () const |
Test if the container is empty. More... | |
void | shrink_to_fit () |
frozen_token_type | issue_frozen_token () |
Create a token guaranteeing the container is in "frozen" state. More... | |
void | mark_as_sorted (frozen_token_type &write_token) |
Tell the container it is sorted. More... | |
void | mark_as_unsorted () |
Tell the container it is no longer sorted. More... | |
void | set_unsorted_callback (std::function< void()> unsorted_callback) |
Set the callback that is invoked when the container becomes unsorted. More... | |
bool | is_sorted () const |
Query if the underlying vectors are still "sorted". More... | |
template<typename Arg > | |
frozen_token_type | apply_reverse_permutation (Arg &&permutation) |
Permute the SoA-format data using an arbitrary range of integers. More... | |
template<typename Range > | |
void | apply_reverse_permutation (Range permutation, frozen_token_type &sorted_token) |
Permute the SoA-format data using an arbitrary range of integers. More... | |
non_owning_identifier< Storage > | at (std::size_t offset) const |
Get a non-owning identifier to the offset-th entry. More... | |
template<typename Tag > | |
constexpr Tag const & | get_tag () const |
Get the instance of the given tag type. More... | |
template<typename Tag > | |
Tag::type & | get (std::size_t offset) |
Get the offset-th element of the column named by Tag. More... | |
template<typename Tag > | |
Tag::type const & | get (std::size_t offset) const |
Get the offset-th element of the column named by Tag. More... | |
template<typename Tag > | |
data_handle< typename Tag::type > | get_handle (non_owning_identifier_without_container id, int array_index=0) const |
Get a handle to the given element of the column named by Tag. More... | |
template<typename Tag > | |
data_handle< typename Tag::type > | get_field_instance_handle (non_owning_identifier_without_container id, int field_index, int array_index=0) const |
Get a handle to the given element of the field_index-th column named by Tag. More... | |
template<typename Tag > | |
Tag::type & | get_field_instance (std::size_t offset, int field_index, int array_index=0) |
Get the offset-th element of the field_index-th instance of the column named by Tag. More... | |
template<typename Tag > | |
Tag::type const & | get_field_instance (std::size_t offset, int field_index, int array_index=0) const |
Get the offset-th element of the field_index-th instance of the column named by Tag. More... | |
non_owning_identifier_without_container | get_identifier (std::size_t offset) const |
Get the offset-th identifier. More... | |
neuron::container::generic_data_handle | find_data_handle (neuron::container::generic_data_handle input_handle) const |
Return a permutation-stable handle if ptr is inside us. More... | |
template<typename Tag > | |
bool | is_storage_pointer (typename Tag::type const *ptr) const |
Query whether the given pointer-to-vector is the one associated to Tag. More... | |
std::unique_ptr< utils::storage_info > | find_container_info (void const *cont) const |
Check if cont refers to a field in this container. More... | |
template<typename Tag > | |
Tag::type *const * | get_data_ptrs () const |
Get a pointer to a range of pointers that always point to the start of the contiguous storage. More... | |
template<typename Tag > | |
int const * | get_array_dims () const |
Get a pointer to an array holding the array dimensions of the fields associated with this tag. More... | |
template<typename Tag > | |
int | get_array_dims (int field_index) const |
template<typename Tag > | |
size_t | get_num_variables () const |
template<typename Tag > | |
int const * | get_array_dim_prefix_sums () const |
Get a pointer to an array holding the prefix sum of array dimensions for this tag. More... | |
template<typename Tag > | |
field_index | translate_legacy_index (int legacy_index) const |
template<typename Tag > | |
bool | field_active () const |
Query whether the field associated with the given tag is active. More... | |
template<typename... TagsToChange> | |
void | set_field_status (bool enabled) |
Enable/disable the fields associated with the given tags. More... | |
StorageMemoryUsage | memory_usage () const |
Static Public Attributes | |
template<typename Tag > | |
static constexpr bool | has_tag_v = detail::type_in_pack_v<Tag, Tags...> |
Private Member Functions | |
void | erase (std::size_t i) |
Remove the \(i^{\text{th}}\) row from the container. More... | |
template<detail::may_cause_reallocation might_reallocate, typename Callable > | |
Callable | for_each_vector (Callable callable) |
Apply the given function to non-const versions of all vectors. More... | |
template<detail::may_cause_reallocation might_reallocate, typename Callable , typename Tag , typename... RemainingTags> | |
Callable | for_each_tag_vector_impl (Callable callable) |
template<detail::may_cause_reallocation , typename Callable > | |
Callable | for_each_tag_vector_impl (Callable callable) |
template<typename Callable > | |
Callable | for_each_vector (Callable callable) const |
Apply the given function to const-qualified versions of all vectors. More... | |
template<typename Callable , typename Tag , typename... RemainingTags> | |
Callable | for_each_tag_vector_impl (Callable callable) const |
template<typename Callable > | |
Callable | for_each_tag_vector_impl (Callable callable) const |
void | increase_frozen_count () |
Record that a state_token was copied. More... | |
void | decrease_frozen_count () |
Flag that the storage is no longer frozen. More... | |
template<bool internal> | |
void | mark_as_unsorted_impl () |
Set m_sorted = false and execute the callback. More... | |
owning_identifier< Storage > | acquire_owning_identifier () |
Create a new entry and return an identifier that owns it. More... | |
void | throw_error (std::string_view message) const |
Throw an exception with a pretty prefix. More... | |
Private Attributes | |
std::mutex | m_mut {} |
Mutex to protect m_frozen_count and m_sorted. More... | |
bool | m_sorted {false} |
Flag for issue_frozen_token(), mark_as_unsorted() and is_sorted(). More... | |
std::size_t | m_frozen_count {} |
Reference count for tokens guaranteeing the container is frozen. More... | |
std::vector< non_owning_identifier_without_container > | m_indices {} |
Pointers to identifiers that record the current physical row. More... | |
std::tuple< detail::field_data< Tags, detail::field_impl_v< Tags > >... > | m_data {} |
Collection of data columns. More... | |
std::function< void()> | m_unsorted_callback {} |
Callback that is invoked when the container becomes unsorted. More... | |
Static Private Attributes | |
template<typename Tag > | |
static constexpr std::size_t | tag_index_v = detail::index_of_type_v<Tag, Tags...> |
Friends | |
struct | state_token< Storage > |
struct | owning_identifier< Storage > |
Utility for generating SOA data structures.
Storage | Name of the actual storage type derived from soa<...>. |
Tags | Parameter pack of tag types that define the columns included in the container. Types may not be repeated. |
This CRTP base class is used to implement the ~global SOA storage structs that hold (so far) Node and Mechanism data. Ownership of rows in these structs is managed via instances of the owning identifier type neuron::container::owning_identifier instantiated with Storage, and non-owning reference to rows in the data structures are managed via instances of the neuron::container::non_owning_identifier template instantiated with Storage. These identifiers are typically wrapped in a data-structure-specific (i.e. Node- or Mechanism-specific) interface type that provides data-structure-specific accessors and methods to obtain actual data values and more generic handle types such as neuron::container::data_handle<T> and neuron::container::generic_data_handle.
Definition at line 683 of file soa_container.hpp.
using neuron::container::soa< Storage, Tags >::frozen_token_type = state_token<Storage> |
Return type of issue_frozen_token()
Definition at line 923 of file soa_container.hpp.
|
inline |
Construct with default-constructed tag type instances.
Definition at line 687 of file soa_container.hpp.
|
inline |
Construct with specific tag instances.
This is useful if the tag types are not empty, for example if the number of times a column is duplicated is a runtime value.
Definition at line 696 of file soa_container.hpp.
|
delete |
soa is not movable
This is to make it harder to accidentally invalidate pointers-to-storage in handles.
|
delete |
soa is not copiable
This is partly to make it harder to accidentally invalidate pointers-to-storage in handles, and partly because it could be very expensive so it might be better to be more explicit.
|
inlineprivate |
Create a new entry and return an identifier that owns it.
Calling this method increases size() by one. Destroying (modulo move operations) the returned identifier, which has the semantics of a unique_ptr, decreases size() by one.
Note that this has different semantics to standard library container methods such as emplace_back(), push_back(), insert() and so on. Because the returned identifier manages the lifetime of the newly-created entry, discarding the return value will cause the new entry to immediately be deleted.
This is a low-level call that is useful for the implementation of the owning_identifier template. The returned owning identifier is typically wrapped inside an owning handle type that adds data-structure-specific methods (e.g. v(), v_handle() for a Node).
Definition at line 1153 of file soa_container.hpp.
|
inline |
Permute the SoA-format data using an arbitrary range of integers.
permutation | The reverse permutation vector to apply. |
This will fail if the container is frozen.
Definition at line 1045 of file soa_container.hpp.
|
inline |
Permute the SoA-format data using an arbitrary range of integers.
permutation | The reverse permutation vector to apply. |
token | A non-const token demonstrating that the caller is the only party that is forcing the container to be frozen, and (non-const) that they are authorised to transfer that status into this method |
Definition at line 1059 of file soa_container.hpp.
|
inline |
Get a non-owning identifier to the offset-th entry.
This method should only be called if either: there is only one thread, or if a frozen token is held.
Definition at line 1195 of file soa_container.hpp.
|
inlineprivate |
Flag that the storage is no longer frozen.
This is called from the destructor of state_token.
Definition at line 913 of file soa_container.hpp.
|
inline |
Test if the container is empty.
Note that this is not thread-safe if the container is not frozen, i.e. you should either hold a token showing the container is frozen, or you should ensure that no non-const operations on this container are being executed concurrently.
Definition at line 759 of file soa_container.hpp.
|
inlineprivate |
Remove the \(i^{\text{th}}\) row from the container.
This is currently implemented by swapping the last element into position \(i\) (if those are not the same element) and reducing the size by one. Iterators to the last element and the deleted element will be invalidated.
Definition at line 786 of file soa_container.hpp.
|
inline |
Query whether the field associated with the given tag is active.
Definition at line 1525 of file soa_container.hpp.
|
inline |
Check if cont
refers to a field in this container.
This is not intended to be called from multi-threaded code if the container is not frozen.
Definition at line 1450 of file soa_container.hpp.
|
inline |
Return a permutation-stable handle if ptr is inside us.
This is not intended to be called from multi-threaded code if the container is not frozen.
Definition at line 1380 of file soa_container.hpp.
|
inlineprivate |
Definition at line 851 of file soa_container.hpp.
|
inlineprivate |
Definition at line 858 of file soa_container.hpp.
|
inlineprivate |
Definition at line 884 of file soa_container.hpp.
|
inlineprivate |
Definition at line 891 of file soa_container.hpp.
|
inlineprivate |
Apply the given function to non-const versions of all vectors.
The callable has a signature compatible with:
void callable(const Tag& tag, std::vector<Tag::data_type, Allocator>& v, int field_index, int array_dim)
where array_dim
is the array dimensions of the field field_index
.
might_reallocate | Might the callable trigger reallocation of the vectors? |
callable | Callable to invoke on each vector. |
If might_allocate is true then the "cached" values of .data() for each vector will be updated.
Definition at line 839 of file soa_container.hpp.
|
inlineprivate |
Apply the given function to const-qualified versions of all vectors.
The callable has a signature compatible with:
void callable(const Tag& tag, const std::vector<Tag::data_type, Allocator>& v, int field_index, int array_dim)
where array_dim
is the array dimensions of the field field_index
.
Because of the const qualification this cannot cause reallocation and trigger updates of pointers inside m_data, so no might_reallocate parameter is needed.
Definition at line 878 of file soa_container.hpp.
|
inline |
Get the offset-th element of the column named by Tag.
Because this is returning a single value, it is permitted even when the container is frozen. The container being frozen means that operations that would invalidate iterators/pointers are forbidden, not that actual data values cannot change. Note that if the container is not frozen then care should be taken in a multi-threaded environment, as offset
could be invalidated by operations performed by other threads (that would fail if the container were frozen).
Definition at line 1233 of file soa_container.hpp.
|
inline |
Get the offset-th element of the column named by Tag.
If the container is not frozen then care should be taken in a multi-threaded environment, as offset
could be invalidated by operations performed by other threads (that would fail if the container were frozen).
Definition at line 1255 of file soa_container.hpp.
|
inline |
Get a pointer to an array holding the prefix sum of array dimensions for this tag.
Definition at line 1512 of file soa_container.hpp.
|
inline |
Get a pointer to an array holding the array dimensions of the fields associated with this tag.
Definition at line 1493 of file soa_container.hpp.
|
inline |
Definition at line 1498 of file soa_container.hpp.
|
inline |
Get a pointer to a range of pointers that always point to the start of the contiguous storage.
Definition at line 1484 of file soa_container.hpp.
|
inline |
Get the offset-th element of the field_index-th instance of the column named by Tag.
Put differently:
Because this is returning a single value, it is permitted even when the container is frozen. The container being frozen means that operations that would invalidate iterators/pointers are forbidden, not that actual data values cannot change. Note that if the container is not frozen then care should be taken in a multi-threaded environment, as offset
could be invalidated by operations performed by other threads (that would fail if the container were frozen).
Definition at line 1332 of file soa_container.hpp.
|
inline |
Get the offset-th element of the field_index-th instance of the column named by Tag.
If the container is not frozen then care should be taken in a multi-threaded environment, as offset
could be invalidated by operations performed by other threads (that would fail if the container were frozen).
Definition at line 1350 of file soa_container.hpp.
|
inline |
Get a handle to the given element of the field_index-th column named by Tag.
This is not intended to be called from multi-threaded code.
Definition at line 1301 of file soa_container.hpp.
|
inline |
Get a handle to the given element of the column named by Tag.
This is not intended to be called from multi-threaded code, and might suffer from race conditions if the status of optional fields was being modified concurrently.
Definition at line 1276 of file soa_container.hpp.
|
inline |
Get the offset-th identifier.
If the container is not frozen then care should be taken in a multi-threaded environment, as offset
could be invalidated by operations performed by other threads (that would fail if the container were frozen).
Definition at line 1367 of file soa_container.hpp.
|
inline |
Definition at line 1504 of file soa_container.hpp.
|
inlineconstexpr |
Get the instance of the given tag type.
Tag | The tag type, which must be a member of the Tags ... pack. |
For example, if this is called on the Node::storage
then Tag
would be something like Node::field::Area
, Node::field::RHS
or Node::field::Voltage
, which are empty types that serve to define the default values and types of those quantities.
At the time of writing the other possibility is that this is called on an instance of Mechanism::storage
, in which case Tag
must (currently) be Mechanism::field::FloatingPoint
. This stores the names and array dimensions of the RANGE variables in the mechanism (MOD file), which are only known at runtime.
Definition at line 1214 of file soa_container.hpp.
|
inlineprivate |
Record that a state_token was copied.
This should only be called from the copy constructor of a state_token, so m_frozen_count should already be non-zero.
Definition at line 902 of file soa_container.hpp.
|
inline |
Query if the underlying vectors are still "sorted".
See the documentation of issue_frozen_token() for an explanation of what this means. You most likely only want to call this method while holding a token guaranteeing that the container is frozen, and therefore that the sorted-status is fixed.
Definition at line 1032 of file soa_container.hpp.
|
inline |
Query whether the given pointer-to-vector is the one associated to Tag.
This is used so that one can ask a data_handle<T> if it refers to a particular field in a particular container. It is not intended to be called from multi-threaded code if the container is not frozen.
Definition at line 1431 of file soa_container.hpp.
|
inline |
Create a token guaranteeing the container is in "frozen" state.
This does not modify the "sorted" flag on the container.
The token type is copy constructible but not default constructible. There is no need to check if a given instance of the token type is "valid"; if a token is held then the container is guaranteed to be frozen.
The tokens returned by this function are reference counted; the container will be frozen for as long as any token is alive.
Methods such as apply_reverse_permutation() take a non-const reference to one of these tokens. This is because a non-const token referring to a container with a token reference count of exactly one has an elevated status: the holder can lend it out to methods such as apply_reverse_permutation() to authorize specific pointer-invaliding operations. This is useful for implementing methods such as nrn_ensure_model_data_are_sorted() in a thread-safe way.
This method can be called from multiple threads, but note that doing so can have surprising effects w.r.t. the elevated status mentioned in the previous paragraph.
It is user-defined precisely what "sorted" means, but the soa<...> class makes some guarantees:
Note that "frozen" refers to the storage layout, not to the stored value, meaning that values inside a frozen container can still be modified – "frozen" is not "runtime const".
Definition at line 966 of file soa_container.hpp.
|
inline |
Tell the container it is sorted.
write_token | Non-const token demonstrating the caller is the only token owner. |
The meaning of being sorted is externally defined, so we should give external code the opportunity to say that the current order is OK. This probably only makes sense if the external code simply doesn't care about the ordering at all for some reason. This avoids having to construct a trivial permutation vector to achieve the same thing.
Definition at line 986 of file soa_container.hpp.
|
inline |
Tell the container it is no longer sorted.
The meaning of being sorted is externally defined, and it is possible that some external change to an input of the (external) algorithm defining the sort order can mean that the data are no longer considered sorted, even if nothing has actually changed inside this container.
This method can only be called if the container is not frozen.
Definition at line 1005 of file soa_container.hpp.
|
inlineprivate |
Set m_sorted = false and execute the callback.
Definition at line 1118 of file soa_container.hpp.
|
inline |
Definition at line 1542 of file soa_container.hpp.
|
delete |
soa is not move assignable
For the same reason it isn't movable.
|
delete |
soa is not copy assignable
For the same reasons it isn't copy constructible
|
inline |
Enable/disable the fields associated with the given tags.
Definition at line 1535 of file soa_container.hpp.
|
inline |
Set the callback that is invoked when the container becomes unsorted.
This is invoked by mark_as_unsorted() and when a container operation (insertion, permutation, deletion) causes the container to transition from being sorted to being unsorted.
This method is not thread-safe.
Definition at line 1020 of file soa_container.hpp.
|
inline |
Definition at line 767 of file soa_container.hpp.
|
inline |
Get the size of the container.
Note that this is not thread-safe if the container is not frozen, i.e. you should either hold a token showing the container is frozen, or you should ensure that no non-const operations on this container are being executed concurrently.
Definition at line 738 of file soa_container.hpp.
|
inlineprivate |
Throw an exception with a pretty prefix.
Definition at line 1554 of file soa_container.hpp.
|
inline |
Definition at line 1517 of file soa_container.hpp.
|
friend |
Definition at line 786 of file soa_container.hpp.
|
friend |
Definition at line 786 of file soa_container.hpp.
|
staticconstexpr |
Definition at line 1219 of file soa_container.hpp.
|
private |
Collection of data columns.
If the tag implements a num_variables() method then it is duplicated a runtime-determined number of times and get_field_instance<Tag>(i) returns the i-th element of the outer vector (of length num_variables()) of vectors. If is no num_variables() method then the outer vector can be omitted and get<Tag>() returns a vector of values.
Definition at line 1609 of file soa_container.hpp.
|
private |
Reference count for tokens guaranteeing the container is frozen.
Definition at line 1593 of file soa_container.hpp.
|
private |
Pointers to identifiers that record the current physical row.
Definition at line 1598 of file soa_container.hpp.
|
mutableprivate |
Mutex to protect m_frozen_count and m_sorted.
The frozen tokens are used to detect, possibly concurrent, use of incompatible operations, such as sorting while erasing rows. All operations that modify the structure of the container must happen sequentially.
To prevent a different thread from obtaining a frozen token while this thread is modifying structure of the container, this thread should lock m_mut
. Likewise, any thread obtaining a frozen token, should acquire a lock on m_mut
to ensure that there are no concurrent operations that require sequential access to the container.
By following this pattern the thread knows that the conditions related to sorted-ness and froze-ness of the container are valid for the entire duration of the operation (== member function of this class).
Note, enforcing proper sequencing of operations is left to the calling code. However, this mutex enforces the required thread-safety to be able to detect invalid concurrent access patterns.
Definition at line 1583 of file soa_container.hpp.
|
private |
Flag for issue_frozen_token(), mark_as_unsorted() and is_sorted().
Definition at line 1588 of file soa_container.hpp.
|
private |
Callback that is invoked when the container becomes unsorted.
Definition at line 1614 of file soa_container.hpp.
|
staticconstexprprivate |
Definition at line 818 of file soa_container.hpp.