univalue.h raw

   1  // Copyright 2014 BitPay Inc.
   2  // Copyright 2015 Bitcoin Core Developers
   3  // Distributed under the MIT software license, see the accompanying
   4  // file COPYING or https://opensource.org/licenses/mit-license.php.
   5  
   6  #ifndef BITCOIN_UNIVALUE_INCLUDE_UNIVALUE_H
   7  #define BITCOIN_UNIVALUE_INCLUDE_UNIVALUE_H
   8  
   9  #include <charconv>
  10  #include <cstddef>
  11  #include <cstdint>
  12  #include <map>
  13  #include <stdexcept>
  14  #include <string>
  15  #include <string_view>
  16  #include <system_error>
  17  #include <type_traits>
  18  #include <utility>
  19  #include <vector>
  20  
  21  // NOLINTNEXTLINE(misc-no-recursion)
  22  class UniValue {
  23  public:
  24      enum VType { VNULL, VOBJ, VARR, VSTR, VNUM, VBOOL, };
  25  
  26      class type_error : public std::runtime_error
  27      {
  28          using std::runtime_error::runtime_error;
  29      };
  30  
  31      UniValue() { typ = VNULL; }
  32      UniValue(UniValue::VType type, std::string str = {}) : typ{type}, val{std::move(str)} {}
  33      template <typename Ref, typename T = std::remove_cv_t<std::remove_reference_t<Ref>>,
  34                std::enable_if_t<std::is_floating_point_v<T> ||                      // setFloat
  35                                     std::is_same_v<bool, T> ||                      // setBool
  36                                     std::is_signed_v<T> || std::is_unsigned_v<T> || // setInt
  37                                     std::is_constructible_v<std::string, T>,        // setStr
  38                                 bool> = true>
  39      UniValue(Ref&& val)
  40      {
  41          if constexpr (std::is_floating_point_v<T>) {
  42              setFloat(val);
  43          } else if constexpr (std::is_same_v<bool, T>) {
  44              setBool(val);
  45          } else if constexpr (std::is_signed_v<T>) {
  46              setInt(int64_t{val});
  47          } else if constexpr (std::is_unsigned_v<T>) {
  48              setInt(uint64_t{val});
  49          } else {
  50              setStr(std::string{std::forward<Ref>(val)});
  51          }
  52      }
  53  
  54      void clear();
  55  
  56      void setNull();
  57      void setBool(bool val);
  58      void setNumStr(std::string str);
  59      void setInt(uint64_t val);
  60      void setInt(int64_t val);
  61      void setInt(int val_) { return setInt(int64_t{val_}); }
  62      void setFloat(double val);
  63      void setStr(std::string str);
  64      void setArray();
  65      void setObject();
  66  
  67      enum VType getType() const { return typ; }
  68      const std::string& getValStr() const { return val; }
  69      bool empty() const { return (values.size() == 0); }
  70  
  71      size_t size() const { return values.size(); }
  72  
  73      void reserve(size_t new_cap);
  74  
  75      void getObjMap(std::map<std::string,UniValue>& kv) const;
  76      bool checkObject(const std::map<std::string,UniValue::VType>& memberTypes) const;
  77      const UniValue& operator[](const std::string& key) const;
  78      const UniValue& operator[](size_t index) const;
  79      bool exists(const std::string& key) const { size_t i; return findKey(key, i); }
  80  
  81      bool isNull() const { return (typ == VNULL); }
  82      bool isTrue() const { return (typ == VBOOL) && (val == "1"); }
  83      bool isFalse() const { return (typ == VBOOL) && (val != "1"); }
  84      bool isBool() const { return (typ == VBOOL); }
  85      bool isStr() const { return (typ == VSTR); }
  86      bool isNum() const { return (typ == VNUM); }
  87      bool isArray() const { return (typ == VARR); }
  88      bool isObject() const { return (typ == VOBJ); }
  89  
  90      void push_back(UniValue val);
  91      void push_backV(const std::vector<UniValue>& vec);
  92      template <class It>
  93      void push_backV(It first, It last);
  94  
  95      void pushKVEnd(std::string key, UniValue val);
  96      void pushKV(std::string key, UniValue val);
  97      void pushKVs(UniValue obj);
  98  
  99      std::string write(unsigned int prettyIndent = 0,
 100                        unsigned int indentLevel = 0) const;
 101  
 102      bool read(std::string_view raw);
 103  
 104  private:
 105      UniValue::VType typ;
 106      std::string val;                       // numbers are stored as C++ strings
 107      std::vector<std::string> keys;
 108      std::vector<UniValue> values;
 109  
 110      void checkType(const VType& expected) const;
 111      bool findKey(const std::string& key, size_t& retIdx) const;
 112      void writeArray(unsigned int prettyIndent, unsigned int indentLevel, std::string& s) const;
 113      void writeObject(unsigned int prettyIndent, unsigned int indentLevel, std::string& s) const;
 114  
 115  public:
 116      // Strict type-specific getters, these throw std::runtime_error if the
 117      // value is of unexpected type
 118      const std::vector<std::string>& getKeys() const;
 119      const std::vector<UniValue>& getValues() const;
 120      template <typename Int>
 121      Int getInt() const;
 122      bool get_bool() const;
 123      const std::string& get_str() const;
 124      double get_real() const;
 125      const UniValue& get_obj() const;
 126      const UniValue& get_array() const;
 127  
 128      enum VType type() const { return getType(); }
 129      const UniValue& find_value(std::string_view key) const;
 130  };
 131  
 132  template <class It>
 133  void UniValue::push_backV(It first, It last)
 134  {
 135      checkType(VARR);
 136      values.insert(values.end(), first, last);
 137  }
 138  
 139  template <typename Int>
 140  Int UniValue::getInt() const
 141  {
 142      static_assert(std::is_integral_v<Int>);
 143      checkType(VNUM);
 144      Int result;
 145      const auto [first_nonmatching, error_condition] = std::from_chars(val.data(), val.data() + val.size(), result);
 146      if (first_nonmatching != val.data() + val.size() || error_condition != std::errc{}) {
 147          throw std::runtime_error("JSON integer out of range");
 148      }
 149      return result;
 150  }
 151  
 152  enum jtokentype {
 153      JTOK_ERR        = -1,
 154      JTOK_NONE       = 0,                           // eof
 155      JTOK_OBJ_OPEN,
 156      JTOK_OBJ_CLOSE,
 157      JTOK_ARR_OPEN,
 158      JTOK_ARR_CLOSE,
 159      JTOK_COLON,
 160      JTOK_COMMA,
 161      JTOK_KW_NULL,
 162      JTOK_KW_TRUE,
 163      JTOK_KW_FALSE,
 164      JTOK_NUMBER,
 165      JTOK_STRING,
 166  };
 167  
 168  extern enum jtokentype getJsonToken(std::string& tokenVal,
 169                                      unsigned int& consumed, const char *raw, const char *end);
 170  extern const char *uvTypeName(UniValue::VType t);
 171  
 172  static inline bool jsonTokenIsValue(enum jtokentype jtt)
 173  {
 174      switch (jtt) {
 175      case JTOK_KW_NULL:
 176      case JTOK_KW_TRUE:
 177      case JTOK_KW_FALSE:
 178      case JTOK_NUMBER:
 179      case JTOK_STRING:
 180          return true;
 181  
 182      default:
 183          return false;
 184      }
 185  
 186      // not reached
 187  }
 188  
 189  static inline bool json_isspace(int ch)
 190  {
 191      switch (ch) {
 192      case 0x20:
 193      case 0x09:
 194      case 0x0a:
 195      case 0x0d:
 196          return true;
 197  
 198      default:
 199          return false;
 200      }
 201  
 202      // not reached
 203  }
 204  
 205  extern const UniValue NullUniValue;
 206  
 207  #endif // BITCOIN_UNIVALUE_INCLUDE_UNIVALUE_H
 208