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/String.h>
46#include <drain/Type.h>
47
48#include "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::StringTools::split(args, keys, separator);
213 }
214
215
216 for (const key_t & key: keys){
217
218 if (key == ""){
219 continue;
220 }
221 else if (key == "0"){
222 v = 0; // TODO if resets and sets?
223 continue;
224 }
225 // mout.warn(" '" , *it , "'" );
226
227 //typename dict_t::const_iterator dit = dict.findByKey(key);
228 typename drain::Dictionary<key_t,T>::const_iterator dit = dict.findByKey(key);
229
230 if (dit != dict.end()){ // String key match,
231 // Numeric value for an alphabetic key was found
232 v = (v | static_cast<FlagResolver::ivalue_t>(dit->second) );
233 }
234 else {
235 // Numeric value
236 FlagResolver::ivalue_t x = 0;
237 std::stringstream sstr(key);
238 sstr >> x; // FIX if empty
239 if (x == 0){
240 // String "0" handled already above
241 // Consider: could advice keys only: sprinter(dict.getKeys()
242 // Or key-value pairs: sprinter(dict)
243 // static const SprinterLayout cmdArgLayout = {",", "?", "=", ""};
244 // mout.error("key '", key, "' not found in: ", sprinter(dict, Sprinter::cmdLineLayout));
245 // mout.error("key '", key, "' not föund in: ", sprinter(dict.getContainer(), cmdArgLayout) );
246 mout.error("key '", key, "' not found in: ", dict);
247 //throw std::runtime_error(key, ": key not found in Flags, dict: ", dict);
248 }
249 v = v | x;
250 // Nice to know
251 /*
252 dict_t::const_iterator vit = dictionaryRef.findByValue(v);
253 if (vit != dictionaryRef.end()){
254 std::cout << "(assigned key '" << vit->second << "')\n"; // or vit->first?
255 }
256 */
257 }
258 }
259
260 return v;
261}
262
263
265template <typename T>
266std::string FlagResolver::getKeys(const drain::Dictionary<key_t,T> &dict, ivalue_t v, char separator){
267 std::stringstream sstr;
268 keysToStream(dict, v, sstr, separator);
269 return sstr.str();
270}
271
272
273
274//
275
277template <typename T>
278std::ostream & FlagResolver::keysToStream(const drain::Dictionary<FlagResolver::key_t,T> &dict, ivalue_t value, std::ostream & ostr, char separator) {
279
280 /* note: instead of shifting bits of this->value, traverses the dictionary which can contain
281 - combined values
282 - repeated values (aliases)
283 */
284
285 if (!separator)
286 separator = dict.separator;
287
288 char sep = 0;
289
290 for (const auto & entry: dict){
291 const ivalue_t v = (entry.second); // static_cast<ivalue_t>
292 //if ((entry.second > 0) && ((entry.second & value) == entry.second)){ // fully covered in value
293 //if ((entry.second == 0) && ((entry.second & value) == entry.second)){ // fully covered in value
294 if ((v > 0) && ((v & value) == v)){ // fully covered in value
295 if (sep)
296 ostr << sep;// "{" << (int)(sep) << "}" <<
297 else
298 sep = separator;
299 ostr << entry.first;
300 }
301 else {
302
303 }
304 }
305
306 return ostr;
307}
308
309
310
311
312template <typename T, typename V>
313void FlagResolver::valuesToList(ivalue_t value, const drain::Dictionary<key_t,T> &dict, std::list<V> & container){
314 for (const auto & entry: dict){
315 if ((entry.second > 0) && ((entry.second & value) == entry.second)){ // fully covered in value
316 // ostr << entry.first;
317 container.push_back(static_cast<V>(entry.second));
318 // container.push_back(entry.first);
319 }
320 }
321}
322
323
324
325// NEW 2022/2023
326
327
328// typedef drain::Dictionary<std::string,unsigned long> FlaggerDict;
329
330// #define FlaggerDict FlagResolver::dict_t
331
360template <typename E=std::size_t, typename T=E> //, typename D=drain::Dictionary<std::string,unsigned long> >
362
363public:
364
365 //static
366 //const SprinterLayout dictLayout = {",", "?", "=", ""};
367
368 // Manifested numeric type (enum or unsigned integer)
369 typedef E value_t;
370 typedef T storage_t;
372 typedef typename dict_t::key_t key_t; // ~string
373
374 // Practical "storage" value
375 // typedef typename dict_t::value_t dict_value_t; // TODO: xould be same as value_t ?
376
377 // Rember to add an initialized unit: template<> SingleFlagger<...>::dict = {{...,...}, ...}
378 // static const dict_t dict;
379
380protected:
381 // Default constructor. Local value \c ownValue will be used.
385 inline
386 FlaggerBase(char separator=','): value(ownValue), separator(','), ownValue((storage_t)0){ // drain::NEUTRAL VALUE!
387 }
388
390
394 inline
395 FlaggerBase(storage_t & v, char separator=','): value(v), separator(','){
396 }
397
398 /* Risky? (Ambiguous)
399 inline
400 FlaggerBase(const dict_value_t & v): value(ownValue), ownValue(v) {
401 }
402 */
403
404 virtual inline
405 ~FlaggerBase(){
406 }
407
408public:
409
411
416 virtual
417 const dict_t & getDict() const = 0;
418
419 virtual inline
420 void reset(){
421 this->value = storage_t(0); // ALERT! enums need neutral value.
422 };
423
424
426
430 virtual
431 bool isSet(const storage_t & x) const = 0;
432
433
434 inline
435 bool isSet(const key_t & key) const {
436 return isSet(getDict().getValue(key));
437 };
438
439 inline
440 const storage_t & getValue() const {
441 return value;
442 }
443
444
446 inline
447 operator const storage_t & () const { // should be ivalue ?
448 return this->value;
449 }
450
451 inline
452 operator storage_t & () { // should be ivalue ?
453 return this->value;
454 }
455
456 inline
457 operator bool() const {
458 return static_cast<FlagResolver::ivalue_t>(this->value) != 0;
459 }
460
461
463 virtual
464 const key_t & str() const = 0;
465
466 // String
467 operator const key_t & () const {
468 return str();
469 }
470
471 // Own or external value.
472 storage_t & value;
473
474 char separator;
475
476 void debug(std::ostream & ostr) const;
477
478 /* these apply to SingleFlaggers */
479 /*
481 virtual inline
482 void set(const key_t & key){
483 if (key.empty())
484 return; // needed?
485 assign(key); // potential problem: assign assumes string arg
486 }
487
489 virtual inline
490 void set(const value_t & value){
491 this->value = value;
492 };
493
494 virtual inline
495 void set(const FlaggerBase<E> & flagger){
496 this->value = flagger.value;
497 }
498 */
499
500protected:
501
502private:
503
504 // protect?
505 virtual
506 void assign(const std::string & s) = 0;
507
508
509 // Own value, discarded if external value referenced.
510 storage_t ownValue = 0; // NEUTRAL
511
512};
513
514
515template <typename E,typename T>
516void drain::FlaggerBase<E,T>::debug(std::ostream & ostr) const {
517 //ostr << typeid(drain::FlaggerBase<E>).name() << ": value=" << getValue() << ", ";
518 ostr << drain::TypeName<E>::str() << ": value=" << getValue() << ", ";
519 FlagResolver::keysToStream(getDict(), getValue(), ostr) << ", ";
520 ostr << " dict: " << getDict();
521}
522
523template <typename E,typename T>
524inline
525std::ostream & operator<<(std::ostream & ostr, const drain::FlaggerBase<E,T> & flagger) {
526 return ostr << flagger.str(); // flags.keysToStream(ostr);
527}
528
529/*
530template <typename E>
531const SprinterLayout drain::FlaggerBase<E>::dictLayout = {",", "?", "=", ""};
532*/
533
534
535
536
537} // drain::
538
539
540#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:278
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:313
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:266
Definition FlagBase.h:361
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:395
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
Logger & error(const TT &... args)
Echoes.
Definition Log.h:416
Logger & debug2(const TT &... args)
Debug information.
Definition Log.h:676
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 String.h:380
Definition DataSelector.cpp:1277