NEURON
pysecname2sec.cpp
Go to the documentation of this file.
1 #include <../../nrnconf.h>
2 
3 #include <stdio.h>
4 #include <hocparse.h>
5 
6 #include <parse.hpp>
7 
8 #include <nrnoc2iv.h>
9 
10 #include "nrnsymdiritem.h"
11 #include "utils/enumerate.h"
12 
13 #include <string>
14 #include <map>
15 
16 static bool activated = false; // true on first use of hoc __pysec.
17 
19 typedef std::pair<CorStype, void*> CellorSec;
20 typedef std::map<const std::string, CellorSec> Name2CellorSec;
22 
23 #define hoc_acterror(a, b) printf("%s %s\n", a, b)
24 
25 static void activate() {
26 #if USE_PYTHON
27  if (!activated) {
28  // printf("first activation\n");
29  activated = true;
30  hoc_Item* qsec;
31  // ForAllSections(sec)
32  ITERATE(qsec, section_list) {
33  Section* sec = hocSEC(qsec);
34  if (sec->prop && sec->prop->dparam[PROP_PY_INDEX].get<void*>()) {
36  }
37  }
38  }
39 #endif
40 }
41 
42 Section* nrnpy_pysecname2sec(const char* name) { // could be Cell part or Sec
43  activate();
44  std::string n(name);
45  if (nrn_parsing_pysec_ == (void*) 1) {
46  Name2CellorSec::iterator search = n2cs.find(n);
47  if (search != n2cs.end()) {
48  if (search->second.first == SECTYPE) {
49  nrn_parsing_pysec_ = NULL; /* done */
50  return (Section*) search->second.second;
51  } else if (search->second.first == CELLTYPE) {
52  nrn_parsing_pysec_ = search->second.second;
53  } else if (search->second.first == OVERLOADCOUNT) {
56  name,
57  " is an overloaded first part name for multiple sections created in python");
58  }
59  } else {
61  hoc_acterror(name, " is not a valid first part name for section created in python");
62  }
63  } else {
65  Name2CellorSec::iterator search = n2s->find(n);
66  if (search != n2s->end()) {
67  if (search->second.first == OVERLOADCOUNT) {
70  name,
71  " is an overloaded second part name for multiple sections created in python");
72  }
73  nrn_parsing_pysec_ = NULL; /* done */
74  assert(search->second.first == SECTYPE);
75  return (Section*) search->second.second;
76  } else {
78  hoc_acterror(name, " is not a valid last part name for section created in python");
79  }
80  }
81  return NULL;
82 }
83 
84 // Want to add a Section to a cell but one may already be there or
85 // already be overloaded.
86 static void n2s_add(Name2CellorSec& n2s, std::string n, Section* sec) {
87  Name2CellorSec::iterator search = n2s.find(n);
88  if (search == n2s.end()) {
89  n2s[n] = CellorSec(SECTYPE, sec);
90  } else {
91  CellorSec& cs = search->second;
92  if (cs.first == SECTYPE) {
93  cs.first = OVERLOADCOUNT;
94  cs.second = (void*) 2;
95  } else if (cs.first == OVERLOADCOUNT) {
96  cs.second = (void*) ((size_t) cs.second + 1);
97  }
98  }
99 }
100 
101 // Want to add a Section to top level but name may already exist. If so
102 // already a Section -- overload 2
103 // already overloaded section -- overload increase by 1
104 // already a cell -- no longer usable, becomes NONETYPE
105 // already NONETYPE -- nothing to do
106 static void n2cs_add_sec(Name2CellorSec& n2cs, std::string sname, Section* sec) {
107  // printf("n2cs_add_sec %s section=%p\n", sname.c_str(), sec);
108  Name2CellorSec::iterator search = n2cs.find(sname);
109  if (search == n2cs.end()) {
110  n2cs[sname] = CellorSec(SECTYPE, sec);
111  } else {
112  CellorSec& cs = search->second;
113  if (cs.first == CELLTYPE) { // conflict so destroy
114  Name2CellorSec* n2s = (Name2CellorSec*) cs.second;
115  delete n2s;
116  cs.first = NONETYPE;
117  cs.second = NULL;
118  } else if (cs.first == SECTYPE) { // overload
119  cs.first = OVERLOADCOUNT;
120  cs.second = (void*) 2;
121  } else if (cs.first == OVERLOADCOUNT) { // increase overload
122  cs.second = (void*) ((size_t) cs.second + 1);
123  }
124  }
125 }
126 
127 // Want to add a Cell to top level but name may already exist. If so
128 // already a Cell -- nothing to do
129 // already a overloaded section or section -- no longer usable, becomes NONETYPE
130 // already NONETYPE -- nothing to do
131 static Name2CellorSec* n2cs_add_cell(Name2CellorSec& n2cs, std::string cname) {
132  Name2CellorSec::iterator search = n2cs.find(cname);
133  Name2CellorSec* n2s = NULL; // not usable if it stays NULL
134  if (search == n2cs.end()) { // not found add cname, Name2Section*
135  n2s = new Name2CellorSec();
136  n2cs[cname] = CellorSec(CELLTYPE, n2s);
137  } else {
138  CellorSec& cs = search->second;
139  if (cs.first == SECTYPE || cs.first == OVERLOADCOUNT) { // conflict so destroy
140  cs.first = NONETYPE;
141  cs.second = NULL;
142  } else if (cs.first == CELLTYPE) { // exists, ready to use.
143  n2s = (Name2CellorSec*) cs.second;
144  }
145  }
146  return n2s;
147 }
148 
149 void n2cs_add(Name2CellorSec& n2cs, std::string cname, std::string sname, Section* sec) {
150  Name2CellorSec* n2s = n2cs_add_cell(n2cs, cname);
151  // printf("n2cs_add %s %s n2s=%p section=%p\n", cname.c_str(), sname.c_str(), n2s, sec);
152  if (n2s) {
153  n2s_add(*n2s, sname, sec);
154  }
155 }
156 
158  if (!activated) {
159  return;
160  }
161  std::string n(secname(sec));
162  if (n.find("__nrnsec_0x", 0) == 0) {
163  return;
164  }
165  if (n.find("<", 0) != n.npos) {
166  return;
167  }
168  // printf("nrnpy_pysecname2sec_add %s\n", secname(sec));
169  size_t dot = n.find('.', 1);
170  if (dot != n.npos) { // cell.sec
171  std::string cname = n.substr(0, dot);
172  std::string sname = n.substr(dot + 1);
173  n2cs_add(n2cs, cname, sname, sec);
174  } else { // sec
175  n2cs_add_sec(n2cs, n, sec);
176  }
177 }
178 
179 static bool decrement(CellorSec& cs) {
180  cs.second = (void*) ((size_t) cs.second - 1);
181  return cs.second ? false : true;
182 }
183 
185  if (!activated) {
186  return;
187  }
188  std::string name(secname(sec));
189  // printf("remove %s\n", name.c_str());
190  if (name[0] == '<') {
191  return;
192  }
193 
194  size_t dot = name.find('.', 1);
195  if (dot != name.npos) { // cell.sec
196  std::string cname = name.substr(0, dot);
197  std::string sname = name.substr(dot + 1);
198  Name2CellorSec::iterator it = n2cs.find(cname);
199  assert(it != n2cs.end());
200  // must be CELLTYPE or NONETYPE
201  CellorSec& cs = it->second;
202  if (cs.first == CELLTYPE) {
203  Name2CellorSec* n2s = (Name2CellorSec*) cs.second;
204  Name2CellorSec::iterator its = n2s->find(sname);
205  assert(its != n2s->end());
206  // must be SECTYPE or OVERLOADCOUNT
207  CellorSec& css = its->second;
208  if (css.first == SECTYPE) {
209  n2s->erase(its);
210  if (n2s->empty()) {
211  delete n2s;
212  n2cs.erase(it);
213  }
214  } else {
215  assert(css.first == OVERLOADCOUNT);
216  if (decrement(css)) {
217  n2s->erase(its);
218  if (n2s->empty()) {
219  delete n2s;
220  n2cs.erase(it);
221  }
222  }
223  }
224  } else {
225  assert(cs.first == NONETYPE);
226  }
227  } else { // sec
228  Name2CellorSec::iterator it = n2cs.find(name);
229  assert(it != n2cs.end());
230  // must be SECTYPE, NONETYPE, or OVERLOADCOUNT
231  CellorSec& cs = it->second;
232  if (cs.first == SECTYPE) {
233  n2cs.erase(it);
234  } else if (cs.first == OVERLOADCOUNT) {
235  if (decrement(cs)) {
236  n2cs.erase(it);
237  }
238  } else {
239  assert(cs.first == NONETYPE);
240  }
241  }
242 #if 0
243  if (n2cs.empty()) {
244  printf("pysecname2sec is empty\n");
245  }
246 #endif
247 }
248 
249 void nrn_symdir_load_pysec(std::vector<SymbolItem*>& sl, void* v) {
250  activate();
251  if (!v) {
252  // top level items are any of the four types
253  for (auto&& [symbol, cs]: n2cs) {
254  if (cs.first != NONETYPE && cs.first != OVERLOADCOUNT) {
255  SymbolItem* si = new SymbolItem(symbol.c_str(), 0);
256  si->pysec_type_ = cs.first == CELLTYPE ? PYSECOBJ : PYSECNAME;
257  si->pysec_ = (Section*) cs.second;
258  sl.push_back(si);
259  }
260  }
261  } else {
262  // in cell items are either OVERLOADCOUNT or SECTYPE
263  for (auto&& [symbol, cs]: *static_cast<Name2CellorSec*>(v)) {
264  if (cs.first == SECTYPE) {
265  auto* si = new SymbolItem(symbol.c_str(), 0);
266  si->pysec_type_ = PYSECNAME;
267  si->pysec_ = (Section*) cs.second;
268  sl.push_back(si);
269  }
270  }
271  }
272 }
const char * secname(Section *sec)
name of section (for use in error messages)
Definition: cabcode.cpp:1674
void * pysec_
Definition: nrnsymdiritem.h:27
#define v
Definition: md1redef.h:11
#define sec
Definition: md1redef.h:20
void * nrn_parsing_pysec_
#define assert(ex)
Definition: hocassrt.h:24
#define hocSEC(q)
Definition: hoclist.h:87
#define ITERATE(itm, lst)
Definition: model.h:18
printf
Definition: extdef.h:5
const char * name
Definition: init.cpp:16
double dot(const Point3D &p1, const Point3D &p2)
Definition: lfp.hpp:18
int const size_t const size_t n
Definition: nrngsl.h:10
hoc_List * section_list
Definition: init.cpp:113
static void n2cs_add_sec(Name2CellorSec &n2cs, std::string sname, Section *sec)
void n2cs_add(Name2CellorSec &n2cs, std::string cname, std::string sname, Section *sec)
static Name2CellorSec n2cs
static void activate()
std::pair< CorStype, void * > CellorSec
static bool activated
void nrnpy_pysecname2sec_add(Section *sec)
Section * nrnpy_pysecname2sec(const char *name)
CorStype
@ CELLTYPE
@ NONETYPE
@ SECTYPE
@ OVERLOADCOUNT
std::map< const std::string, CellorSec > Name2CellorSec
static void n2s_add(Name2CellorSec &n2s, std::string n, Section *sec)
static Name2CellorSec * n2cs_add_cell(Name2CellorSec &n2cs, std::string cname)
static bool decrement(CellorSec &cs)
void nrn_symdir_load_pysec(std::vector< SymbolItem * > &sl, void *v)
#define hoc_acterror(a, b)
void nrnpy_pysecname2sec_remove(Section *sec)
#define PROP_PY_INDEX
Definition: section.h:230
#define NULL
Definition: spdefs.h:105