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