NEURON
generic_data_handle.cpp
Go to the documentation of this file.
3 #include "neuron/model_data.hpp"
4 
5 #include <catch2/catch_test_macros.hpp>
6 
7 #include <optional>
8 #include <sstream>
9 
10 using namespace neuron::container;
11 
12 template <typename T>
13 static std::string to_str(T const& x) {
14  std::ostringstream oss;
15  oss << x;
16  return oss.str();
17 }
18 
19 TEST_CASE("generic_data_handle", "[Neuron][data_structures][generic_data_handle]") {
20  // Checks that apply to both typeless-null and double-typed null handles.
21  auto const check_double_or_typeless_null_handle = [](auto& handle) {
22  THEN("Check it does not claim to refer to a modern container") {
23  REQUIRE_FALSE(handle.refers_to_a_modern_data_structure());
24  }
25  THEN("Check it can be converted to a null data_handle<double>") {
26  auto const typed_null = static_cast<data_handle<double>>(handle);
27  REQUIRE_FALSE(typed_null);
28  REQUIRE(typed_null == data_handle<double>{});
29  }
30  THEN("Check it can be made typeless-null by assigning nullptr") {
31  REQUIRE_NOTHROW(handle = nullptr);
32  AND_THEN("Check it has the expected string representation") {
33  REQUIRE(to_str(handle) == "generic_data_handle{raw=nullptr type=typeless_null}");
34  }
35  }
36  THEN("Check it can be made double*-null by assigning a null double*") {
37  REQUIRE_NOTHROW(handle = static_cast<double*>(nullptr));
38  AND_THEN("Check it has the expected string representation") {
39  REQUIRE(to_str(handle) == "generic_data_handle{raw=nullptr type=double*}");
40  }
41  }
42  THEN("Check it can be assigned a literal int value") {
43  REQUIRE_NOTHROW(handle = 42);
44  AND_THEN("Check it has the expected string representation") {
45  REQUIRE(to_str(handle) == "generic_data_handle{raw=0x2a type=int}");
46  }
47  }
48  THEN("Check it can be assigned a literal double value") {
49  REQUIRE_NOTHROW(handle = 42.0);
50  AND_THEN("Check it has the expected string representation") {
51  // this is 42.0 interpreted as a 64-bit integer...
52  REQUIRE(to_str(handle) ==
53  "generic_data_handle{raw=0x4045000000000000 type=double}");
54  }
55  }
56  };
57  auto const check_typeless_null = [&](auto& handle) {
58  check_double_or_typeless_null_handle(handle);
59  THEN("Check it has the expected string representation") {
60  REQUIRE(to_str(handle) == "generic_data_handle{raw=nullptr type=typeless_null}");
61  }
62  THEN("Check it can be converted to data_handle<int>") {
63  REQUIRE_NOTHROW(static_cast<data_handle<int>>(handle));
64  }
65  };
66  GIVEN("A typeless null generic handle") {
68  check_typeless_null(handle);
69  }
70  GIVEN("A typeless null generic handle constructed from nullptr") {
71  generic_data_handle handle{nullptr};
72  check_typeless_null(handle);
73  }
74  GIVEN("A double*-typed null generic handle") {
75  // construct a double*-typed null handle
77  check_double_or_typeless_null_handle(null_handle);
78  THEN("Check it cannot be converted to data_handle<int>") {
79  REQUIRE_THROWS(static_cast<data_handle<int>>(null_handle));
80  }
81  THEN("Check it has the expected string representation") {
82  REQUIRE(to_str(null_handle) == "generic_data_handle{raw=nullptr type=double*}");
83  }
84  }
85  GIVEN("A handle wrapping a raw pointer (compatibility mode)") {
86  auto* const raw_ptr = reinterpret_cast<double*>(0xdeadbeefdeadbeef);
87  data_handle<double> typed_handle{raw_ptr};
88  generic_data_handle handle{typed_handle};
89  THEN("Check it remembered the double type") {
90  REQUIRE(handle.type_name() == "double*");
91  }
92  THEN("Check it can be converted back to data_handle<double>") {
93  REQUIRE_NOTHROW(static_cast<data_handle<double>>(handle));
94  }
95  THEN("Check it cannot be converted to data_handle<int>") {
96  REQUIRE_THROWS(static_cast<data_handle<int>>(handle));
97  }
98  THEN("Check it has the expected string representation") {
99  REQUIRE(to_str(handle) == "generic_data_handle{raw=0xdeadbeefdeadbeef type=double*}");
100  }
101  THEN("Check it does not claim to refer to a modern container") {
102  REQUIRE_FALSE(handle.refers_to_a_modern_data_structure());
103  }
104  THEN("Check we can't get another type out of it") {
105  REQUIRE_THROWS(handle.get<int>());
106  REQUIRE_THROWS(handle.literal_value<int>());
107  }
108  }
109  GIVEN("A generic_handle referring to an entry in an SOA container") {
110  auto& node_data = neuron::model().node_data();
111  REQUIRE(node_data.size() == 0);
112  std::optional<Node::owning_handle> node{node_data};
113  auto typed_handle = node->v_handle();
114  THEN("Match typed_handle as true") {
115  REQUIRE(typed_handle);
116  }
117  generic_data_handle handle{typed_handle};
118  THEN("Check it remembered the double type") {
119  REQUIRE(handle.type_name() == "double*");
120  }
121  THEN("Check it can be converted back to data_handle<double>") {
122  REQUIRE_NOTHROW(static_cast<data_handle<double>>(handle));
123  }
124  THEN("Check it cannot be converted to data_handle<int>") {
125  REQUIRE_THROWS(static_cast<data_handle<int>>(handle));
126  }
127  THEN("Check it has the expected string representation") {
128  REQUIRE(to_str(handle) ==
129  "generic_data_handle{Node::field::Voltage row=0/1 type=double*}");
130  }
131  THEN("Check that it knows it refers to a modern data structure") {
132  REQUIRE(handle.refers_to_a_modern_data_structure());
133  }
134  THEN("Check that we can't get another type out of it") {
135  REQUIRE_THROWS(handle.get<int>());
136  REQUIRE_THROWS(handle.get<double>());
137  }
138  THEN("Check we cannot obtain a literal value") {
139  REQUIRE_THROWS(handle.literal_value<int>());
140  REQUIRE_THROWS(handle.literal_value<double>());
141  }
142  WHEN("The row of the modern data structure is deleted") {
143  node.reset();
144  THEN("Check it still reports referring to a modern data structure") {
145  REQUIRE(handle.refers_to_a_modern_data_structure());
146  }
147  THEN("Check it has the expected string representation") {
148  REQUIRE(to_str(handle) ==
149  "generic_data_handle{Node::field::Voltage died/0 type=double*}");
150  }
151  }
152  }
153 }
static std::string to_str(T const &x)
TEST_CASE("generic_data_handle", "[Neuron][data_structures][generic_data_handle]")
handle_interface< non_owning_identifier< storage > > handle
Non-owning handle to a Mechanism instance.
Model & model()
Access the global Model instance.
Definition: model_data.hpp:206
static Node * node(Object *)
Definition: netcvode.cpp:291
auto v_handle()
Definition: section.h:153
container::Node::storage & node_data()
Access the structure containing the data of all Nodes.
Definition: model_data.hpp:24
Non-template stable handle to a generic value.