Loading...
Searching...
No Matches
FlagBase.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
32#ifndef DRAIN_FLAG_BASE
33#define DRAIN_FLAG_BASE
34
35#include <iostream>
36#include <list>
37#include <iterator>
38#include <iostream>
39#include <list>
40#include <sstream>
41#include <stdexcept>
42#include <typeinfo>
43
44#include <drain/Log.h>
45#include <drain/StringTools.h>
46#include <drain/Dictionary.h>
47#include <drain/TypeName.h>
48
49namespace drain {
50
52
57
58public:
59
60 // Definite
61 typedef std::string key_t;
62
63 // "Recommended" storage type for both numeric and enumerated-type flags.
64 typedef unsigned long int ivalue_t;
65
68
69 static
70 const ivalue_t ALL; // = std::numeric_limits<FlagResolver::ivalue_t>::max();
71
72
74
79 // Consider: lenient: if true, bypasses unknown keys silently, otherwise throws exception
80 // Consider: FLAG for keys only, and for numerics throw exception
81 template <typename T>
82 static
83 ivalue_t getIntValue(const drain::Dictionary<key_t,T> & dict, const std::string & keys, char separator=',');
84
86 template <typename T>
87 static
88 std::string getKeys(const drain::Dictionary<key_t,T> & dict, ivalue_t, char separator=',');
89
91 template <typename T>
92 static
93 std::ostream & keysToStream(const drain::Dictionary<key_t,T> &dict, ivalue_t value, std::ostream & ostr, char separator=',');
94
96
101 template <typename T, typename V>
102 static
103 void valuesToList(ivalue_t value, const drain::Dictionary<key_t,T> &dict, std::list<V> & container);
104
106
109 template <typename T>
110 static
111 ivalue_t addEntry(drain::Dictionary<key_t,T> & dict, const key_t & key, ivalue_t i=0);
112
113
115
118 template <typename T>
119 static
120 ivalue_t getFreeBit(const drain::Dictionary<key_t,T> & dict);
121
122
123};
124
125
126template <typename T>
127typename FlagResolver::ivalue_t FlagResolver::getFreeBit(const drain::Dictionary<key_t,T> & dict){
128
129 drain::Logger mout(__FILE__, __FUNCTION__);
130
131 // Bit mask containing all the values.
132 ivalue_t currentMask = 0;
133 for (const auto & entry: dict){
134 currentMask = currentMask | entry.second;
135 }
136
137 mout.debug2("sum:" , currentMask );
138
139 ivalue_t i = 1;
140 while ((i&currentMask) > 0){
141 mout.debug3("checking bit:" , i , " vs.\t" , currentMask );
142 //full = (full>>1);
143 i = (i<<1);
144 }
145 /*
146 while (full>0){
147 mout.debug2("checking bit:" , i , " vs.\t" , full );
148 full = (full>>1);
149 i = (i<<1);
150 }
151 */
152
153 mout.debug("released: " , i );
154
155 return i;
156
157}
158
159/*
160template <typename T>
161typename FlagResolver::ivalue_t FlagResolver::addEntry(drain::Dictionary<key_t,T> &dict, const typename dict_t::key_t & key){
162
163 drain::Logger mout(__FILE__, __FUNCTION__);
164 if (dict.hasKey(key)){
165 mout.info(key , " already in dict: " , dict );
166 return dict.getValue(key);
167 }
168
169 return addEntry(dict, key, )
170}
171*/
172
173template <typename T>
174typename FlagResolver::ivalue_t FlagResolver::addEntry(drain::Dictionary<key_t,T> &dict, const typename dict_t::key_t & key, ivalue_t i){
175
176 drain::Logger mout(__FILE__, __FUNCTION__);
177
178 if (dict.hasKey(key)){
179 mout.info(key , " already in dict: " , dict );
180 return dict.getValue(key);
181 }
182
183 if (i==0)
184 i = getFreeBit(dict);
185
186 if (i>0){
187 dict.add(key, i);
188 }
189 else {
190 mout.warn(key , " could not get a valid (non-zero) bit flag for dict: " , dict );
191 }
192
193 return i;
194};
195
196
197template <typename T>
198typename FlagResolver::ivalue_t FlagResolver::getIntValue(const drain::Dictionary<key_t,T> & dict, const std::string & args, char separator){
199
200 drain::Logger mout(__FILE__, __FUNCTION__);
201
202 FlagResolver::ivalue_t v = 0;
203
204 std::list<key_t> keys;
205
206 if (!separator){
207 separator = dict.separator;
208 }
209
210 if (separator){
211 //drain::
212 // StringTools foo;
213 StringTools::split(args, keys, separator);
214 }
215
216
217 for (const key_t & key: keys){
218
219 if (key == ""){
220 continue;
221 }
222 else if (key == "0"){
223 v = 0; // TODO if resets and sets?
224 continue;
225 }
226 // mout.warn(" '" , *it , "'" );
227
228 //typename dict_t::const_iterator dit = dict.findByKey(key);
229 typename drain::Dictionary<key_t,T>::const_iterator dit = dict.findByKey(key);
230
231 if (dit != dict.end()){ // String key match,
232 // Numeric value for an alphabetic key was found
233 v = (v | static_cast<FlagResolver::ivalue_t>(dit->second) );
234 }
235 else {
236 // Numeric value
237 FlagResolver::ivalue_t x = 0;
238 std::stringstream sstr(key);
239 sstr >> x; // FIX if empty
240 if (x == 0){
241 // String "0" handled already above
242 // Consider: could advice keys only: sprinter(dict.getKeys()
243 // Or key-value pairs: sprinter(dict)
244 // static const SprinterLayout cmdArgLayout = {",", "?", "=", ""};
245 // mout.error("key '", key, "' not found in: ", sprinter(dict, Sprinter::cmdLineLayout));
246 // mout.error("key '", key, "' not föund in: ", sprinter(dict.getContainer(), cmdArgLayout) );
247 mout.error("key '", key, "' not found in: ", dict);
248 //throw std::runtime_error(key, ": key not found in Flags, dict: ", dict);
249 }
250 v = v | x;
251 // Nice to know
252 /*
253 dict_t::const_iterator vit = dictionaryRef.findByValue(v);
254 if (vit != dictionaryRef.end()){
255 std::cout << "(assigned key '" << vit->second << "')\n"; // or vit->first?
256 }
257 */
258 }
259 }
260
261 return v;
262}
263
264
266template <typename T>
267std::string FlagResolver::getKeys(const drain::Dictionary<key_t,T> &dict, ivalue_t v, char separator){
268 std::stringstream sstr;
269 keysToStream(dict, v, sstr, separator);
270 return sstr.str();
271}
272
273
274
275//
276
278template <typename T>
279std::ostream & FlagResolver::keysToStream(const drain::Dictionary<FlagResolver::key_t,T> &dict, ivalue_t value, std::ostream & ostr, char separator) {
280
281 /* note: instead of shifting bits of this->value, traverses the dictionary which can contain
282 - combined values
283 - repeated values (aliases)
284 */
285
286 if (!separator)
287 separator = dict.separator;
288
289 char sep = 0;
290
291 for (const auto & entry: dict){
292 const ivalue_t v = (entry.second); // static_cast<ivalue_t>
293 //if ((entry.second > 0) && ((entry.second & value) == entry.second)){ // fully covered in value
294 //if ((entry.second == 0) && ((entry.second & value) == entry.second)){ // fully covered in value
295 if ((v > 0) && ((v & value) == v)){ // fully covered in value
296 if (sep)
297 ostr << sep;// "{" << (int)(sep) << "}" <<
298 else
299 sep = separator;
300 ostr << entry.first;
301 }
302 else {
303
304 }
305 }
306
307 return ostr;
308}
309
310
311
312
313template <typename T, typename V>
314void FlagResolver::valuesToList(ivalue_t value, const drain::Dictionary<key_t,T> &dict, std::list<V> & container){
315 for (const auto & entry: dict){
316 if ((entry.second > 0) && ((entry.second & value) == entry.second)){ // fully covered in value
317 // ostr << entry.first;
318 container.push_back(static_cast<V>(entry.second));
319 // container.push_back(entry.first);
320 }
321 }
322}
323
324
325
326// NEW 2022/2023
327
328
329// typedef drain::Dictionary<std::string,unsigned long> FlaggerDict;
330
331// #define FlaggerDict FlagResolver::dict_t
332
361template <typename E=std::size_t, typename T=E> //, typename D=drain::Dictionary<std::string,unsigned long> >
363
364public:
365
366 //static
367 //const SprinterLayout dictLayout = {",", "?", "=", ""};
368
369 // Manifested numeric type (enum or unsigned integer)
370 typedef E value_t;
371 typedef T storage_t;
373 typedef typename dict_t::key_t key_t; // ~string
374
375 // Practical "storage" value
376 // typedef typename dict_t::value_t dict_value_t; // TODO: xould be same as value_t ?
377
378 // Rember to add an initialized unit: template<> SingleFlagger<...>::dict = {{...,...}, ...}
379 // static const dict_t dict;
380
381protected:
382 // Default constructor. Local value \c ownValue will be used.
386 inline
387 FlaggerBase(char separator=','): value(ownValue), separator(','), ownValue((storage_t)0){ // drain::NEUTRAL VALUE!
388 }
389
391
395 inline
396 FlaggerBase(storage_t & v, char separator=','): value(v), separator(','){
397 }
398
399 /* Risky? (Ambiguous)
400 inline
401 FlaggerBase(const dict_value_t & v): value(ownValue), ownValue(v) {
402 }
403 */
404
405 virtual inline
406 ~FlaggerBase(){
407 }
408
409public:
410
412
417 virtual
418 const dict_t & getDict() const = 0;
419
420 virtual inline
421 void reset(){
422 this->value = storage_t(0); // ALERT! enums need neutral value.
423 };
424
425
427
431 virtual
432 bool isSet(const storage_t & x) const = 0;
433
434
435 inline
436 bool isSet(const key_t & key) const {
437 return isSet(getDict().getValue(key));
438 };
439
440 inline
441 const storage_t & getValue() const {
442 return value;
443 }
444
445
447 inline
448 operator const storage_t & () const { // should be ivalue ?
449 return this->value;
450 }
451
452 inline
453 operator storage_t & () { // should be ivalue ?
454 return this->value;
455 }
456
457 inline
458 operator bool() const {
459 return static_cast<FlagResolver::ivalue_t>(this->value) != 0;
460 }
461
462
464 virtual
465 const key_t & str() const = 0;
466
467 // String
468 operator const key_t & () const {
469 return str();
470 }
471
472 // Own or external value.
473 storage_t & value;
474
475 char separator;
476
477 void debug(std::ostream & ostr) const;
478
479 /* these apply to SingleFlaggers */
480 /*
482 virtual inline
483 void set(const key_t & key){
484 if (key.empty())
485 return; // needed?
486 assign(key); // potential problem: assign assumes string arg
487 }
488
490 virtual inline
491 void set(const value_t & value){
492 this->value = value;
493 };
494
495 virtual inline
496 void set(const FlaggerBase<E> & flagger){
497 this->value = flagger.value;
498 }
499 */
500
501protected:
502
503private:
504
505 // protect?
506 virtual
507 void assign(const std::string & s) = 0;
508
509
510 // Own value, discarded if external value referenced.
511 storage_t ownValue = 0; // NEUTRAL
512
513};
514
515
516template <typename E,typename T>
517void drain::FlaggerBase<E,T>::debug(std::ostream & ostr) const {
518 //ostr << typeid(drain::FlaggerBase<E>).name() << ": value=" << getValue() << ", ";
519 ostr << drain::TypeName<E>::str() << ": value=" << getValue() << ", ";
520 FlagResolver::keysToStream(getDict(), getValue(), ostr) << ", ";
521 ostr << " dict: " << getDict();
522}
523
524template <typename E,typename T>
525inline
526std::ostream & operator<<(std::ostream & ostr, const drain::FlaggerBase<E,T> & flagger) {
527 return ostr << flagger.str(); // flags.keysToStream(ostr);
528}
529
530/*
531template <typename E>
532const SprinterLayout drain::FlaggerBase<E>::dictLayout = {",", "?", "=", ""};
533*/
534
535
536
537
538} // drain::
539
540
541#endif
Two-way mapping between strings and objects of template class T.
Definition Dictionary.h:63
const V & getValue(const K &key, bool lenient=true) const
Given a key, return the first value associated with it.
Definition Dictionary.h:149
Referencing a dictionary of binary values: {"A",1: "B":2, "C": 4, "D": 8, ...} resolves two-way mappi...
Definition FlagBase.h:56
static ivalue_t getIntValue(const drain::Dictionary< key_t, T > &dict, const std::string &keys, char separator=',')
Computes bitwise OR function on the numeric or alphabetic value(s) presented by a string.
Definition FlagBase.h:198
drain::Dictionary< key_t, ivalue_t > dict_t
"Recommended" dictionary type. All the methods are templates, however.
Definition FlagBase.h:67
static std::ostream & keysToStream(const drain::Dictionary< key_t, T > &dict, ivalue_t value, std::ostream &ostr, char separator=',')
Write keys in a stream, in numeric order.
Definition FlagBase.h:279
static void valuesToList(ivalue_t value, const drain::Dictionary< key_t, T > &dict, std::list< V > &container)
Given a bit vector (integer value), extracts separate flag values to a list.
Definition FlagBase.h:314
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.
static ivalue_t getFreeBit(const drain::Dictionary< key_t, T > &dict)
Return an interger (bit vector) with a new, previously unused value.
Definition FlagBase.h:127
static std::string getKeys(const drain::Dictionary< key_t, T > &dict, ivalue_t, char separator=',')
Given an integer, retrieves dictionary keys corresponding to each index of set bits.
Definition FlagBase.h:267
Definition FlagBase.h:362
virtual bool isSet(const storage_t &x) const =0
Checks if a given bit, or any of given bits, is set.
virtual const key_t & str() const =0
String corresponding the current value. Returns empty, if not found.
virtual const dict_t & getDict() const =0
Returns the static dictionary created for this value_t .
FlaggerBase(storage_t &v, char separator=',')
Value-referencing constructor.
Definition FlagBase.h:396
LogSourc e is the means for a function or any program segment to "connect" to a Log.
Definition Log.h:313
Logger & debug(const TT &... args)
Debug information.
Definition Log.h:667
Logger & error(const TT &... args)
Echoes.
Definition Log.h:417
Logger & debug2(const TT &... args)
Debug information.
Definition Log.h:677
static void split(const std::string &s, T &sequence, const C &separators, const std::string &trimChars=" \t\n")
Splits and trims a given std::string to a std Sequence.
Definition StringTools.h:487
Definition DataSelector.cpp:1277