/ src / univalue / include / univalue.h
univalue.h
  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