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