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