NEURON
container.cpp
Go to the documentation of this file.
1 #include "membfunc.h"
4 #include "neuron/model_data.hpp"
5 #include "section.h"
6 
7 #include <cstddef>
8 #include <optional>
9 
10 namespace {
11 void invalidate_cache() {
12  neuron::cache::model.reset();
13 }
14 } // namespace
15 namespace neuron {
17  m_node_data.set_unsorted_callback(invalidate_cache);
18  // needs some re-organisation if we ever want to support multiple Model instances
21 }
25  std::for_each(m_ptrs_for_deferred_deletion.begin(),
27  [](void* ptr) { operator delete[](ptr); });
28 }
29 std::unique_ptr<container::utils::storage_info> Model::find_container_info(void const* cont) const {
30  if (auto maybe_info = m_node_data.find_container_info(cont); maybe_info) {
31  return maybe_info;
32  }
33  for (auto& mech_data: m_mech_data) {
34  if (!mech_data) {
35  continue;
36  }
37  if (auto maybe_info = mech_data->find_container_info(cont); maybe_info) {
38  return maybe_info;
39  }
40  }
41  return {};
42 }
43 
45  mech_data.set_unsorted_callback(invalidate_cache);
46  // This is called when a new Mechanism storage struct is created, i.e. when
47  // a new Mechanism type is registered. When that happens the cache
48  // implicitly becomes invalid, because it does not contain entries for the
49  // newly-added Mechanism. If this proves to be a bottleneck then we could
50  // handle this more efficiently.
51  invalidate_cache();
52 }
53 } // namespace neuron
54 namespace neuron::detail {
55 // See neuron/model_data.hpp
57 } // namespace neuron::detail
58 namespace neuron::cache {
59 std::optional<Model> model{};
60 }
61 namespace neuron::container {
62 std::ostream& operator<<(std::ostream& os, generic_data_handle const& dh) {
63  os << "generic_data_handle{";
64  if (!dh.m_offset.has_always_been_null()) {
65  // modern and valid or once-valid data handle
66  auto* const container_data = *static_cast<void**>(dh.m_container);
67  auto const maybe_info = utils::find_container_info(container_data);
68  if (maybe_info) {
69  if (!maybe_info->container().empty()) {
70  os << "cont=" << maybe_info->container() << ' ';
71  }
72  os << maybe_info->field() << ' ' << dh.m_offset << '/' << maybe_info->size();
73  } else {
74  // couldn't find which container it points into; if container_data is null that will be
75  // because the relevant container/column was deleted
76  os << "cont=" << (container_data ? "unknown " : "deleted ") << dh.m_offset
77  << "/unknown";
78  }
79  } else {
80  // legacy data handle
81  os << "raw=";
82  if (dh.m_container) {
83  // This shouldn't crash, but it might contain some garbage if
84  // we're wrapping a literal value
85  os << dh.m_container;
86  } else {
87  os << "nullptr";
88  }
89  }
90  return os << " type=" << dh.type_name() << '}';
91 }
92 } // namespace neuron::container
93 namespace neuron::container::detail {
94 // See neuron/container/soa_container.hpp
95 std::vector<void*>* defer_delete_storage{};
96 } // namespace neuron::container::detail
98 storage::storage(short mech_type, std::string name, std::vector<Variable> floating_point_fields)
99  : base_type{field::FloatingPoint{std::move(floating_point_fields)}}
100  , m_mech_name{std::move(name)}
101  , m_mech_type{mech_type} {}
102 double& storage::fpfield(std::size_t instance, int field, int array_index) {
103  return get_field_instance<field::FloatingPoint>(instance, field, array_index);
104 }
105 double const& storage::fpfield(std::size_t instance, int field, int array_index) const {
106  return get_field_instance<field::FloatingPoint>(instance, field, array_index);
107 }
109  int field,
110  int array_index) {
111  return get_field_instance_handle<field::FloatingPoint>(id, field, array_index);
112 }
113 std::string_view storage::name() const {
114  return m_mech_name;
115 }
116 short storage::type() const {
117  return m_mech_type;
118 }
119 std::ostream& operator<<(std::ostream& os, storage const& data) {
120  return os << data.name() << "::storage{type=" << data.type() << ", "
121  << data.get_tag<field::FloatingPoint>().num_variables() << " fields}";
122 }
123 } // namespace neuron::container::Mechanism
124 namespace neuron::container::utils {
125 namespace detail {
127  // The whole point of this method is that it receives a raw pointer
129  auto& model = neuron::model();
131  return h;
132  }
133  bool done{false};
134  model.apply_to_mechanisms([&done, &gdh](auto& mech_data) {
135  if (done) {
136  return;
137  }
138  if (auto h = mech_data.find_data_handle(gdh); h.refers_to_a_modern_data_structure()) {
139  gdh = std::move(h);
140  done = true;
141  }
142  });
143  if (done) {
144  return gdh;
145  }
146  return {};
147 }
148 } // namespace detail
149 std::unique_ptr<storage_info> find_container_info(void const* c) {
150  return model().find_container_info(c);
151 }
152 } // namespace neuron::container::utils
static int c
Definition: hoc.cpp:169
#define assert(ex)
Definition: hocassrt.h:24
const char * name
Definition: init.cpp:16
void move(Item *q1, Item *q2, Item *q3)
Definition: list.cpp:200
std::optional< Model > model
Definition: container.cpp:59
std::ostream & operator<<(std::ostream &os, storage const &data)
Definition: container.cpp:119
std::vector< void * > * defer_delete_storage
Defer deleting pointers to deallocated memory.
Definition: container.cpp:95
generic_data_handle promote_or_clear(generic_data_handle)
Try and promote a generic_data_handle wrapping a raw pointer.
Definition: container.cpp:126
std::unique_ptr< storage_info > find_container_info(void const *)
Try and find a helpful name for a container.
Definition: container.cpp:149
std::ostream & operator<<(std::ostream &os, generic_data_handle const &dh)
Definition: container.cpp:62
Model model_data
Definition: container.cpp:56
In mechanism libraries, cannot use auto const token = nrn_ensure_model_data_are_sorted(); because the...
Definition: tnode.hpp:17
Model & model()
Access the global Model instance.
Definition: model_data.hpp:206
mech_type
static double done(void *v)
Definition: ocbbs.cpp:251
Top-level structure.
Definition: model_data.hpp:18
std::unique_ptr< container::utils::storage_info > find_container_info(void const *cont) const
Find some metadata about the given container.
Definition: container.cpp:29
std::vector< void * > m_ptrs_for_deferred_deletion
Backing storage for defer_delete helper.
Definition: model_data.hpp:157
void set_unsorted_callback(container::Mechanism::storage &mech_data)
Definition: container.cpp:44
std::vector< std::unique_ptr< container::Mechanism::storage > > m_mech_data
Storage for mechanism-specific data.
Definition: model_data.hpp:152
container::Node::storage m_node_data
One structure for all Nodes.
Definition: model_data.hpp:145
void apply_to_mechanisms(Callable const &callable)
Apply a function to each non-null Mechanism.
Definition: model_data.hpp:37
container::Node::storage & node_data()
Access the structure containing the data of all Nodes.
Definition: model_data.hpp:24
Catch-all for floating point per-instance variables in the MOD file.
Definition: mechanism.hpp:21
Underlying storage for all instances of a particular Mechanism.
storage(short mech_type, std::string name, std::vector< Variable > floating_point_fields={})
Definition: container.cpp:98
std::string_view name() const
The name of this mechanism.
Definition: container.cpp:113
short type() const
The type of this mechanism.
Definition: container.cpp:116
double & fpfield(std::size_t instance, int field, int array_index=0)
Access floating point values.
Definition: container.cpp:102
data_handle< double > fpfield_handle(non_owning_identifier_without_container id, int field, int array_index=0)
Access floating point values.
Definition: container.cpp:108
Non-template stable handle to a generic value.
bool refers_to_a_modern_data_structure() const
Check if this handle contains a data_handle<T> or just a literal.
non_owning_identifier_without_container m_offset
std::string type_name() const
Return the demangled name of the type this handle refers to.
A non-owning permutation-stable identifier for an entry in a container.
bool has_always_been_null() const
Has the identifier always been null.
void set_unsorted_callback(std::function< void()> unsorted_callback)
Set the callback that is invoked when the container becomes unsorted.
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.
std::unique_ptr< utils::storage_info > find_container_info(void const *cont) const
Check if cont refers to a field in this container.