Loading...
Searching...
No Matches
Bank.h
1/*
2
3MIT License
4
5Copyright (c) 2017 FMI Open Development / Markus Peura, first.last@fmi.fi
6
7Permission is hereby granted, free of charge, to any person obtaining a copy
8of this software and associated documentation files (the "Software"), to deal
9in the Software without restriction, including without limitation the rights
10to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11copies of the Software, and to permit persons to whom the Software is
12furnished to do so, subject to the following conditions:
13
14The above copyright notice and this permission notice shall be included in all
15copies or substantial portions of the Software.
16
17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23SOFTWARE.
24
25*/
26/*
27Part of Rack development has been done in the BALTRAD projects part-financed
28by the European Union (European Regional Development Fund and European
29Neighbourhood Partnership Instrument, Baltic Sea Region Programme 2007-2013)
30*/
31#ifndef DRAIN_BANK_H_
32#define DRAIN_BANK_H_
33
34//
35#include <drain/Log.h>
36#include <iostream>
37#include <map>
38
39#include <drain/Sprinter.h>
40
41#include "Registry.h"
42#include "Cloner.h"
43#include "Flags.h"
44#include "Static.h"
45
46namespace drain
47{
48
49// NEW
50
51// Container storing entries of different classes derived from T.
63// TODO: remove resolve(key), lower it to superbank, with applying functions; redefine has(), get(), etc.
64template <class T, class K=std::string>
65class Bank : protected std::map<K, ClonerBase<T> *> {
66
67public:
68
70 typedef K key_t;
71
73 typedef T value_t;
74
76 typedef ClonerBase<T> cloner_t;
77
79 typedef std::map<K, cloner_t *> map_t;
80
82 typedef std::set<K> key_set_t;
83
84 struct bank_id {
85 };
86
87 virtual inline
88 ~Bank(){
89 }
90
91 template <class D>
92 static
93 Cloner<T,D> & getCloner(){
94 static Cloner<T,D> & cloner = Static::get<Cloner<T,D>, bank_id>();
95 return cloner;
96 }
97
98
100
107 template <class D>
108 D & add(const K & key){
109 static Cloner<T,D> & cloner = Bank<T,K>::getCloner<D>(); // Static::get<Cloner<T,D>, bank_id>();
110 set(key, cloner);
111 return cloner.src;
112 }
113
114 // Add something that has getName()
115 template <class D>
116 D & add(){
117 static Cloner<T,D> & cloner = Bank<T,K>::getCloner<D>(); // Static::get<Cloner<T,D>, bank_id>();
118 set(cloner.src.getName(), cloner);
119 return cloner.src;
120 }
121
123
131 template <class D>
132 D & addExternal(const D & entry, const K & key){
133 //static Cloner<T,D> & cloner = Static::get<Cloner<T,D>, bank_id>();
134 static drain::Cloner<T,D> cloner(entry);
135 //set(resolve(key), cloner);
136 set(key, cloner);
137 return cloner.src;
138 }
139
141 inline
142 bool has(const K & key) const {
143 return (this->find(resolve(key)) != this->end());
144 }
145
147 inline
148 T & clone(const K & key) const {
149 typename map_t::const_iterator it = this->find(resolve(key));
150 if (it != this->end()){
151 return it->second->getCloned();
152 }
153 else {
154 throw std::runtime_error(resolve(key) + '[' + key + "]: no such entry");
155 }
156 }
157
159 inline
160 const T & get(const K & key) const {
161 typename map_t::const_iterator it = this->find(resolve(key));
162 if (it != this->end()){
163 return it->second->getSource();
164 }
165 else {
166 throw std::runtime_error(resolve(key) + '[' + key + "]: no such entry");
167 }
168 }
169
171 inline
172 T & get(const K & key){
173 typename map_t::iterator it = this->find(resolve(key));
174 if (it != this->end()){
175 return it->second->getSource();
176 }
177 else {
178 throw std::runtime_error(resolve(key) + '[' + key + "]: no such entry");
179 }
180 }
181
183 template <class D>
184 typename map_t::const_iterator get() const {
185 static const cloner_t & cloner = Bank<T,K>::getCloner<D>();
186 for (typename map_t::const_iterator it = this->begin(); it != this->end(); ++it){
187 if (it->second == &cloner)
188 return it;
189 }
190 throw std::runtime_error("find(): no such entry");
191 return this->end();
192 }
193
195 /*
196 * This method is useful if one wants to first set parameters of the
197 * source and the create clones of it.
198 *
199 */
200 inline
201 cloner_t & getCloner(const K & key) const {
202 typename map_t::const_iterator it = this->find(resolve(key));
203 if (it != this->end()){
204 return *(it->second);
205 }
206 else {
207 throw std::runtime_error(key + ": no such entry");
208 }
209 }
210
211 /*
212 template <class D>
213 cloner_t & getCloner() const {
214 static const cloner_t & cloner = Bank<T,K>::getCloner<D>();
215 for (typename map_t::const_iterator it = this->begin(); it != this->end(); ++it){
216 if (it->second == &cloner)
217 return it;
218 }
219 throw std::runtime_error("getCloner(): no such entry");
220 return this->end();
221 }
222 */
223
224 /*
225 inline
226 void clear(const K &key, T *ptr){
227 cloner_t & cloner = getCloner(key);
228 cloner.clear(*ptr);
229 }
230 */
231
233 inline
234 const map_t & getMap() const{
235 return *this;
236 }
237
239
242 // TODO: remove this stupid resolve(key), it works only with K=std::string, and cannot work (easily) with other classes.
243 // lower it to superbank, with applying functions; redefine has(), get(), etc.
244 virtual
245 const std::string & resolve(const K & key) const {
246 return key;
247 }
248
249 void toStream(std::ostream & ostr = std::cout) const {
250 /*
251 Sprinter::sequenceToStream(ostr, getMap(), Sprinter::lineLayout);
252 for (typename map_t::const_iterator it = this->begin(); it != this->end(); ++it) {
253 ostr << it->first << ':' << it->second->getSource() << '\n';
254 }
255 */
256 for (const auto & entry: *this) {
257 ostr << entry.first << ':' << entry.second->getSource() << '\n';
258 }
259
260
261 //std::cout << it->first << ' ' << it->second->getSource() << '\n';
262 }
263
264 inline
265 key_set_t & getKeys(){
266 return keys;
267 }
268
269
270protected:
271
272 key_set_t keys;
273
277 drain::ClonerBase<T> & set(const std::string & key, drain::ClonerBase<T> & cloner){
278
279 const typename map_t::iterator it = this->find(key);
280
281 if (it != this->end()){
282 // Redefined existing (making brief?)
283 if (it->second != &cloner){
284 std::cerr << __FILE__ << " warning: changing cloner source for: " << key << "\n";
285 //throw std::runtime_error(key + ": no such entry");
286 }
287 else {
288 // Re-introduce existing?
289 std::cerr << __FILE__ << " warning: re-defining: " << key << "\n";
290 }
291 it->second = &cloner;
292 }
293 else {
294 // Create new
295 this->operator [](key) = &cloner;
296 keys.insert(key);
297 }
298
299 return cloner;
300
301 }
302
303};
304
305template <class T>
306std::ostream & operator<<(std::ostream & ostr, const Bank<T> & bank) {
307 bank.toStream(ostr);
308 return ostr;
309}
310
312
316template <class T>
317class BankSuper : public Bank<T, std::string> {
318
319public:
320
322 typedef typename bank_t::key_t key_t;
323 typedef typename bank_t::bank_id bank_id;
324
325 typedef T data_t;
326
327 BankSuper(): bank_t() { //, sectionFlags(sections){
328 }
329
330 BankSuper(const BankSuper & bank): bank_t(bank){ //, sectionFlags(sections){
331 std::cerr << __FUNCTION__ << ": copy const" << std::endl;
332 }
333
334
335 // Short (brief) keys needs repeating code or Bank::add()
336 // Note: BankSuper uses same cloner as Bank. Consider leniency.
337 template <class D>
338 D & add(const std::string & key, char brief=0){
339 static Cloner<T,D> & cloner = Static::get<Cloner<T,D>, bank_id>();
340 // static const D & clonerSrc = Static<Cloner<T,D>, bank_id>::getSource().src;
341 if (brief)
342 setBriefKey(brief, key);
343 bank_t::set(key, cloner);
344 return cloner.src;
345 }
346
348 // Short (brief) key needs repeating code or Bank::add()
349 template <class D>
350 D & add(char brief=0){
351 static Cloner<T,D> & cloner = Static::get<Cloner<T,D>, bank_id>();
352 if (brief)
353 setBriefKey(brief, cloner.src.getName());
354 bank_t::set(cloner.src.getName(), cloner);
355 return cloner.src;
356 }
357
358
359 /*
360 template <class D>
361 D & addExternal(D & entry, const std::string & key ){
362 return Bank<T, std::string>::template addExternal<D>(key, entry);
363 }
364 */
365
366 template <class D>
367 D & addExternal(const D & entry, const std::string & key, char brief = 0){
368 if (brief)
369 setBriefKey(brief, key);
370 return Bank<T, std::string>::addExternal(entry, key);
371 //return Bank<T, std::string>::template addExternal<D>(entry, key);
372 }
373
375 /* well, ok
376 template <class D>
377 D & addExternal(D & entry, char brief = 0){
378 std::string key = entry.getName()+"MIKA";
379 if (brief)
380 setBriefKey(brief, key);
381 // TODO: what if the KEY is a single char?
382 return Bank<T, std::string>::template addExternal<D>(key, entry);
383 }
384 */
385
386
387
388 inline
389 void setBriefKey(char brief, const std::string & value){
390 briefKeys.add(brief, value);
391 }
392
393 inline
394 bool hasAlias(const std::string & value) const {
395 if (value.empty())
396 return false;
397 else if (value.length()==1)
398 return hasAlias(value.at(0));
399 else
400 return briefKeys.hasValue(value);
401 }
402
403 inline
404 bool hasAlias(char brief) const {
405 return briefKeys.hasKey(brief);
406 }
407
408 inline
409 char getAlias(const std::string & value) const {
410 if (value.length() > 1)
411 return briefKeys.getKey(value);
412 else if (value.length()==1){
413 // Warn ?
414 char c = value.at(0);
415 if (briefKeys.hasKey(c))
416 return c;
417 }
418 return '\0';
419 }
420
421
422
423 inline
424 const drain::Dictionary<char, key_t> & getAliases() const {
425 return briefKeys;
426 }
427
428
430
433 // TODO: what is the KEY is a single char?
434 virtual inline
435 const std::string & resolve(const key_t & value) const {
436 //std::cout << __FUNCTION__ << ':' << value << '\n';
437 if (value.length() == 1)
438 return briefKeys.getValue(value.at(0));
439 else
440 return value;
441 }
442
443
445 inline
446 void setTitle(const std::string & title){
447 this->title = title;
448 };
449
450
451 FlagResolver::ivalue_t addSection(const FlagResolver::dict_t::key_t & title, const FlagResolver::dict_t::value_t index=0){
452 // Flagger2<int>::value_t addSection(const FlagResolver::dict_t::key_t & title, const FlagResolver::dict_t::value_t index=0){
453 return FlagResolver::addEntry(sections, title, index);
454 }
455
456 /*
457 CommandSection(const std::string & title) : title(title), index(drain::Flagger::getFreeBit(drain::getCommandBank().sections)){
458 std::cerr << __FUNCTION__ << ":installing " << title << '(' << index << ')' << std::endl;
459 drain::getCommandBank().sections.add(title, index);
460 }
461 */
462
463 FlagResolver::dict_t sections;
464
465
466protected:
467
469
471 std::string title;
472
473};
474
475
477// TODO: extend to local bank, creating and destroying several entries.
478template <class B>
480
481public:
482
483 typedef Bank<B> bank_t;
484
485 // Inherit type
486 typedef typename bank_t::cloner_t cloner_t;
487
488 // Inherit type
489 typedef typename cloner_t::entry_t entry_t;
490
491 // Inherit type
492 typedef typename cloner_t::index_t index_t;
493
494 const bank_t & bank;
495
496 typedef std::map<cloner_t *, std::set<index_t> > book_t;
497
498 UniCloner(const bank_t & bank) : bank(bank), idx(0) { // , cloner(nullptr)
499 };
500
501 ~UniCloner(){
502 for (typename book_t::value_type & v : this->book){
503 drain::Logger mout(__FILE__, __FUNCTION__);
504 mout.debug() << "Freeing: ";
505 for (index_t i : v.second){ // << v.first->getSource().getName() not universal
506 //std::cerr << __FILE__ << ':' << __FUNCTION__ << ": dropping " << i << '\n';
507 mout << i << ", ";
508 v.first->drop(i);
509 }
510 mout << mout;
511 }
512 };
513
514 B & getCloned(const typename bank_t::key_t & key){
515
516 cloner_t & cloner = bank.getCloner(key);
517 entry_t entry = cloner.getClonerEntry();
518 idx = entry.first;
519 book[&cloner].insert(entry.first);
520 return *entry.second;
521 //return cloner.cloneUnique();
522 }
523
524 template <class T>
525 B & getCloned(){
526
527 typename bank_t::map_t::const_iterator it = bank.template get<T>();
528 cloner_t *cloner = it->second;
529 entry_t entry = cloner->getClonerEntry();
530 idx = entry.first;
531 book[cloner].insert(entry.first);
532 return *entry.second;
533 //idx = entry.first;
534 //return *(it->second->getCloned());
535 //return cloner.cloneUnique();
536 }
537
538
539 // Returns last index
540
541 inline
542 index_t getIndex() const{
543 return idx;
544 }
545
546
547protected:
548
549 book_t book;
550
551 //cloner_t *cloner;
552 //entry_t entry;
553 index_t idx;
554
555
556};
557
558
559
560
561
562
563
564
565
566// OLD:
567/*
569template <class T>
570class BankOLD : public Registry<ClonerBase<T> > {
571
572public:
573
575 template <class D>
576 void add2(const std::string & key){
577 static drain::Cloner<T,D> cloner;
578 this->add(cloner, key);
579 }
580
581 inline
582 T & clone(const std::string & key) const {
583 // return this->template Registry<ClonerBase<T> >::get(key).clone();
584 return this->Registry<ClonerBase<T> >::get(key).getCloned();
585 }
586
587 inline
588 T & get(const std::string & key){
589 return this->Registry<ClonerBase<T> >::get(key).getSource();
590 //return this->Registry<ClonerBase<T> >::get(key).get();
591 }
592
593
594};
595*/
596
597}
598
599#endif
600
601// Drain
A Bank with additional support for brief, single char keys.
Definition Bank.h:317
virtual const std::string & resolve(const key_t &value) const
Given brief or long key, returns the long key .
Definition Bank.h:435
void setBriefKey(char brief, const std::string &value)
Now, D::getName() is required.
Definition Bank.h:389
void setTitle(const std::string &title)
Set name and brief description of a program, to appear in help dumps.
Definition Bank.h:446
std::string title
For example, name of the program, to appear in help dumps etc.
Definition Bank.h:471
D & add(char brief=0)
Add something that has getName()
Definition Bank.h:350
Definition Bank.h:65
std::map< K, cloner_t * > map_t
Base class.
Definition Bank.h:79
bool has(const K &key) const
Check if a cloner is defined for this key.
Definition Bank.h:142
drain::ClonerBase< T > & set(const std::string &key, drain::ClonerBase< T > &cloner)
Definition Bank.h:277
K key_t
Public key type. (Key type used in the public interface.)
Definition Bank.h:70
map_t::const_iterator get() const
Returns a map entry: pair<Key,D *>()
Definition Bank.h:184
T & get(const K &key)
Returns the base instance.
Definition Bank.h:172
const T & get(const K &key) const
Returns the base instance.
Definition Bank.h:160
T & clone(const K &key) const
Return a copy of the base instance.
Definition Bank.h:148
D & addExternal(const D &entry, const K &key)
Adds class D using a copy constructor on an external instance.
Definition Bank.h:132
D & add(const K &key)
Adds class D as an internal instance.
Definition Bank.h:108
T value_t
Base type of cloned objects.
Definition Bank.h:73
cloner_t & getCloner(const K &key) const
Return the internal static entry.
Definition Bank.h:201
std::set< K > key_set_t
For enumerating keys.
Definition Bank.h:82
virtual const std::string & resolve(const K &key) const
Definition Bank.h:245
Two-way mapping between strings and objects of template class T.
Definition Dictionary.h:63
const K & getKey(const V &value, bool lenient=true) const
Identity mapping useful for type deduction of template arguments in functions.
Definition Dictionary.h:172
const V & getValue(const K &key, bool lenient=true) const
Given a key, return the first value associated with it.
Definition Dictionary.h:149
bool hasValue(const V &value) const
Given a key, return the first value associated with it.
Definition Dictionary.h:143
drain::Dictionary< key_t, ivalue_t > dict_t
"Recommended" dictionary type. All the methods are templates, however.
Definition FlagBase.h:68
static ivalue_t addEntry(drain::Dictionary< key_t, T > &dict, const key_t &key, ivalue_t i=0)
Add a new entry in the dictionary.
LogSourc e is the means for a function or any program segment to "connect" to a Log.
Definition Log.h:312
Logger & debug(const TT &... args)
Debug information.
Definition Log.h:666
Creates an entry of desired type and destroys it upon exit.
Definition Bank.h:479
Definition DataSelector.cpp:1277
Definition Bank.h:84
Definition Cloner.h:46
size_t index_t
Each cloned entry has an index.
Definition Cloner.h:52
Wrapper for derived class S, returning base class T.
Definition Cloner.h:117
S src
Default instance, also the source for cloning.
Definition Cloner.h:274