Line data Source code
1 : /********************************************************************\
2 :
3 : Name: odbxx.cxx
4 : Created by: Stefan Ritt
5 :
6 : Contents: Object oriented interface to ODB
7 :
8 : This file provides a very object-oriented approach to interacting with the
9 : midas ODB. You can think of it like a "magic" map/dictionary that
10 : automatically sends changes you make to the ODB, and receives updates that
11 : others have made.
12 :
13 : Documentation is at https://midas.triumf.ca/MidasWiki/index.php/Odbxx
14 :
15 : \********************************************************************/
16 :
17 : #ifndef _ODBXX_HXX
18 : #define _ODBXX_HXX
19 :
20 : #include <string>
21 : #include <iostream>
22 : #include <sstream>
23 : #include <stdexcept>
24 : #include <initializer_list>
25 : #include <cstring>
26 : #include <bitset>
27 : #include <functional>
28 : #include <fstream>
29 :
30 : #include "midas.h"
31 : #include "mexcept.h"
32 : #include "mxml.h"
33 : #include "mjson.h"
34 : // #include "mleak.h" // un-comment for memory leak debugging
35 :
36 :
37 : /*------------------------------------------------------------------*/
38 :
39 : namespace midas {
40 :
41 : class odb;
42 :
43 : //================================================================
44 : // u_odb class is a union to hold one ODB value, either a basic
45 : // type, a std::string or a pointer to an odb object
46 : //================================================================
47 :
48 : class u_odb {
49 : private:
50 : // union to hold data
51 : union {
52 : uint8_t m_uint8;
53 : int8_t m_int8;
54 : uint16_t m_uint16;
55 : int16_t m_int16;
56 : uint32_t m_uint32;
57 : int32_t m_int32;
58 : uint64_t m_uint64;
59 : int64_t m_int64;
60 : bool m_bool;
61 : float m_float;
62 : double m_double;
63 : std::string *m_string;
64 : odb *m_odb;
65 : };
66 :
67 : int m_tid;
68 : odb *m_parent_odb;
69 :
70 : public:
71 112 : u_odb() : m_string{}, m_tid{}, m_parent_odb{nullptr} {};
72 :
73 : // for shorter values, first set m_string to nullptr to initialize higher bytes to zero
74 0 : u_odb(uint8_t v) : m_tid{TID_UINT8}, m_parent_odb{nullptr} {m_string = nullptr; m_uint8 = v;};
75 :
76 : u_odb(int8_t v) : m_tid{TID_INT8}, m_parent_odb{nullptr} {m_string = nullptr; m_int8 = v;};
77 :
78 : u_odb(uint16_t v) : m_tid{TID_UINT16}, m_parent_odb{nullptr} {m_string = nullptr; m_uint16 = v;};
79 :
80 : u_odb(int16_t v) : m_tid{TID_INT16}, m_parent_odb{nullptr} {m_string = nullptr; m_int16 = v;};
81 :
82 : u_odb(uint32_t v) : m_tid{TID_UINT32}, m_parent_odb{nullptr} {m_string = nullptr; m_uint32 = v;};
83 :
84 0 : u_odb(int32_t v) : m_tid{TID_INT32}, m_parent_odb{nullptr} {m_string = nullptr; m_int32 = v;};
85 :
86 : u_odb(uint64_t v) : m_tid{TID_UINT64}, m_parent_odb{nullptr} {m_string = nullptr; m_uint64 = v;};
87 :
88 : u_odb(int64_t v) : m_tid{TID_INT64}, m_parent_odb{nullptr} {m_string = nullptr; m_int64 = v;};
89 :
90 0 : u_odb(bool v) : m_tid{TID_BOOL}, m_parent_odb{nullptr} {m_string = nullptr; m_bool = v;};
91 :
92 0 : u_odb(float v) : m_float{v}, m_tid{TID_FLOAT}, m_parent_odb{nullptr} {m_string = nullptr; m_float = v;};
93 :
94 0 : u_odb(double v) : m_double{v}, m_tid{TID_DOUBLE}, m_parent_odb{nullptr} {m_string = nullptr; m_double = v;};
95 :
96 0 : u_odb(std::string *v) : m_string{v}, m_tid{TID_STRING}, m_parent_odb{nullptr} {};
97 :
98 : // Destructor
99 : ~u_odb();
100 :
101 : // Setters and getters
102 112 : void set_parent(odb *o) { m_parent_odb = o; }
103 : odb *get_parent() { return m_parent_odb; }
104 :
105 112 : void set_tid(int tid) { m_tid = tid; }
106 :
107 0 : int get_tid() { return m_tid; }
108 :
109 : // Overload the Assignment Operators
110 : uint8_t operator=(uint8_t v);
111 : int8_t operator=(int8_t v);
112 : uint16_t operator=(uint16_t v);
113 : int16_t operator=(int16_t v);
114 : uint32_t operator=(uint32_t v);
115 : int32_t operator=(int32_t v);
116 : uint64_t operator=(uint64_t v);
117 : int64_t operator=(int64_t v);
118 : bool operator=(bool v);
119 : float operator=(float v);
120 : double operator=(double v);
121 : const char *operator=(const char *v);
122 : std::string *operator=(std::string * v);
123 : std::string operator=(std::string v);
124 :
125 : // Overload the Conversion Operators
126 : operator uint8_t();
127 : operator int8_t();
128 : operator uint16_t();
129 : operator int16_t();
130 : operator uint32_t();
131 : operator int32_t();
132 : operator uint64_t();
133 : operator int64_t();
134 : operator bool();
135 : operator float();
136 : operator double();
137 : operator std::string();
138 : operator const char *();
139 : operator midas::odb &();
140 :
141 : template<typename T>
142 28 : void set(T v) {
143 28 : if (m_tid == TID_UINT8)
144 0 : m_uint8 = v;
145 28 : else if (m_tid == TID_INT8)
146 0 : m_int8 = v;
147 28 : else if (m_tid == TID_UINT16)
148 0 : m_uint16 = v;
149 28 : else if (m_tid == TID_INT16)
150 0 : m_int16 = v;
151 28 : else if (m_tid == TID_UINT32)
152 8 : m_uint32 = v;
153 20 : else if (m_tid == TID_INT32)
154 4 : m_int32 = v;
155 16 : else if (m_tid == TID_UINT64)
156 0 : m_uint64 = v;
157 16 : else if (m_tid == TID_INT64)
158 0 : m_int64 = v;
159 16 : else if (m_tid == TID_BOOL)
160 16 : m_bool = v;
161 0 : else if (m_tid == TID_FLOAT)
162 0 : m_float = v;
163 0 : else if (m_tid == TID_DOUBLE)
164 0 : m_double = v;
165 0 : else if (m_tid == TID_STRING) {
166 0 : delete m_string;
167 0 : m_string = new std::string(std::to_string(v));
168 : } else
169 0 : mthrow("Invalid type ID " + std::to_string(m_tid));
170 28 : }
171 :
172 2 : void set_string(std::string s) {
173 2 : delete m_string;
174 2 : m_string = new std::string(s);
175 2 : }
176 :
177 : void set_string_size(std::string s, int size);
178 :
179 0 : void set_string_ptr(std::string *s) {
180 0 : m_string = s;
181 0 : }
182 :
183 36 : void set(odb *v) {
184 36 : if (m_tid != TID_KEY)
185 0 : mthrow("Subkey can only be assigned to ODB key");
186 36 : m_odb = v;
187 36 : }
188 :
189 0 : void set_odb(odb *v) {
190 0 : if (m_tid != TID_KEY)
191 0 : mthrow("Subkey can only be assigned to ODB key");
192 0 : m_odb = v;
193 0 : }
194 :
195 12 : void set(std::string v) {
196 12 : if (m_tid == TID_UINT8)
197 0 : m_uint8 = std::stoi(v, nullptr, 0); // stoi convertx 0x automatically
198 12 : else if (m_tid == TID_INT8)
199 0 : m_int8 = std::stoi(v, nullptr, 0);
200 12 : else if (m_tid == TID_UINT16)
201 0 : m_uint16 = std::stoi(v, nullptr, 0);
202 12 : else if (m_tid == TID_INT16)
203 0 : m_int16 = std::stoi(v, nullptr, 0);
204 12 : else if (m_tid == TID_UINT32)
205 0 : m_uint32 = std::stoul(v, nullptr, 0);
206 12 : else if (m_tid == TID_INT32)
207 0 : m_int32 = std::stoul(v, nullptr, 0);
208 12 : else if (m_tid == TID_UINT64)
209 0 : m_uint64 = std::stoul(v, nullptr, 0);
210 12 : else if (m_tid == TID_INT64)
211 0 : m_int64 = std::stoul(v, nullptr, 0);
212 12 : else if (m_tid == TID_BOOL)
213 0 : m_bool = std::stoi(v, nullptr, 0);
214 12 : else if (m_tid == TID_FLOAT)
215 0 : m_float = std::stod(v);
216 12 : else if (m_tid == TID_DOUBLE)
217 0 : m_double = std::stod(v);
218 12 : else if (m_tid == TID_STRING) {
219 12 : delete m_string;
220 12 : m_string = new std::string(v);
221 0 : } else if (m_tid == TID_LINK) {
222 0 : delete m_string;
223 0 : m_string = new std::string(v);
224 : } else
225 0 : mthrow("Invalid type ID " + std::to_string(m_tid));
226 12 : }
227 :
228 0 : void set(const char *v) {
229 0 : set(std::string(v));
230 0 : }
231 :
232 10 : void set(char *v) {
233 10 : set(std::string(v));
234 10 : }
235 :
236 :
237 : void add(double inc, bool push = true);
238 :
239 : void mult(double f, bool push = true);
240 :
241 : // overload arithmetic operators
242 : u_odb &operator++(int) {
243 : add(1);
244 : return *this;
245 : }
246 :
247 : u_odb &operator++() {
248 : add(1);
249 : return *this;
250 : }
251 :
252 : u_odb &operator--(int) {
253 : add(-1);
254 : return *this;
255 : }
256 :
257 : u_odb &operator--() {
258 : add(-1);
259 : return *this;
260 : }
261 :
262 : u_odb &operator+=(double d) {
263 : add(d);
264 : return *this;
265 : }
266 :
267 : u_odb &operator-=(double d) {
268 : add(-d);
269 : return *this;
270 : }
271 :
272 : u_odb &operator*=(double d) {
273 : mult(d);
274 : return *this;
275 : }
276 :
277 : u_odb &operator/=(double d) {
278 : if (d == 0)
279 : mthrow("Division by zero");
280 : mult(1 / d);
281 : return *this;
282 : }
283 :
284 : template<typename T>
285 : u_odb &operator+(T v) {
286 : double d = *this;
287 : d += v;
288 : set(v);
289 : return *this;
290 : }
291 :
292 : template<typename T>
293 : u_odb &operator-(T v) {
294 : double d = *this;
295 : d -= v;
296 : set(v);
297 : return *this;
298 : }
299 :
300 : template<typename T>
301 : u_odb &operator*(T v) {
302 : double d = *this;
303 : d *= v;
304 : set(v);
305 : return *this;
306 : }
307 :
308 : template<typename T>
309 : u_odb &operator/(T v) {
310 : double d = *this;
311 : d /= v;
312 : set(v);
313 : return *this;
314 : }
315 :
316 : // get function for basic type
317 : template<typename T>
318 0 : T get() {
319 0 : if (m_tid == TID_UINT8)
320 0 : return (T) m_uint8;
321 0 : else if (m_tid == TID_INT8)
322 0 : return (T) m_int8;
323 0 : else if (m_tid == TID_UINT16)
324 0 : return (T) m_uint16;
325 0 : else if (m_tid == TID_INT16)
326 0 : return (T) m_int16;
327 0 : else if (m_tid == TID_UINT32)
328 0 : return (T) m_uint32;
329 0 : else if (m_tid == TID_INT32)
330 0 : return (T) m_int32;
331 0 : else if (m_tid == TID_UINT64)
332 0 : return (T) m_uint64;
333 0 : else if (m_tid == TID_INT64)
334 0 : return (T) m_int64;
335 0 : else if (m_tid == TID_BOOL)
336 0 : return (T) m_bool;
337 0 : else if (m_tid == TID_FLOAT)
338 0 : return (T) m_float;
339 0 : else if (m_tid == TID_DOUBLE)
340 0 : return (T) m_double;
341 0 : else if (m_tid == 0)
342 0 : mthrow("Subkey not found");
343 : else
344 0 : mthrow("Invalid type ID %s" + std::to_string(m_tid));
345 : }
346 :
347 : // get function for string
348 0 : std::string get() {
349 0 : std::string s;
350 0 : get(s);
351 0 : return s;
352 0 : }
353 :
354 : std::string get_value() {
355 : std::string s;
356 : get(s);
357 : return s;
358 : }
359 :
360 : // shortcut to above
361 0 : std::string s() {
362 0 : return get();
363 : }
364 :
365 : // get function for strings
366 : void get(std::string &s);
367 :
368 : // get_function for keys
369 4 : odb *get_podb() {
370 4 : if (m_tid != TID_KEY)
371 0 : mthrow("odb_get() called for non-key object");
372 4 : return m_odb;
373 : }
374 :
375 70 : odb &get_odb() {
376 70 : if (m_tid != TID_KEY)
377 0 : mthrow("odb_get() called for non-key object");
378 70 : return *m_odb;
379 : }
380 :
381 : // overload stream out operator
382 : friend std::ostream &operator<<(std::ostream &output, u_odb &o) {
383 : std::string s = o;
384 : output << s;
385 : return output;
386 : };
387 :
388 : };
389 :
390 : //-----------------------------------------------
391 :
392 : // bit in odb::m_flags
393 : enum odb_flags {
394 : AUTO_REFRESH_READ = 0,
395 : AUTO_REFRESH_WRITE,
396 : PRESERVE_STRING_SIZE,
397 : AUTO_CREATE,
398 : AUTO_ENLARGE_ARRAY,
399 : DIRTY,
400 : DELETED,
401 : WRITE_PROTECT,
402 : TRIGGER_HOTLINK
403 : };
404 :
405 : //================================================================
406 : // the odb object holds an ODB entry with name, type,
407 : // hKey and array of u_odb values
408 : //================================================================
409 :
410 : class odb {
411 : public:
412 : // data source
413 : enum odb_source {
414 : ONLINE = 0,
415 : STRING,
416 : FILE
417 : };
418 :
419 : class iterator {
420 : public:
421 0 : iterator(u_odb *pu) : pu_odb(pu) {}
422 :
423 : // Pre-increment
424 0 : iterator operator++() {
425 0 : ++pu_odb;
426 0 : return *this;
427 : }
428 :
429 : // Post-increment
430 : iterator operator++(int) {
431 : iterator ret = *this;
432 : this->operator++();
433 : return ret;
434 : }
435 :
436 0 : bool operator!=(const iterator &other) const { return pu_odb != other.pu_odb; }
437 :
438 0 : u_odb &operator*() { return *pu_odb; }
439 :
440 : private:
441 : u_odb *pu_odb;
442 : };
443 :
444 : private:
445 :
446 : // source of ODB, same for all instances
447 0 : thread_local static odb_source s_odb_source;
448 0 : thread_local static std::string s_odb_source_str; // string or filename
449 : // handle to ODB, same for all instances
450 : static HNDLE s_hDB;
451 : // global debug flag for all instances
452 : static bool s_debug;
453 : // global flag indicating that we are connected to the ODB
454 : static bool s_connected_odb;
455 : // global list of ODB keys used by odb::watch
456 : static std::vector<midas::odb> m_watch;
457 :
458 : // various parameters defined in odb_flags
459 : std::bitset<9> m_flags;
460 : // type of this object, one of TID_xxx
461 : int m_tid;
462 : // vector containing data for this object
463 : u_odb *m_data;
464 : // name of ODB entry
465 : std::string m_name;
466 : // number of values of ODB entry
467 : int m_num_values;
468 : // last index accessed, needed for o[i] = x
469 : int m_last_index;
470 : // ODB handle for this key
471 : HNDLE m_hKey;
472 : // callback for watch funciton
473 : std::function<void(midas::odb &)> m_watch_callback;
474 : // parent ODB key
475 : midas::odb *m_parent;
476 :
477 : //-------------------------------------------------------------
478 :
479 : // static functions
480 : static void init_hdb();
481 : static midas::odb *search_hkey(midas::odb *po, int hKey);
482 : static void watch_callback(int hDB, int hKey, int index, void *info);
483 : static void unwatch_all();
484 :
485 : //-------------------------------------------------------------
486 :
487 : void set_flags_recursively(uint32_t f);
488 : void resize_mdata(int size);
489 :
490 : // get function for basic types
491 : template<typename T>
492 0 : T get() {
493 0 : if (m_num_values > 1)
494 0 : mthrow("ODB key \"" + get_full_path() +
495 : "[0..." + std::to_string(m_num_values - 1) +
496 : "]\" contains array. Please assign to std::vector.");
497 0 : if (is_auto_refresh_read())
498 0 : read();
499 0 : return (T) m_data[0];
500 : }
501 :
502 : // get function for basic types as a parameter
503 : template<typename T>
504 0 : void get(T &v) {
505 0 : if (m_num_values > 1)
506 0 : mthrow("ODB key \"" + get_full_path() + "\" contains array. Please assign to std::vector.");
507 0 : if (is_auto_refresh_read())
508 0 : read();
509 0 : v = (T) m_data[0];
510 0 : }
511 :
512 : // get function for strings
513 : void get(std::string &s, bool quotes = false, bool refresh = true);
514 :
515 : // return internal data
516 : u_odb &get_mdata(int index = 0) { return m_data[index]; }
517 :
518 : odb &get_subkey(std::string str);
519 : int get_subkeys(std::vector<std::string> &name);
520 : bool read_key(const std::string &path);
521 : bool write_key(std::string &path, bool write_defaults);
522 :
523 0 : void set_hkey(HNDLE hKey) { m_hKey = hKey; }
524 :
525 0 : void set_flags(uint32_t f) { m_flags = f; }
526 2 : uint32_t get_flags() { return static_cast<uint32_t>(m_flags.to_ulong()); }
527 :
528 40 : bool is_deleted() const { return m_flags[odb_flags::DELETED]; }
529 0 : void set_deleted(bool f) { m_flags[odb_flags::DELETED] = f; }
530 :
531 0 : void set_tid(int tid) { m_tid = tid; }
532 0 : void set_num_values(int n) { m_num_values = n; }
533 :
534 0 : void set_name(std::string s) { m_name = s; }
535 :
536 36 : void set_parent(midas::odb *p) { m_parent = p; }
537 : midas::odb *get_parent() { return m_parent; }
538 :
539 : public:
540 :
541 : // Default constructor
542 40 : odb() :
543 40 : m_flags{(1 << odb_flags::AUTO_REFRESH_READ) |
544 : (1 << odb_flags::AUTO_REFRESH_WRITE) |
545 : (1 << odb_flags::AUTO_ENLARGE_ARRAY) |
546 : (1 << odb_flags::AUTO_CREATE) |
547 : (1 << odb_flags::TRIGGER_HOTLINK)},
548 40 : m_tid{0},
549 40 : m_data{nullptr},
550 40 : m_name{},
551 40 : m_num_values{0},
552 40 : m_last_index{-1},
553 40 : m_hKey{},
554 40 : m_parent{} {}
555 :
556 : // Destructor
557 40 : ~odb() {
558 96 : delete[] m_data;
559 40 : }
560 :
561 : // Deep copy constructor
562 : odb(const odb &o);
563 :
564 : // Delete shallow assignment operator
565 : odb operator=(odb &&o) = delete;
566 :
567 : // Constructor for single basic types
568 : template<typename T>
569 0 : odb(T v):odb() {
570 0 : m_num_values = 1;
571 0 : m_data = new u_odb[1]{v};
572 0 : m_tid = m_data[0].get_tid();
573 0 : m_data[0].set_parent(this);
574 0 : }
575 :
576 : // Constructor with std::initializer_list
577 0 : odb(std::initializer_list<std::pair<const char *, midas::odb>> list) : odb() {
578 0 : m_tid = TID_KEY;
579 0 : m_num_values = list.size();
580 0 : m_data = new u_odb[m_num_values];
581 0 : int i = 0;
582 0 : for (auto &element: list) {
583 : // check if name exists already
584 0 : for (int j=0 ; j<i ; j++) {
585 0 : if (strcasecmp(element.first, m_data[j].get_odb().get_name().c_str()) == 0) {
586 0 : if (element.first == m_data[j].get_odb().get_name().c_str()) {
587 0 : mthrow("ODB key with name \"" + m_data[j].get_odb().get_name() + "\" exists already");
588 : } else {
589 0 : mthrow("ODB key \"" + std::string(element.first) + "\" exists already as \"" +
590 : m_data[j].get_odb().get_name() + "\" (only case differs)");
591 : }
592 : }
593 : }
594 0 : auto o = new midas::odb(element.second);
595 0 : o->set_name(element.first);
596 0 : o->set_parent(this);
597 0 : m_data[i].set_tid(TID_KEY);
598 0 : m_data[i].set_parent(this);
599 0 : m_data[i].set(o);
600 0 : i++;
601 : }
602 0 : }
603 :
604 : // Constructor with basic type array
605 : template<typename T>
606 0 : odb(std::initializer_list<T> list) : odb() {
607 0 : m_num_values = list.size();
608 0 : m_data = new u_odb[m_num_values]{};
609 0 : int i = 0;
610 0 : for (auto &element : list) {
611 0 : u_odb u(element);
612 0 : m_data[i].set_tid(u.get_tid());
613 0 : m_data[i].set_parent(this);
614 0 : m_data[i].set(element);
615 0 : i++;
616 : }
617 0 : m_tid = m_data[0].get_tid();
618 0 : }
619 :
620 : // Constructor with basic explicit array
621 : template<typename T, size_t SIZE>
622 0 : odb(const std::array<T, SIZE> &arr) : odb() {
623 0 : m_num_values = SIZE;
624 0 : m_data = new u_odb[m_num_values]{};
625 0 : for (int i = 0; i < (int)SIZE; i++) {
626 0 : u_odb u(arr[i]);
627 0 : m_data[i].set_tid(u.get_tid());
628 0 : m_data[i].set_parent(this);
629 0 : m_data[i].set(arr[i]);
630 : }
631 0 : m_tid = m_data[0].get_tid();
632 0 : }
633 :
634 : // Constructor with explicit array of std::string
635 : template<size_t SIZE>
636 0 : odb(const std::array<std::string, SIZE> &arr) : odb() {
637 0 : m_num_values = SIZE;
638 0 : m_data = new u_odb[m_num_values]{};
639 0 : for (int i = 0; i < (int)SIZE; i++) {
640 0 : std::string * mystring = new std::string(arr[i]);
641 0 : u_odb u(mystring);
642 0 : m_data[i].set_tid(u.get_tid());
643 0 : m_data[i].set_parent(this);
644 0 : m_data[i].set(arr[i]);
645 : }
646 0 : m_tid = m_data[0].get_tid();
647 0 : }
648 :
649 : // Constructor for std::string
650 38 : odb(const std::string &path, bool init_via_xml = false) : odb() {
651 38 : if (path[0] == '/') {
652 : // ODB path
653 38 : if (s_odb_source == ONLINE) {
654 38 : if (init_via_xml) {
655 0 : if (!exists(path))
656 0 : odb::create(path.c_str(), TID_KEY);
657 0 : odb_from_xml_remote(path);
658 : } else {
659 38 : if (!read_key(path))
660 : // create subdir if key does not exist
661 0 : odb::create(path.c_str(), TID_KEY);
662 :
663 38 : if (!read_key(path))
664 0 : mthrow("ODB key \"" + path + "\" not found in ODB");
665 :
666 38 : if (m_tid != TID_KEY)
667 36 : read();
668 : }
669 0 : } else if (s_odb_source == STRING) {
670 :
671 0 : if (s_odb_source_str.substr(0, 19) == "<?xml version=\"1.0\"")
672 0 : odb_from_xml_string(s_odb_source_str, path);
673 0 : else if (s_odb_source_str.substr(0, 1) == "{")
674 0 : odb_from_json_string(s_odb_source_str, path);
675 : else
676 0 : mthrow("Unknown string format: \"" + s_odb_source_str + "\"");
677 :
678 0 : } else if (s_odb_source == FILE) {
679 :
680 : // create odb from file
681 0 : std::ifstream file(s_odb_source_str);
682 0 : if (!file)
683 0 : mthrow("File \"" + s_odb_source_str + "\" not found");
684 0 : std::ostringstream ss;
685 0 : ss << file.rdbuf();
686 0 : file.close();
687 :
688 0 : if (s_odb_source_str.find(".xml") != std::string::npos ||
689 0 : s_odb_source_str.find(".XML") != std::string::npos)
690 0 : odb_from_xml_string(ss.str(), path);
691 0 : else if (s_odb_source_str.find(".json") != std::string::npos ||
692 0 : s_odb_source_str.find(".JSON") != std::string::npos)
693 0 : odb_from_json_string(ss.str(), path);
694 : else
695 0 : mthrow("File type of \"" +s_odb_source_str + "\" is not supported");
696 :
697 0 : } else
698 0 : mthrow("Unknown ODB source: " + std::to_string(s_odb_source));
699 :
700 : } else {
701 : // simple string
702 :
703 : // Construct object from initializer_list
704 0 : m_num_values = 1;
705 0 : m_data = new u_odb[1]{new std::string{path}};
706 0 : m_tid = m_data[0].get_tid();
707 0 : m_data[0].set_parent(this);
708 : }
709 38 : }
710 :
711 : // Constructor for C string
712 72 : odb(const char *s) : odb(std::string(s)) {
713 36 : }
714 :
715 : // Constructor with const char * array
716 0 : odb(std::initializer_list<const char *> list) : odb() {
717 0 : m_num_values = list.size();
718 0 : m_data = new u_odb[m_num_values]{};
719 0 : int i = 0;
720 0 : for (auto &element : list) {
721 0 : m_data[i].set_tid(TID_STRING);
722 0 : m_data[i].set_parent(this);
723 0 : m_data[i].set(element);
724 0 : i++;
725 : }
726 0 : m_tid = m_data[0].get_tid();
727 0 : }
728 :
729 : template<typename T>
730 0 : int detect_type(const T &) {
731 : if (std::is_same<T, uint8_t>::value)
732 : return TID_UINT8;
733 : else if (std::is_same<T, int8_t>::value)
734 : return TID_INT8;
735 : else if (std::is_same<T, uint16_t>::value)
736 : return TID_UINT16;
737 : else if (std::is_same<T, int16_t>::value)
738 : return TID_INT16;
739 : else if (std::is_same<T, uint32_t>::value)
740 0 : return TID_UINT32;
741 : else if (std::is_same<T, unsigned long>::value && sizeof(long) == 4)
742 : return TID_UINT32;
743 : else if (std::is_same<T, int32_t>::value)
744 0 : return TID_INT32;
745 : else if (std::is_same<T, long>::value && sizeof(long) == 4)
746 : return TID_INT32;
747 : else if (std::is_same<T, uint64_t>::value)
748 0 : return TID_UINT64;
749 : else if (std::is_same<T, unsigned long>::value && sizeof(long) == 8)
750 : return TID_UINT64;
751 : else if (std::is_same<T, int64_t>::value)
752 : return TID_INT64;
753 : else if (std::is_same<T, long>::value && sizeof(long) == 8)
754 : return TID_INT64;
755 : else if (std::is_same<T, bool>::value)
756 0 : return TID_BOOL;
757 : else if (std::is_same<T, float>::value)
758 0 : return TID_FLOAT;
759 : else if (std::is_same<T, double>::value)
760 0 : return TID_DOUBLE;
761 : else
762 0 : return TID_STRING;
763 : }
764 :
765 : // Overload the Assignment Operators
766 : template<typename T>
767 0 : const T &operator=(const T &v) {
768 :
769 0 : if (this->is_write_protect())
770 0 : mthrow("Cannot modify write protected key \"" + get_full_path() + "\"");
771 :
772 0 : if (m_num_values == 0) {
773 : // initialize this
774 0 : m_num_values = 1;
775 0 : m_tid = detect_type(v);
776 0 : m_data = new u_odb[1]{};
777 0 : m_data[0].set_tid(m_tid);
778 0 : m_data[0].set_parent(this);
779 0 : m_data[0].set(v);
780 0 : if (this->is_auto_refresh_write())
781 0 : write();
782 : } else {
783 0 : for (int i = 0; i < m_num_values; i++)
784 0 : m_data[i].set(v);
785 :
786 0 : if (this->is_auto_refresh_write())
787 0 : write();
788 : }
789 0 : return v;
790 : }
791 :
792 : // Overload the Assignment Operators for std::vector
793 : template<typename T>
794 0 : const std::vector<T> &operator=(const std::vector<T> &v) {
795 :
796 0 : if (this->is_write_protect())
797 0 : mthrow("Cannot modify write protected key \"" + get_full_path() + "\"");
798 :
799 0 : if (m_num_values == 0) {
800 : // initialize this
801 0 : m_num_values = v.size();
802 : if (std::is_same<T, bool>::value) {
803 : // Special logic for vector<bool>, which may not be a true
804 : // container: it's often optimized to be a bitfield, with
805 : // references to elements being masked bits rather than bools.
806 : // So T is a bool here, but typeof(v[0]) may not be bool!
807 : // "Fake container optimization" only applies to vector<bool>,
808 : // not array<bool> or any other vector<T>.
809 0 : m_tid = TID_BOOL;
810 : } else {
811 : // Every other type can be detected using ref to first element.
812 0 : m_tid = detect_type(v[0]);
813 : }
814 :
815 0 : m_data = new u_odb[m_num_values]{};
816 0 : for (int i = 0; i < m_num_values; i++) {
817 0 : m_data[i].set_tid(m_tid);
818 0 : m_data[i].set_parent(this);
819 : }
820 :
821 : } else {
822 :
823 : // resize internal array if different
824 0 : if ((int)v.size() != m_num_values) {
825 0 : resize_mdata(v.size());
826 : }
827 : }
828 :
829 0 : for (int i = 0; i < m_num_values; i++)
830 0 : m_data[i].set(v[i]);
831 :
832 0 : if (this->is_auto_refresh_write())
833 0 : write();
834 :
835 0 : return v;
836 : }
837 :
838 : // Overload the Assignment Operators for std::array
839 : template<typename T, size_t SIZE>
840 0 : const std::array<T, SIZE> &operator=(const std::array<T, SIZE> &arr) {
841 :
842 0 : if (this->is_write_protect())
843 0 : mthrow("Cannot modify write protected key \"" + get_full_path() + "\"");
844 :
845 0 : if (m_num_values == 0) {
846 : // initialize this
847 0 : m_num_values = SIZE;
848 0 : m_tid = detect_type(arr[0]);
849 0 : m_data = new u_odb[m_num_values]{};
850 0 : for (int i = 0; i < m_num_values; i++) {
851 0 : m_data[i].set_tid(m_tid);
852 0 : m_data[i].set_parent(this);
853 : }
854 :
855 : } else {
856 :
857 : // resize internal array if different
858 0 : if (SIZE != m_num_values) {
859 0 : resize_mdata(SIZE);
860 : }
861 : }
862 :
863 0 : for (int i = 0; i < m_num_values; i++)
864 0 : m_data[i].set(arr[i]);
865 :
866 0 : if (this->is_auto_refresh_write())
867 0 : write();
868 0 : return arr;
869 : }
870 :
871 : // overload conversion operator for std::string
872 0 : operator std::string() {
873 0 : std::string s;
874 0 : if (m_tid == TID_KEY)
875 0 : print(s, 0);
876 : else
877 0 : get(s); // forward to get(std::string)
878 0 : return s;
879 0 : }
880 :
881 : // overload conversion operator for std::vector<T>
882 : template<typename T>
883 0 : operator std::vector<T>() {
884 0 : if (is_auto_refresh_read())
885 0 : read();
886 0 : std::vector<T> v(m_num_values);
887 0 : for (int i = 0; i < m_num_values; i++)
888 0 : v[i] = m_data[i];
889 0 : return v;
890 0 : }
891 :
892 0 : operator std::vector<std::string>() {
893 0 : if (is_auto_refresh_read())
894 0 : read();
895 0 : std::vector<std::string> v(m_num_values);
896 0 : for (int i = 0; i < m_num_values; i++)
897 0 : v[i] = m_data[i].get();
898 0 : return v;
899 0 : }
900 :
901 : // overload all other conversion operators
902 : template<typename T, typename std::enable_if<
903 : std::is_same<T, uint8_t>::value ||
904 : std::is_same<T, int8_t>::value ||
905 : std::is_same<T, uint16_t>::value ||
906 : std::is_same<T, int16_t>::value ||
907 : std::is_same<T, uint32_t>::value ||
908 : std::is_same<T, int32_t>::value ||
909 : std::is_same<T, uint64_t>::value ||
910 : std::is_same<T, int64_t>::value ||
911 : std::is_same<T, bool>::value ||
912 : std::is_same<T, float>::value ||
913 : std::is_same<T, double>::value, T>::type * = nullptr>
914 0 : operator T() {
915 0 : if (m_tid == 0)
916 0 : mthrow("Element \"" + m_name + "\" not found");
917 0 : return get<T>(); // forward to get<T>()
918 : }
919 :
920 : // overload stream out operator
921 0 : friend std::ostream &operator<<(std::ostream &output, odb &o) {
922 0 : std::string s;
923 0 : if (o.m_tid == TID_KEY)
924 0 : o.print(s, 0);
925 : else
926 0 : o.get(s);
927 0 : output << s;
928 0 : return output;
929 0 : };
930 :
931 : // overload index operator for arrays
932 0 : u_odb &operator[](int index) {
933 0 : if (this->is_write_protect())
934 0 : mthrow("Cannot modify write protected key \"" + get_full_path() + "\"");
935 :
936 0 : if (index < 0)
937 0 : throw std::out_of_range("Index \"" + std::to_string(index) + "\" out of range for ODB key \"" + get_full_path() + "[0..." + std::to_string(m_num_values - 1) + "]\"");
938 :
939 0 : if (index == 0 && m_num_values == 0) {
940 : // initialize this
941 0 : m_num_values = 1;
942 0 : m_tid = 0;
943 0 : m_data = new u_odb[1]{};
944 0 : m_data[0].set_tid(m_tid);
945 0 : m_data[0].set_parent(this);
946 0 : m_last_index = 0;
947 0 : return m_data[0];
948 0 : } else if (index >= m_num_values) {
949 0 : if (is_auto_enlarge_array()) {
950 0 : resize_mdata(index+1);
951 0 : if (this->is_auto_refresh_write())
952 0 : write(index, 0);
953 : } else {
954 0 : throw std::out_of_range("Index \"" + std::to_string(index) + "\" out of range for ODB key \"" + get_full_path() + "[0..." + std::to_string(m_num_values - 1) + "]\", please consider set_auto_enlarge_array(true)");
955 : }
956 : }
957 :
958 0 : if (is_auto_refresh_read())
959 0 : read(index);
960 :
961 0 : m_last_index = index;
962 0 : return m_data[index];
963 : }
964 :
965 : // overload index operator for subkeys
966 0 : odb &operator[](std::string str) {
967 0 : return get_subkey(str);
968 : }
969 :
970 4 : odb &operator[](const char *str) {
971 8 : return get_subkey(std::string(str));
972 : }
973 :
974 : // overload the call operator
975 : template <typename T>
976 0 : odb& operator()(T v) {
977 0 : if (m_tid == 0) {
978 0 : if (m_num_values == 0) {
979 : // initialize this
980 0 : m_num_values = 1;
981 0 : m_tid = detect_type(v);
982 0 : m_data = new u_odb[1]{};
983 0 : m_data[0].set_tid(m_tid);
984 0 : m_data[0].set_parent(this);
985 0 : m_data[0].set(v);
986 0 : if (this->is_auto_refresh_write())
987 0 : write();
988 : } else {
989 0 : for (int i = 0; i < m_num_values; i++)
990 0 : m_data[i].set(v);
991 0 : if (this->is_auto_refresh_write())
992 0 : write();
993 : }
994 : }
995 0 : return *this;
996 : }
997 :
998 : // indexed access, internal use only
999 : int get_last_index() { return m_last_index; }
1000 2 : void set_last_index(int i) { m_last_index = i; }
1001 :
1002 : // iterator support
1003 0 : iterator begin() const { return iterator(m_data); }
1004 0 : iterator end() const { return iterator(m_data + m_num_values); }
1005 :
1006 : // overload arithmetic operators
1007 : template<typename T>
1008 0 : T operator+(T i) {
1009 0 : if (m_num_values > 1)
1010 0 : mthrow("ODB key \"" + get_full_path() +
1011 : "\" contains array which cannot be used in basic arithmetic operation.");
1012 : if (std::is_same<T, midas::odb>::value) {
1013 0 : if (is_auto_refresh_read()) {
1014 0 : read();
1015 0 : i.read();
1016 : }
1017 : // adding two midas::odb objects is best done in double
1018 0 : double s1 = static_cast<double>(m_data[0]);
1019 0 : double s2 = static_cast<double>(i.m_data[0]);
1020 0 : return s1 + s2;
1021 : } else {
1022 : if (is_auto_refresh_read())
1023 : read();
1024 : T s = (T) m_data[0];
1025 : return s + i;
1026 : }
1027 : }
1028 :
1029 : template<typename T>
1030 : T operator-(T i) {
1031 : if (m_num_values > 1)
1032 : mthrow("ODB key \"" + get_full_path() +
1033 : "\" contains array which cannot be used in basic arithmetic operation.");
1034 : if (std::is_same<T, midas::odb>::value) {
1035 : if (is_auto_refresh_read()) {
1036 : read();
1037 : i.read();
1038 : }
1039 : // subtracting two midas::odb objects is best done in double
1040 : double s1 = static_cast<double>(m_data[0]);
1041 : double s2 = static_cast<double>(i.m_data[0]);
1042 : return s1 - s2;
1043 : } else {
1044 : if (is_auto_refresh_read())
1045 : read();
1046 : T s = (T) m_data[0];
1047 : return s - i;
1048 : }
1049 : }
1050 :
1051 : template<typename T>
1052 : T operator*(const T i) {
1053 : if (m_num_values > 1)
1054 : mthrow("ODB key \"" + get_full_path() +
1055 : "\" contains array which cannot be used in basic arithmetic operation.");
1056 : if (is_auto_refresh_read())
1057 : read();
1058 : T s = (T) m_data[0];
1059 : return s * i;
1060 : }
1061 :
1062 : template<typename T>
1063 : T operator/(const T i) {
1064 : if (m_num_values > 1)
1065 : mthrow("ODB key \"" + get_full_path() +
1066 : "\" contains array which cannot be used in basic arithmetic operation.");
1067 : if (is_auto_refresh_read())
1068 : read();
1069 : T s = (T) m_data[0];
1070 : return s / i;
1071 : }
1072 :
1073 : odb &operator++() {
1074 : if (is_auto_refresh_read())
1075 : read();
1076 : for (int i = 0; i < m_num_values; i++)
1077 : m_data[i].add(1, false);
1078 : if (this->is_auto_refresh_write())
1079 : write();
1080 : return *this;
1081 : }
1082 :
1083 0 : odb operator++(int) {
1084 : // create temporary object
1085 0 : odb o(this);
1086 0 : if (is_auto_refresh_read())
1087 0 : read();
1088 0 : for (int i = 0; i < m_num_values; i++)
1089 0 : m_data[i].add(1, false);
1090 0 : if (this->is_auto_refresh_write())
1091 0 : write();
1092 0 : return o;
1093 0 : }
1094 :
1095 : odb &operator--() {
1096 : if (is_auto_refresh_read())
1097 : read();
1098 : for (int i = 0; i < m_num_values; i++)
1099 : m_data[i].add(-1, false);
1100 : if (this->is_auto_refresh_write())
1101 : write();
1102 : return *this;
1103 : }
1104 :
1105 : odb operator--(int) {
1106 : // create temporary object
1107 : odb o(this);
1108 : if (is_auto_refresh_read())
1109 : read();
1110 : for (int i = 0; i < m_num_values; i++)
1111 : m_data[i].add(-1, false);
1112 : if (this->is_auto_refresh_write())
1113 : write();
1114 : return o;
1115 : }
1116 :
1117 : odb &operator+=(double d) {
1118 : if (is_auto_refresh_read())
1119 : read();
1120 : for (int i = 0; i < m_num_values; i++)
1121 : m_data[i].add(d, false);
1122 : if (this->is_auto_refresh_write())
1123 : write();
1124 : return *this;
1125 : }
1126 :
1127 : odb &operator-=(double d) {
1128 : if (is_auto_refresh_read())
1129 : read();
1130 : for (int i = 0; i < m_num_values; i++)
1131 : m_data[i].add(-d, false);
1132 : if (this->is_auto_refresh_write())
1133 : write();
1134 : return *this;
1135 : }
1136 :
1137 0 : odb &operator*=(double d) {
1138 0 : if (is_auto_refresh_read())
1139 0 : read();
1140 0 : for (int i = 0; i < m_num_values; i++)
1141 0 : m_data[i].mult(d, false);
1142 0 : if (this->is_auto_refresh_write())
1143 0 : write();
1144 0 : return *this;
1145 : }
1146 :
1147 : odb &operator/=(double d) {
1148 : if (is_auto_refresh_read())
1149 : read();
1150 : if (d == 0)
1151 : mthrow("Division by zero");
1152 : for (int i = 0; i < m_num_values; i++)
1153 : m_data[i].mult(1 / d, false);
1154 : if (this->is_auto_refresh_write())
1155 : write();
1156 : return *this;
1157 : }
1158 :
1159 : // overload comparison operators
1160 : template<typename T>
1161 : friend bool operator==(const midas::odb &o, const T &d);
1162 : template<typename T>
1163 : friend bool operator==(const T &d, const midas::odb &o);
1164 : template<typename T>
1165 : friend bool operator!=(const midas::odb &o, const T &d);
1166 : template<typename T>
1167 : friend bool operator!=(const T &d, const midas::odb &o);
1168 : template<typename T>
1169 : friend bool operator<(const midas::odb &o, const T &d);
1170 : template<typename T>
1171 : friend bool operator<(const T &d, const midas::odb &o);
1172 : template<typename T>
1173 : friend bool operator<=(const midas::odb &o, const T &d);
1174 : template<typename T>
1175 : friend bool operator<=(const T &d, const midas::odb &o);
1176 : template<typename T>
1177 : friend bool operator>(const midas::odb &o, const T &d);
1178 : template<typename T>
1179 : friend bool operator>(const T &d, const midas::odb &o);
1180 : template<typename T>
1181 : friend bool operator>=(const midas::odb &o, const T &d);
1182 : template<typename T>
1183 : friend bool operator>=(const T &d, const midas::odb &o);
1184 :
1185 : // create midas::odb object form MXML node
1186 0 : midas::odb *odb_from_xml(PMXML_NODE node, odb *o) {
1187 0 : std::string type(mxml_get_name(node));
1188 :
1189 0 : unsigned int tid = 0;
1190 0 : if (type == "dir" || type == "odb")
1191 0 : tid = TID_KEY;
1192 : else {
1193 0 : for (tid = 0; tid < TID_LAST; tid++) {
1194 0 : if (equal_ustring(rpc_tid_name(tid), mxml_get_attribute(node, "type")))
1195 0 : break;
1196 : }
1197 : }
1198 0 : if (tid == TID_LAST)
1199 0 : mthrow("Wrong key type in XML file");
1200 :
1201 0 : if (o == nullptr)
1202 0 : o = new midas::odb();
1203 0 : o->set_tid(tid);
1204 0 : if (type == "odb") {
1205 0 : o->set_name("root");
1206 0 : o->set_hkey(0);
1207 : } else {
1208 0 : o->set_name(mxml_get_attribute(node, "name"));
1209 0 : if (mxml_get_attribute(node, "handle") == nullptr)
1210 0 : mthrow("No \"handle\" attribute found in XML data");
1211 0 : o->set_hkey(std::stoi(std::string(mxml_get_attribute(node, "handle"))));
1212 : }
1213 :
1214 0 : if (type == "key") {
1215 0 : std::string value(mxml_get_value(node));
1216 0 : o->set(value);
1217 0 : } else if (type == "keyarray") {
1218 0 : int n = std::atoi(mxml_get_attribute(node, "num_values"));
1219 0 : o->set_num_values(n);
1220 0 : for (int i=0 ; i<n ; i++) {
1221 0 : std::string value(mxml_get_value(mxml_subnode(node, i)));
1222 0 : o->set(value, i);
1223 0 : }
1224 0 : } else if (type == "dir" || type == "odb") {
1225 0 : int n = mxml_get_number_of_children(node);
1226 0 : o->set_num_values(n);
1227 0 : for (int i = 0; i < n; i++) {
1228 0 : midas::odb *os = odb_from_xml(mxml_subnode(node, i), nullptr);
1229 0 : os->set_parent(o);
1230 0 : o->set_odb(os, i);
1231 : }
1232 : } else
1233 0 : mthrow("Unexpected XML element " + std::string(mxml_get_name(node)));
1234 :
1235 0 : return o;
1236 0 : };
1237 :
1238 : // set midas::odb object form a non-array MJsonNode
1239 0 : std::string node_to_string(const MJsonNode* node) {
1240 0 : std::string value;
1241 :
1242 0 : switch (node->GetType()) {
1243 0 : case MJSON_STRING:
1244 0 : value = node->GetString();
1245 0 : break;
1246 0 : case MJSON_INT:
1247 0 : value = std::to_string(node->GetInt());
1248 0 : break;
1249 0 : case MJSON_NUMBER:
1250 0 : value = std::to_string(node->GetDouble());
1251 0 : break;
1252 0 : case MJSON_BOOL:
1253 0 : value = std::to_string(node->GetBool());
1254 0 : break;
1255 0 : default:
1256 0 : mthrow("Invalid MJSON type \"" + std::to_string(node->GetType()) + "\"");
1257 : }
1258 :
1259 0 : return value;
1260 0 : };
1261 :
1262 : // create midas::odb object form MJsonNode
1263 0 : midas::odb *odb_from_json(const MJsonNode* node, std::string name, int tid, odb *o) {
1264 0 : int type = node->GetType();
1265 :
1266 0 : if (type == MJSON_OBJECT) { // subdir
1267 0 : const MJsonStringVector* names = node->GetObjectNames();
1268 0 : const MJsonNodeVector* nodes = node->GetObjectNodes();
1269 0 : if (names == nullptr || nodes==nullptr || names->size() != nodes->size())
1270 0 : mthrow("Invalid JSON format");
1271 :
1272 0 : if (o == nullptr)
1273 0 : o = new midas::odb();
1274 0 : o->set_tid(TID_KEY);
1275 0 : o->set_name(name);
1276 0 : o->set_hkey(0);
1277 :
1278 : // count subkeys
1279 0 : int n=0;
1280 0 : for (int i=0 ; i<(int)names->size() ; i++) {
1281 0 : const char *name = (*names)[i].c_str();
1282 :
1283 0 : if (strchr(name, '/'))// skip special entries
1284 0 : continue;
1285 0 : n++;
1286 : }
1287 0 : o->set_num_values(n);
1288 :
1289 0 : for (int i=n=0 ; i<(int)names->size() ; i++) {
1290 0 : const char *name = (*names)[i].c_str();
1291 :
1292 0 : if (strchr(name, '/'))// skip special entries
1293 0 : continue;
1294 :
1295 0 : int t = 0;
1296 0 : auto key = node->FindObjectNode((std::string(name) + "/key").c_str());
1297 0 : if (key)
1298 0 : t = key->FindObjectNode("type")->GetInt();
1299 : else
1300 0 : t = TID_KEY;
1301 :
1302 0 : midas::odb *os = odb_from_json((*nodes)[i], (*names)[i].c_str(), t, nullptr);
1303 0 : os->set_parent(o);
1304 0 : o->set_odb(os, n);
1305 0 : n++;
1306 : }
1307 :
1308 0 : o->set_num_values(n);
1309 :
1310 : } else { // key
1311 :
1312 0 : if (o == nullptr)
1313 0 : o = new midas::odb();
1314 :
1315 0 : o->set_name(name);
1316 0 : o->set_tid(tid);
1317 0 : o->set_hkey(0);
1318 :
1319 0 : if (node->GetType() == MJSON_ARRAY) {
1320 0 : const MJsonNodeVector* a = node->GetArray();
1321 0 : o->set_num_values(a->size());
1322 0 : for (int i=0 ; i<(int)a->size() ; i++) {
1323 0 : MJsonNode *n = (*a)[i];
1324 0 : auto value = node_to_string(n);
1325 0 : o->set(value, i);
1326 0 : }
1327 : } else {
1328 0 : auto value = node_to_string(node);
1329 0 : o->set(value);
1330 0 : }
1331 : }
1332 :
1333 0 : return o;
1334 : };
1335 :
1336 : // Deep copy
1337 : void deep_copy(odb &d, const odb &s);
1338 :
1339 : // Setters and Getters
1340 2 : bool is_preserve_string_size() const { return m_flags[odb_flags::PRESERVE_STRING_SIZE]; }
1341 2 : void set_preserve_string_size(bool f) {
1342 2 : m_flags[odb_flags::PRESERVE_STRING_SIZE] = f;
1343 2 : set_flags_recursively(get_flags());
1344 2 : }
1345 :
1346 2 : bool is_auto_refresh_read() const { return m_flags[odb_flags::AUTO_REFRESH_READ]; }
1347 0 : void set_auto_refresh_read(bool f) {
1348 0 : m_flags[odb_flags::AUTO_REFRESH_READ] = f;
1349 0 : set_flags_recursively(get_flags());
1350 0 : }
1351 :
1352 2 : bool is_auto_refresh_write() const { return m_flags[odb_flags::AUTO_REFRESH_WRITE]; }
1353 0 : void set_auto_refresh_write(bool f) {
1354 0 : m_flags[odb_flags::AUTO_REFRESH_WRITE] = f;
1355 0 : set_flags_recursively(get_flags());
1356 0 : }
1357 :
1358 : bool is_dirty() const { return m_flags[odb_flags::DIRTY]; }
1359 : void set_dirty(bool f) { m_flags[odb_flags::DIRTY] = f; }
1360 :
1361 0 : bool is_auto_create() const { return m_flags[odb_flags::AUTO_CREATE]; }
1362 0 : void set_auto_create(bool f) {
1363 0 : m_flags[odb_flags::AUTO_CREATE] = f;
1364 0 : set_flags_recursively(get_flags());
1365 0 : }
1366 :
1367 0 : bool is_auto_enlarge_array() const { return m_flags[odb_flags::AUTO_ENLARGE_ARRAY]; }
1368 0 : void set_auto_enlarge_array(bool f) {
1369 0 : m_flags[odb_flags::AUTO_ENLARGE_ARRAY] = f;
1370 0 : set_flags_recursively(get_flags());
1371 0 : }
1372 :
1373 2 : bool is_write_protect() const { return m_flags[odb_flags::WRITE_PROTECT]; }
1374 0 : void set_write_protect(bool f) {
1375 0 : m_flags[odb_flags::WRITE_PROTECT] = f;
1376 0 : set_flags_recursively(get_flags());
1377 0 : }
1378 :
1379 2 : bool is_trigger_hotlink() const { return m_flags[odb_flags::TRIGGER_HOTLINK]; }
1380 0 : void set_trigger_hotlink(bool f) {
1381 0 : m_flags[odb_flags::TRIGGER_HOTLINK] = f;
1382 0 : set_flags_recursively(get_flags());
1383 0 : }
1384 :
1385 : // Static functions
1386 0 : static void set_debug(bool flag) { s_debug = flag; }
1387 0 : static bool get_debug() { return s_debug; }
1388 : static int create(const char *name, int type = TID_KEY);
1389 : static bool exists(const std::string &name);
1390 : static int delete_key(const std::string &name);
1391 : static void load(const std::string &filename, const std::string &odb_path);
1392 :
1393 : void odb_from_xml_remote(const std::string &str);
1394 : void odb_from_xml_string(const std::string &str, const std::string &subkey);
1395 : void odb_from_json_string(const std::string &str, const std::string &subkey);
1396 : void connect(const std::string &path, const std::string &name, bool write_defaults, bool delete_keys_not_in_defaults = false);
1397 : void connect(std::string str, bool write_defaults = false, bool delete_keys_not_in_defaults = false);
1398 : void connect_and_fix_structure(std::string path);
1399 :
1400 : static odb::odb_source get_odb_source() { return s_odb_source; }
1401 : static void set_odb_source(odb::odb_source s) {
1402 : if (s == STRING)
1403 : mthrow1("ODB source STRING requires a string");
1404 : if (s == FILE)
1405 : mthrow1("ODB source FILE requires a filename");
1406 : s_odb_source = s;
1407 : }
1408 0 : static void set_odb_source(odb::odb_source s, std::string str) {
1409 0 : if (s == odb::FILE) {
1410 : // check file contents
1411 0 : std::ifstream file(str);
1412 0 : if (!file)
1413 0 : mthrow("File \"" + str + "\" not found");
1414 0 : std::ostringstream ss;
1415 0 : ss << file.rdbuf();
1416 0 : if (str.find(".xml") == std::string::npos &&
1417 0 : str.find(".XML") == std::string::npos &&
1418 0 : str.find(".json") == std::string::npos &&
1419 0 : str.find(".JSON") == std::string::npos)
1420 0 : mthrow("File type of \"" + str + "\" is not supported");
1421 0 : }
1422 :
1423 0 : s_odb_source = s;
1424 0 : s_odb_source_str = str;
1425 0 : }
1426 :
1427 42 : static bool is_connected_odb() { return s_connected_odb; }
1428 :
1429 : void read();
1430 : void read(int index);
1431 : void write(int str_size = 0);
1432 : void write(int index, int str_size);
1433 : std::string print();
1434 : std::string dump();
1435 : void print(std::string &s, int indent=0);
1436 : void dump(std::string &s, int indent=0);
1437 : void save(const std::string &filename);
1438 : void delete_key();
1439 : int size();
1440 : void resize(int size);
1441 : void resize(int size, bool b);
1442 : void watch(std::function<void(midas::odb &)> f);
1443 : void unwatch();
1444 : void set(std::string str);
1445 : void set(std::string s, int i);
1446 : void set_odb(odb *o, int i);
1447 : void set_string_size(std::string s, int size);
1448 :
1449 : bool is_subkey(std::string str);
1450 0 : HNDLE get_hkey() { return m_hKey; }
1451 : std::string get_full_path();
1452 : std::string get_parent_path();
1453 36 : int get_tid() { return m_tid; }
1454 0 : int get_num_values() { return m_num_values; }
1455 34 : std::string get_name() { return m_name; }
1456 : odb& items() { return *this; }
1457 :
1458 0 : std::string s() {
1459 0 : std::string s;
1460 0 : get(s);
1461 0 : return s;
1462 0 : }
1463 :
1464 : void fix_order(std::vector<std::string> target_subkey_order);
1465 :
1466 : void set_mode(int mode);
1467 : int get_mode();
1468 :
1469 : unsigned int get_last_written();
1470 : };
1471 :
1472 : //---- midas::odb friend functions -------------------------------
1473 :
1474 : // overload comparison operators
1475 : template<typename T>
1476 2 : bool operator==(const midas::odb &o, const T &d) {
1477 : // the operator needs a "const midas::odb" reference,
1478 : // so we have to make a non-const copy
1479 2 : T v;
1480 2 : midas::odb oc(o);
1481 2 : oc.get(v);
1482 4 : return v == d;
1483 2 : }
1484 :
1485 : template<typename T>
1486 : bool operator==(const T &d, const midas::odb &o) {
1487 : T v;
1488 : midas::odb oc(o);
1489 : oc.get(v);
1490 : return d == v;
1491 : }
1492 :
1493 : template<typename T>
1494 0 : bool operator!=(const midas::odb &o, const T &d) {
1495 0 : T v;
1496 0 : midas::odb oc(o);
1497 0 : oc.get(v);
1498 0 : return v != d;
1499 0 : }
1500 :
1501 : template<typename T>
1502 : bool operator!=(const T &d, const midas::odb &o) {
1503 : T v;
1504 : midas::odb oc(o);
1505 : oc.get(v);
1506 : return d != v;
1507 : }
1508 :
1509 : template<typename T>
1510 : bool operator<(const midas::odb &o, const T &d) {
1511 : T v;
1512 : midas::odb oc(o);
1513 : oc.get(v);
1514 : return v < d;
1515 : }
1516 :
1517 : template<typename T>
1518 : bool operator<(const T &d, const midas::odb &o) {
1519 : T v;
1520 : midas::odb oc(o);
1521 : oc.get(v);
1522 : return d < v;
1523 : }
1524 :
1525 : template<typename T>
1526 : bool operator<=(const midas::odb &o, const T &d) {
1527 : T v;
1528 : midas::odb oc(o);
1529 : oc.get(v);
1530 : return v <= d;
1531 : }
1532 :
1533 : template<typename T>
1534 : bool operator<=(const T &d, const midas::odb &o) {
1535 : T v;
1536 : midas::odb oc(o);
1537 : oc.get(v);
1538 : return d <= v;
1539 : }
1540 :
1541 : template<typename T>
1542 0 : bool operator>(const midas::odb &o, const T &d) {
1543 : T v;
1544 0 : midas::odb oc(o);
1545 0 : oc.get(v);
1546 0 : return v > d;
1547 0 : }
1548 :
1549 : template<typename T>
1550 0 : bool operator>(const T &d, const midas::odb &o) {
1551 : T v;
1552 0 : midas::odb oc(o);
1553 0 : oc.get(v);
1554 0 : return d > v;
1555 0 : }
1556 :
1557 : template<typename T>
1558 : bool operator>=(const midas::odb &o, const T &d) {
1559 : T v;
1560 : midas::odb oc(o);
1561 : oc.get(v);
1562 : return v >= d;
1563 : }
1564 :
1565 : template<typename T>
1566 0 : bool operator>=(const T &d, const midas::odb &o) {
1567 : T v;
1568 0 : midas::odb oc(o);
1569 0 : oc.get(v);
1570 0 : return d >= v;
1571 0 : }
1572 :
1573 : } // namespace midas
1574 :
1575 :
1576 : #endif // _ODBXX_HXX
|