bump to -rc12
[gnucap-felix.git] / src / l_dispatcher.h
blobed835d2058a37c6edf35d07948f157a555db337c
1 /*$Id: l_dispatcher.h 2016/03/29 al -*- C++ -*-
2 * Copyright (C) 2006 Albert Davis
3 * Author: Albert Davis <aldavis@gnu.org>
5 * This file is part of "Gnucap", the Gnu Circuit Analysis Package
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3, or (at your option)
10 * any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 * 02110-1301, USA.
21 *------------------------------------------------------------------
22 * dispatcher -- for dynamically loaded modules
24 //testing=script 2015.01.21
25 #ifndef L_DISPATCHER_H
26 #define L_DISPATCHER_H
27 #include "e_base.h"
28 #include "l_stlextra.h"
29 #include "u_opt.h"
30 #include "ap.h"
31 /*--------------------------------------------------------------------------*/
32 class DISPATCHER_BASE {
33 protected:
34 std::map<std::string, CKT_BASE*> * _map;
35 private:
36 explicit DISPATCHER_BASE(DISPATCHER_BASE*) {unreachable();incomplete();}
37 public:
38 DISPATCHER_BASE() /*: _map(new std::map<std::string, CKT_BASE*>)*/ {
39 if (!_map) {
40 _map = new std::map<std::string, CKT_BASE*>;
41 }else{unreachable();
42 fprintf(stderr, "build error: link order: constructing dispatcher that already has contents\n");
45 ~DISPATCHER_BASE() {
46 #if !defined(NDEBUG)
47 for (typename std::map<std::string, CKT_BASE*>::iterator
48 ii = _map->begin();
49 ii != _map->end();
50 ++ii) {
51 if(ii->second){
52 std::cerr << ii->second->long_label() << "\n";
53 unreachable();
56 #endif
57 delete _map;
58 _map = NULL;
61 typedef typename std::map<std::string, CKT_BASE*>::const_iterator const_iterator;
62 //class const_iterator : public std::map<std::string, CKT_BASE*>::const_iterator {};
64 const_iterator begin()const {assert(_map); return _map->begin();}
65 const_iterator end()const {assert(_map); return _map->end();}
67 CKT_BASE* operator[](std::string s) {
68 assert(_map);
69 CKT_BASE* rv = (*_map)[s];
70 if (!rv && OPT::case_insensitive) {
71 notstd::to_lower(&s);
72 rv = (*_map)[s];
73 }else{
75 return rv;
78 /*--------------------------------------------------------------------------*/
79 template <class TT>
80 class INTERFACE DISPATCHER : public DISPATCHER_BASE {
81 public:
82 void install(const std::string& s, TT* p) {
83 assert(s.find(',', 0) == std::string::npos);
84 if (!_map) {unreachable();
85 puts("build error: link order: dispatcher not yet constructed\n");
86 _map = new std::map<std::string, CKT_BASE*>;
87 }else{
89 trace1("DISPATCHER ", s);
90 // loop over all keys, separated by '|'
91 for (std::string::size_type // bss: begin sub-string
92 bss = 0, ess = s.find('|', bss); // ess: end sub-string
93 bss != std::string::npos;
94 bss = (ess != std::string::npos) ? ess+1 : std::string::npos,
95 ess = s.find('|', bss)) {
96 std::string name = s.substr(bss,
97 (ess != std::string::npos) ? ess-bss : std::string::npos);
98 trace2(name.c_str(), bss, ess);
99 if (name == "") {
100 // quietly ignore empty string
101 }else if ((*_map)[name]) {
102 // duplicate .. stash the old one so we can get it back
103 error(bWARNING, name + ": already installed, replacing\n");
104 std::string save_name = name + ":0";
105 for (int ii = 0; (*_map)[save_name]; ++ii) {
106 save_name = name + ":" + ::to_string(ii);
108 (*_map)[save_name] = (*_map)[name];
109 error(bWARNING, "stashing as " + save_name + "\n");
110 }else{
111 // it's new, just put it in
113 (*_map)[name] = p;
117 void uninstall(TT* p) {
118 assert(_map);
119 for (typename std::map<std::string, CKT_BASE*>::iterator
120 ii = _map->begin();
121 ii != _map->end();
122 ++ii) {
123 if (ii->second == p) {
124 ii->second = NULL;
125 }else{
128 #if !defined(NDEBUG)
129 for (typename std::map<std::string, CKT_BASE*>::iterator
130 ii = _map->begin();
131 ii != _map->end();
132 ++ii) {
133 assert(ii->second != p);
135 #endif
138 void uninstall(const std::string& s) {untested();
139 assert(_map);
140 // loop over all keys, separated by '|'
141 for (std::string::size_type // bss: begin sub-string
142 bss = 0, ess = s.find('|', bss); // ess: end sub-string
143 bss != std::string::npos;
144 bss = (ess != std::string::npos) ? ess+1 : std::string::npos,
145 ess = s.find('|', bss)) {untested();
146 std::string name = s.substr(bss,
147 (ess != std::string::npos) ? ess-bss : std::string::npos);
148 if (name == "") {untested();
149 // quietly ignore empty string
150 }else if ((*_map)[name]) {untested();
151 // delete, try to get back the old one
152 int ii = 0;
153 std::string save_name = name + ":0";
154 for (ii = 0; (*_map)[save_name]; ++ii) {
155 save_name = name + ":" + ::to_string(ii);
157 if (ii > 1) {
158 save_name = name + ":" + ::to_string(ii-2);
159 (*_map)[name] = (*_map)[save_name];
160 (*_map)[save_name] = NULL;
161 error(bWARNING, "restoring " + save_name + " as " + name + "\n");
162 }else{untested();
163 (*_map)[name] = NULL;
165 }else{untested();
166 error(bWARNING, name + ": not installed, doing nothing\n");
171 TT* operator[](std::string s) {
172 assert(_map);
173 CKT_BASE* rv = (*_map)[s];
174 if (!rv && OPT::case_insensitive) {
175 notstd::to_lower(&s);
176 rv = (*_map)[s];
177 }else{
179 return prechecked_cast<TT*>(rv);
182 TT* operator[](CS& cmd) {
183 unsigned here = cmd.cursor();
184 std::string s;
185 cmd >> s;
186 //------------------------
187 TT* p = (*this)[s];
188 //------------------------
189 if (!p) {
190 cmd.reset(here);
191 }else{
193 return p;
196 TT* clone(std::string s) {
197 TT* proto = (*this)[s];
198 if (proto) {
199 return proto->clone();
200 }else{untested();
201 return NULL;
205 class INSTALL {
206 private:
207 const std::string _name;
208 DISPATCHER<TT>* _d;
209 TT* _p;
210 public:
211 INSTALL(DISPATCHER<TT>* d, const std::string& name, TT* p) :
212 _name(name),
213 _d(d),
214 _p(p)
216 trace1("INSTALL ", _name);
217 assert(_d);
218 assert(p);
219 _d->install(_name, p);
222 ~INSTALL() {
223 //_d->uninstall(_name);
224 _d->uninstall(_p);
228 /*--------------------------------------------------------------------------*/
229 /*--------------------------------------------------------------------------*/
230 #endif
231 // vim:ts=8:sw=2:noet: