libfilezilla
json.hpp
Go to the documentation of this file.
1 #ifndef LIBFILEZILLA_JSON_HEADER
2 #define LIBFILEZILLA_JSON_HEADER
3 
7 #include "string.hpp"
8 
9 #include <limits.h>
10 #include <map>
11 #include <optional>
12 #include <type_traits>
13 #include <variant>
14 
15 namespace fz {
16 
18 enum class json_type {
19  none,
20  null,
21  object,
22  array,
23  string,
24  number,
25  boolean
26 };
27 
28 class buffer;
29 
32 class FZ_PUBLIC_SYMBOL json final
33 {
34 public:
35  json() noexcept = default;
36  json(json const&) = default;
37  json(json &&) noexcept = default;
38 
40  explicit json(json_type t);
41 
42  json_type type() const {
43  return static_cast<json_type>(value_.index());
44  }
45 
47  std::string string_value() const;
48 
50  std::wstring wstring_value() const {
51  return fz::to_wstring_from_utf8(string_value());
52  }
53 
54 
56  template<typename T, std::enable_if_t<std::is_integral_v<typename std::decay_t<T>>, int> = 0>
57  T number_value(T errorval = {}) const {
58  auto v = number_value_o<T>();
59  if (v) {
60  return *v;
61  }
62  return errorval;
63  }
64 
65  template<typename T, std::enable_if_t<std::is_integral_v<typename std::decay_t<T>>, int> = 0>
66  std::optional<T> number_value_o() const {
67  bool constexpr is_signed = std::is_signed_v<typename std::decay_t<T>>;
68  if constexpr (is_signed) {
69  std::optional<int64_t> tmp = number_value_integer_s();
70  if (tmp) {
71  if (tmp >= std::numeric_limits<T>::min() && tmp <= std::numeric_limits<T>::max()) {
72  return static_cast<T>(*tmp);
73  }
74  }
75  }
76  else {
77  std::optional<uint64_t> tmp = number_value_integer_u();
78  if (tmp) {
79  if (tmp <= std::numeric_limits<T>::max()) {
80  return static_cast<T>(*tmp);
81  }
82  }
83  }
84 
85  return {};
86  }
87 
89  template<typename T, std::enable_if_t<std::is_floating_point_v<typename std::decay_t<T>>, int> = 0>
90  T number_value() const {
91  return static_cast<T>(number_value_double());
92  }
93 
95  bool bool_value() const;
96 
98  void erase(std::string const& name);
99 
101  json const& operator[](std::string const& name) const;
102 
109  json& operator[](std::string const& name);
110 
112  json const& operator[](size_t i) const;
113 
120  json& operator[](size_t i);
121 
123  size_t children() const;
124 
126  template<typename Bool, std::enable_if_t<std::is_same_v<bool, typename std::decay_t<Bool>>, int> = 0>
127  json& operator=(Bool b) {
128  value_ = b;
129  return *this;
130  }
131 
133  template<typename T, std::enable_if_t<std::is_integral_v<T> && !std::is_same_v<bool, typename std::decay_t<T>>, int> = 0>
134  json& operator=(T n) {
135  value_.emplace<std::size_t(json_type::number)>(fz::to_string(n));
136  return *this;
137  }
138 
143  json& operator=(std::string_view const& v);
144 
146  json& operator=(std::wstring_view const& v) {
147  return *this = to_utf8(v);
148  }
149 
150  json& operator=(json const&);
151  json& operator=(json &&) noexcept;
152 
153  explicit operator bool() const { return type() != json_type::none; }
154 
155  bool has_non_null_value() const {
156  return type() != fz::json_type::none && type() != fz::json_type::null;
157  }
158 
159  bool is_null() const { return type() == fz::json_type::null; }
160  bool is_object() const { return type() == fz::json_type::object; }
161  bool is_array() const { return type() == fz::json_type::array; }
162  bool is_number() const { return type() == fz::json_type::number; }
163  bool is_boolean() const { return type() == fz::json_type::boolean; }
164 
170  std::string to_string(bool pretty = false, size_t depth = 0) const;
171 
179  void to_string(std::string & ret, bool pretty = false, size_t depth = 0) const;
180 
185  static json parse(std::string_view const& v, size_t max_depth = 20);
186  static json parse(fz::buffer const& b, size_t max_depth = 20);
187 
188  void clear();
189 
190 private:
191  void to_string_impl(std::string & ret, bool pretty = false, size_t depth = 0) const;
192 
193  std::optional<int64_t> number_value_integer_s() const;
194  std::optional<uint64_t> number_value_integer_u() const;
195  double number_value_double() const;
196 
197  bool FZ_PRIVATE_SYMBOL check_type(json_type t);
198  void FZ_PRIVATE_SYMBOL set_type(json_type t);
199 
200  static json FZ_PRIVATE_SYMBOL parse(char const*& p, char const* end, size_t max_depth);
201 
202  typedef std::variant<
203  std::monostate, // json_type::none
204  std::nullptr_t, // json_type::null
205  std::map<std::string, json, std::less<>>, // json_type::object
206  std::vector<json>, // json_type::array
207  std::string, // json_type::string,
208  std::string, // json_type::number,
209  bool // json_type::boolean
210  > value_type;
211  value_type value_;
212 };
213 
214 template <bool isconst>
215 struct json_array_iterator final {
216  using json_ref_t = std::conditional_t<isconst, json const&, json &>;
217 
218  struct sentinel final {};
219 
220  json_array_iterator(json_ref_t j)
221  // 0 if it's an array, -1 otherwise
222  : idx_((j.type() == json_type::array)-1)
223  , json_(j)
224  {}
225 
226  json_array_iterator & operator++()
227  {
228  ++idx_;
229 
230  return *this;
231  }
232 
233  json_ref_t operator*() const
234  {
235  return json_[idx_];
236  }
237 
238  bool operator!=(json_array_iterator::sentinel const&) const
239  {
240  return idx_ < json_.children();
241  }
242 
243 private:
244  std::size_t idx_;
245  json_ref_t json_;
246 };
247 
248 inline json_array_iterator<false> begin(json &j) { return {j}; }
249 inline json_array_iterator<false>::sentinel end(json &) { return {}; }
250 
251 inline json_array_iterator<true> begin(json const& j) { return {j}; }
252 inline json_array_iterator<true>::sentinel end(json const&) { return {}; }
253 
254 }
255 
256 #endif
T number_value(T errorval={}) const
Returns number and string values as the passed integer type.
Definition: json.hpp:57
json & operator=(T n)
Sets type to number and assigns value.
Definition: json.hpp:134
std::wstring wstring_value() const
Returns string, number and boolean values as wstring.
Definition: json.hpp:50
std::string to_utf8(std::string_view const &in)
Converts from std::string in native encoding into std::string in UTF-8.
The explicit null value.
Definition: json.hpp:215
std::wstring to_wstring_from_utf8(std::string_view const &in)
Converts from std::string in UTF-8 into std::wstring.
Definition: json.hpp:218
String types and assorted functions.
json parser/builder
Definition: json.hpp:32
The namespace used by libfilezilla.
Definition: apply.hpp:17
json_type
Types of JSON values.
Definition: json.hpp:18
json & operator=(std::wstring_view const &v)
Sets type to string and assigns value.
Definition: json.hpp:146
The buffer class is a simple buffer where data can be appended at the end and consumed at the front...
Definition: buffer.hpp:26
Not a JSON value.
json & operator=(Bool b)
Sets type to boolean and assigns value.
Definition: json.hpp:127
T number_value() const
Returns number and string values as the passed floating point type.
Definition: json.hpp:90
std::string to_string(std::wstring_view const &in)
Converts from std::wstring into std::string in system encoding.