LCOV - code coverage report
Current view: top level - include - odbxx.h (source / functions) Coverage Total Hit
Test: coverage.info Lines: 14.9 % 653 97
Test Date: 2025-11-11 10:26:08 Functions: 19.9 % 156 31

            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
        

Generated by: LCOV version 2.0-1