Apache Mesos
jsonify.hpp
Go to the documentation of this file.
1 // Licensed under the Apache License, Version 2.0 (the "License");
2 // you may not use this file except in compliance with the License.
3 // You may obtain a copy of the License at
4 //
5 // http://www.apache.org/licenses/LICENSE-2.0
6 //
7 // Unless required by applicable law or agreed to in writing, software
8 // distributed under the License is distributed on an "AS IS" BASIS,
9 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10 // See the License for the specific language governing permissions and
11 // limitations under the License.
12 
13 #ifndef __STOUT_JSONIFY__
14 #define __STOUT_JSONIFY__
15 
16 #define RAPIDJSON_HAS_STDSTRING 1
17 #define RAPIDJSON_WRITE_DEFAULT_FLAGS kWriteNanAndInfFlag
18 
19 // TODO(bmahler): Consider enabling UTF-8 validation when writing
20 // json. Prior to the introduction of rapidjson, we performed no
21 // validation, so we maintain this status quo for now.
22 //
23 // #define RAPIDJSON_WRITE_DEFAULT_FLAGS 1 // kWriteValidateEncodingFlag
24 
25 // TODO(bmahler): Consider enabling SIMD for rapidjson, unfortunately
26 // it showed slightly slower results on the serialization path when
27 // benchmarked so I've left it disabled.
28 //
29 // #if defined(__SSE4_2__)
30 // # define RAPIDJSON_SSE42
31 // #elif defined(__SSE2__)
32 // # define RAPIDJSON_SSE2
33 // #elif defined(_MSC_VER) // Turn on SSE4.2 for VC
34 // # define RAPIDJSON_SSE42
35 // #endif
36 
37 #include <rapidjson/stringbuffer.h>
38 #include <rapidjson/writer.h>
39 
40 #include <cstddef>
41 #include <functional>
42 #include <ostream>
43 #include <string>
44 #include <type_traits>
45 #include <utility>
46 
47 #include <stout/check.hpp>
48 #include <stout/result_of.hpp>
49 #include <stout/strings.hpp>
50 
51 // `jsonify` takes an instance of a C++ object and returns a light-weight proxy
52 // object that can either be implicitly converted to a `std::string`, or
53 // directly inserted into an output stream.
54 //
55 // `jsonify(const T&)` is implemented by calling the function `json`.
56 // We perform unqualified function call so that it can detect overloads via
57 // argument dependent lookup. That is, we will search for, and use a free
58 // function named `json` in the same namespace as `T`.
59 //
60 // NOTE: This relationship is similar to `boost::hash` and `hash_value`.
61 //
62 // IMPORTANT: The output stream must not be exception-enabled. This is because
63 // the writer definitions below insert into the output stream in their
64 // destructors.
65 //
66 // Refer to https://github.com/apache/mesos/tree/master/3rdparty/stout#jsonify
67 // for more information.
68 
69 // Forward declaration of `JSON::Proxy`.
70 namespace JSON { class Proxy; }
71 
72 // Forward declaration of `jsonify`.
73 template <typename T>
74 JSON::Proxy jsonify(const T&);
75 
76 namespace JSON {
77 
78 // The result of `jsonify`. This is a light-weight proxy object that can either
79 // be implicitly converted to a `std::string`, or directly inserted into an
80 // output stream.
81 //
82 // In order to make this object light-weight, variables are captured by
83 // reference. This gives rise to similar semantics as `std::forward_as_tuple`.
84 // If the arguments are temporaries, `JSON::Proxy` does not extend their
85 // lifetime; they have to be used before the end of the full expression.
86 class Proxy
87 {
88 public:
89  operator std::string() &&
90  {
91  rapidjson::StringBuffer buffer;
92  rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
93 
94  write(&writer);
95 
96  return {buffer.GetString(), buffer.GetSize()};
97  }
98 
99 private:
100  Proxy(std::function<void(rapidjson::Writer<rapidjson::StringBuffer>*)> write)
101  : write(std::move(write)) {}
102 
103  // We declare copy/move constructors `private` to prevent statements that try
104  // to "save" an instance of `Proxy` such as:
105  //
106  // ```
107  // std::string F();
108  // Proxy proxy = jsonify(F());
109  // ```
110  //
111  // Since `proxy` in the above example would be holding onto a reference to a
112  // temporary string returned by `F()`.
113  Proxy(const Proxy&) = default;
114  Proxy(Proxy&&) = default;
115 
116  template <typename T>
117  friend Proxy (::jsonify)(const T&);
118 
119  friend std::ostream& operator<<(std::ostream& stream, Proxy&& that);
120 
121 public:
122  // This is public in order to enable the `ObjectWriter` and `ArrayWriter`
123  // to continue writing to the same writer.
124  std::function<void(rapidjson::Writer<rapidjson::StringBuffer>*)> write;
125 };
126 
127 
128 inline std::ostream& operator<<(std::ostream& stream, Proxy&& that)
129 {
130  return stream << std::string(std::move(that));
131 }
132 
133 
134 // The boolean writer. If `set` is not called at all, a false value is
135 // written. If `set` is called more than once, only the last value is
136 // written.
138 {
139 public:
140  BooleanWriter(rapidjson::Writer<rapidjson::StringBuffer>* writer)
141  : writer_(writer), value_(false) {}
142 
143  BooleanWriter(const BooleanWriter&) = delete;
144  BooleanWriter(BooleanWriter&&) = delete;
145 
146  ~BooleanWriter() { CHECK(writer_->Bool(value_)); }
147 
148  BooleanWriter& operator=(const BooleanWriter&) = delete;
149  BooleanWriter& operator=(BooleanWriter&&) = delete;
150 
151  void set(bool value) { value_ = value; }
152 
153 private:
154  rapidjson::Writer<rapidjson::StringBuffer>* writer_;
155  bool value_;
156 };
157 
158 
159 // The number writer. If `set` is not called at all, `0` is written.
160 // If `set` is called more than once, only the last value is written.
162 {
163 public:
164  NumberWriter(rapidjson::Writer<rapidjson::StringBuffer>* writer)
165  : writer_(writer), type_(INT), int_(0) {}
166 
167  NumberWriter(const NumberWriter&) = delete;
168  NumberWriter(NumberWriter&&) = delete;
169 
171  {
172  switch (type_) {
173  case INT: CHECK(writer_->Int64(int_)); break;
174  case UINT: CHECK(writer_->Uint64(uint_)); break;
175  case DOUBLE: CHECK(writer_->Double(double_)); break;
176  }
177  }
178 
179  NumberWriter& operator=(const NumberWriter&) = delete;
180  NumberWriter& operator=(NumberWriter&&) = delete;
181 
182  // NOTE 1: We enumerate overloads for all of the integral types here to avoid
183  // ambiguities between signed and unsigned conversions. If we were to only
184  // overload for `long long int` and `unsigned long long int`, passing an
185  // argument of `0` would be ambiguous since `0` has type `int`, and cost of
186  // conversion to `long long int` or `unsigned long long int` is equivalent.
187 
188  // NOTE 2: We use the various modifiers on `int` as opposed to fixed size
189  // types such as `int32_t` and `int64_t` because these types do not cover all
190  // of the integral types. For example, `uint32_t` may map to `unsigned int`,
191  // and `uint64_t` to `unsigned long long int`. If `size_t` maps to `unsigned
192  // long int`, it is ambiguous to pass an instance of `size_t`. defining an
193  // overload for `size_t` would solve the problem on a specific platform, but
194  // we can run into issues again on another platform if `size_t` maps to
195  // `unsigned long long int`, since we would get a redefinition error.
196 
197  void set(short int value) { set(static_cast<long long int>(value)); }
198 
199  void set(int value) { set(static_cast<long long int>(value)); }
200 
201  void set(long int value) { set(static_cast<long long int>(value)); }
202 
203  void set(long long int value)
204  {
205  type_ = INT;
206  int_ = value;
207  }
208 
209  void set(unsigned short int value)
210  {
211  set(static_cast<unsigned long long int>(value));
212  }
213 
214  void set(unsigned int value)
215  {
216  set(static_cast<unsigned long long int>(value));
217  }
218 
219  void set(unsigned long int value)
220  {
221  set(static_cast<unsigned long long int>(value));
222  }
223 
224  void set(unsigned long long int value)
225  {
226  type_ = UINT;
227  uint_ = value;
228  }
229 
230  void set(float value) { set(static_cast<double>(value)); }
231 
232  void set(double value)
233  {
234  type_ = DOUBLE;
235  double_ = value;
236  }
237 
238 private:
239  rapidjson::Writer<rapidjson::StringBuffer>* writer_;
240 
241  enum { INT, UINT, DOUBLE } type_;
242 
243  union
244  {
245  long long int int_;
246  unsigned long long int uint_;
247  double double_;
248  };
249 };
250 
251 
252 // The string writer. `set` is used to write a string and must only
253 // be called once. If `set` is not called at all, an empty JSON
254 // string is written.
256 {
257 public:
258  StringWriter(rapidjson::Writer<rapidjson::StringBuffer>* writer)
259  : writer_(writer), empty_(true) {}
260 
261  StringWriter(const StringWriter&) = delete;
262  StringWriter(StringWriter&&) = delete;
263 
264  ~StringWriter() { if (empty_) { CHECK(writer_->String("")); } }
265 
266  StringWriter& operator=(const StringWriter&) = delete;
267  StringWriter& operator=(StringWriter&&) = delete;
268 
269  template <std::size_t N>
270  void set(const char (&value)[N])
271  {
272  empty_ = false;
273 
274  // This check will fail if we enable write validation in rapidjson;
275  // we'll need to figure out a way to surface the error.
276  CHECK(writer_->String(value, N-1));
277  }
278 
279  void set(const std::string& value)
280  {
281  empty_ = false;
282 
283  // This check will fail if we enable write validation in rapidjson;
284  // we'll need to figure out a way to surface the error.
285  CHECK(writer_->String(value));
286  }
287 
288 private:
289  rapidjson::Writer<rapidjson::StringBuffer>* writer_;
290  bool empty_;
291 };
292 
293 
294 // The array writer. `element(value)` is used to write a new element.
295 // If `element` is not called at all, an empty JSON array is written.
297 {
298 public:
299  ArrayWriter(rapidjson::Writer<rapidjson::StringBuffer>* writer)
300  : writer_(writer)
301  {
302  CHECK(writer_->StartArray());
303  }
304 
305  ArrayWriter(const ArrayWriter&) = delete;
306  ArrayWriter(ArrayWriter&&) = delete;
307 
309  {
310  CHECK(writer_->EndArray());
311  }
312 
313  ArrayWriter& operator=(const ArrayWriter&) = delete;
314  ArrayWriter& operator=(ArrayWriter&&) = delete;
315 
316  template <typename T>
317  void element(const T& value) { jsonify(value).write(writer_); }
318 
319 private:
320  rapidjson::Writer<rapidjson::StringBuffer>* writer_;
321 };
322 
323 
324 // The object writer. `field(key, value)` is used to write a new field.
325 // If `field` is not called at all, an empty JSON object is written.
327 {
328 public:
329  ObjectWriter(rapidjson::Writer<rapidjson::StringBuffer>* writer)
330  : writer_(writer)
331  {
332  CHECK(writer_->StartObject());
333  }
334 
335  ObjectWriter(const ObjectWriter&) = delete;
336  ObjectWriter(ObjectWriter&&) = delete;
337 
339  {
340  CHECK(writer_->EndObject());
341  }
342 
343  ObjectWriter& operator=(const ObjectWriter&) = delete;
344  ObjectWriter& operator=(ObjectWriter&&) = delete;
345 
346  template <typename T>
347  void field(const std::string& key, const T& value)
348  {
349  // This check will fail we enable write validation in rapidjson;
350  // we'll need to figure out a way to surface the error.
351  //
352  // TODO(bmahler): The 1.1.0 release of rapidjson did not
353  // yet have the std::string overload for `Key`, avoid calling
354  // `c_str()` and `size()` when we upgrade beyond 1.1.0.
355  CHECK(writer_->Key(key.c_str(), key.size()));
356  jsonify(value).write(writer_);
357  }
358 
359 private:
360  rapidjson::Writer<rapidjson::StringBuffer>* writer_;
361 };
362 
363 
365 {
366 public:
367  NullWriter(rapidjson::Writer<rapidjson::StringBuffer>* writer)
368  : writer_(writer) {}
369 
370  NullWriter(const NullWriter&) = delete;
371  NullWriter(NullWriter&&) = delete;
372 
373  ~NullWriter() { CHECK(writer_->Null()); }
374 
375  NullWriter& operator=(const NullWriter&) = delete;
376  NullWriter& operator=(NullWriter&&) = delete;
377 
378 private:
379  rapidjson::Writer<rapidjson::StringBuffer>* writer_;
380 };
381 
382 
383 // `json` function for boolean.
384 inline void json(BooleanWriter* writer, bool value) { writer->set(value); }
385 
386 
387 // `json` functions for numbers.
388 inline void json(NumberWriter* writer, short int value) { writer->set(value); }
389 inline void json(NumberWriter* writer, int value) { writer->set(value); }
390 inline void json(NumberWriter* writer, long int value) { writer->set(value); }
391 
392 
393 inline void json(NumberWriter* writer, long long int value)
394 {
395  writer->set(value);
396 }
397 
398 
399 inline void json(NumberWriter* writer, unsigned short int value)
400 {
401  writer->set(value);
402 }
403 
404 
405 inline void json(NumberWriter* writer, unsigned int value)
406 {
407  writer->set(value);
408 }
409 
410 
411 inline void json(NumberWriter* writer, unsigned long int value)
412 {
413  writer->set(value);
414 }
415 
416 
417 inline void json(NumberWriter* writer, unsigned long long int value)
418 {
419  writer->set(value);
420 }
421 
422 
423 inline void json(NumberWriter* writer, float value) { writer->set(value); }
424 inline void json(NumberWriter* writer, double value) { writer->set(value); }
425 
426 
427 // `json` functions for strings.
428 
429 template <std::size_t N>
430 void json(StringWriter* writer, const char (&value)[N])
431 {
432  writer->set(value);
433 }
434 
435 
436 inline void json(StringWriter* writer, const std::string& value)
437 {
438  writer->set(value);
439 }
440 
441 namespace internal {
442 
443 // TODO(mpark): Pull this out to something like <stout/meta.hpp>.
444 // This pattern already exists in `<process/future.hpp>`.
445 struct LessPrefer {};
446 struct Prefer : LessPrefer {};
447 
448 // The member `value` is `true` if `T` is a sequence, and `false` otherwise.
449 template <typename T>
451 {
452 private:
453  // This overload only participates in overload resolution if the following
454  // expressions are valid.
455  // (1) begin(t) != end(t)
456  // (2) auto iter = begin(t); ++iter
457  // (3) *begin(t)
458  //
459  // The expressions are only used for SFINAE purposes, and comma operators are
460  // used to ignore the results of the expressions. That is, the return type of
461  // this function is `decltype(expr0, expr1, expr2, std::true_type{})` which is
462  // `std::true_type`.
463  template <typename U>
464  static auto test(Prefer) -> decltype(
465  // Cast to `void` to suppress `-Wunused-comparison` warnings.
466  void(std::begin(std::declval<U&>()) != std::end(std::declval<U&>())),
467  ++std::declval<decltype(std::begin(std::declval<U&>()))&>(),
468  *std::begin(std::declval<U&>()),
469  std::true_type{});
470 
471  // This overload is chosen if the preferred version is SFINAE'd out.
472  template <typename U>
473  static std::false_type test(LessPrefer);
474 
475 public:
476  static constexpr bool value = decltype(test<T>(Prefer()))::value;
477 };
478 
479 
480 // The member `value` is `true` if `T` has a member typedef `mapped_type`, and
481 // `false` otherwise. We take the existence of `mapped_type` as the indication
482 // of an associative container (e.g., std::map).
483 template <typename T>
485 {
486 private:
487  template <typename U, typename = typename U::mapped_type>
488  static std::true_type test(Prefer);
489 
490  template <typename U>
491  static std::false_type test(LessPrefer);
492 
493 public:
494  static constexpr bool value = decltype(test<T>(Prefer()))::value;
495 };
496 
497 } // namespace internal {
498 
499 // `json` function for iterables (e.g., std::vector).
500 // This function is only enabled if `Iterable` is iterable, is not a
501 // `const char (&)[N]` (in order to avoid ambiguity with the string literal
502 // overload), and does not have a member typedef `mapped_type` (we take the
503 // existence of `mapped_type` as the indication of an associative container).
504 template <
505  typename Iterable,
506  typename std::enable_if<
508  !(std::is_array<Iterable>::value &&
509  std::rank<Iterable>::value == 1 &&
510  std::is_same<
511  char, typename std::remove_extent<Iterable>::type>::value) &&
513 void json(ArrayWriter* writer, const Iterable& iterable)
514 {
515  foreach (const auto& value, iterable) {
516  writer->element(value);
517  }
518 }
519 
520 
521 // `json` function for dictionaries (e.g., std::map).
522 // This function is only enabled if `Dictionary` is iterable, and has a member
523 // typedef `mapped_type` (we take the existence of `mapped_type` as the
524 // indication of an associative container).
525 template <
526  typename Dictionary,
527  typename std::enable_if<
530 void json(ObjectWriter* writer, const Dictionary& dictionary)
531 {
532  foreachpair (const auto& key, const auto& value, dictionary) {
533  // TODO(mpark): Consider passing `stringify(key)`.
534  writer->field(key, value);
535  }
536 }
537 
538 
539 // An object that can be converted to a pointer to any of the JSON writers.
540 // This is used to resolve the following scenario:
541 //
542 // ```
543 // void json(JSON::ObjectWriter*, const Resources&);
544 //
545 // void json(
546 // JSON::ArrayWriter*,
547 // const google::protobuf::RepeatedPtrField<Resource>&);
548 //
549 // Resources resources;
550 // std::cout << jsonify(resources); // We want to use the first overload!
551 // ```
552 //
553 // The goal is to perform overload resolution based on the second parameter.
554 // Since `WriterProxy` is convertible to any of the writers equivalently, we
555 // force overload resolution of `json(WriterProxy(writer), value)` to depend
556 // only on the second parameter.
558 {
559 public:
560  WriterProxy(rapidjson::Writer<rapidjson::StringBuffer>* writer)
561  : writer_(writer), type_(NULL_WRITER) {}
562 
564  {
565  switch (type_) {
566  case BOOLEAN_WRITER: {
567  proxy_.boolean_writer.~BooleanWriter();
568  break;
569  }
570  case NUMBER_WRITER: {
571  proxy_.number_writer.~NumberWriter();
572  break;
573  }
574  case STRING_WRITER: {
575  proxy_.string_writer.~StringWriter();
576  break;
577  }
578  case ARRAY_WRITER: {
579  proxy_.array_writer.~ArrayWriter();
580  break;
581  }
582  case OBJECT_WRITER: {
583  proxy_.object_writer.~ObjectWriter();
584  break;
585  }
586  case NULL_WRITER: {
587  proxy_.null_writer.~NullWriter();
588  break;
589  }
590  }
591  }
592 
593  operator BooleanWriter*() &&
594  {
595  new (&proxy_.boolean_writer) BooleanWriter(writer_);
596  type_ = BOOLEAN_WRITER;
597  return &proxy_.boolean_writer;
598  }
599 
600  operator NumberWriter*() &&
601  {
602  new (&proxy_.number_writer) NumberWriter(writer_);
603  type_ = NUMBER_WRITER;
604  return &proxy_.number_writer;
605  }
606 
607  operator StringWriter*() &&
608  {
609  new (&proxy_.string_writer) StringWriter(writer_);
610  type_ = STRING_WRITER;
611  return &proxy_.string_writer;
612  }
613 
614  operator ArrayWriter*() &&
615  {
616  new (&proxy_.array_writer) ArrayWriter(writer_);
617  type_ = ARRAY_WRITER;
618  return &proxy_.array_writer;
619  }
620 
621  operator ObjectWriter*() &&
622  {
623  new (&proxy_.object_writer) ObjectWriter(writer_);
624  type_ = OBJECT_WRITER;
625  return &proxy_.object_writer;
626  }
627 
628  operator NullWriter*() &&
629  {
630  new (&proxy_.null_writer) NullWriter(writer_);
631  type_ = NULL_WRITER;
632  return &proxy_.null_writer;
633  }
634 
635 private:
636  enum Type
637  {
638  BOOLEAN_WRITER,
639  NUMBER_WRITER,
640  STRING_WRITER,
641  ARRAY_WRITER,
642  OBJECT_WRITER,
643  NULL_WRITER
644  };
645 
646  union Writer
647  {
648  Writer() {}
649  ~Writer() {}
650  BooleanWriter boolean_writer;
651  NumberWriter number_writer;
652  StringWriter string_writer;
653  ArrayWriter array_writer;
654  ObjectWriter object_writer;
655  NullWriter null_writer;
656  };
657 
658  rapidjson::Writer<rapidjson::StringBuffer>* writer_;
659  Type type_;
660  Writer proxy_;
661 };
662 
663 
664 namespace internal {
665 
666 // NOTE: The following overloads of `internal::jsonify` return a `std::function`
667 // rather than a `JSON::Proxy` since `JSON::Proxy`'s copy/move constructors are
668 // declared `private`. We could also declare `internal::jsonify` as friend of
669 // `JSON::Proxy` but chose to minimize friendship and construct a
670 // `std::function` instead.
671 
672 // Given an `F` which is a "write" function, we simply use it directly.
674 std::function<void(rapidjson::Writer<rapidjson::StringBuffer>*)> jsonify(
675  const F& write,
676  Prefer)
677 {
678  return [&write](rapidjson::Writer<rapidjson::StringBuffer>* writer) {
679  write(WriterProxy(writer));
680  };
681 }
682 
683 // Given a `T` which is not a "write" function itself, the default "write"
684 // function is to perform an unqualified function call to `json`, which enables
685 // argument-dependent lookup. This considers the `json` overloads in the `JSON`
686 // namespace as well, since `WriterProxy` is intentionally defined in the
687 // `JSON` namespace.
688 template <typename T>
689 std::function<void(rapidjson::Writer<rapidjson::StringBuffer>*)> jsonify(
690  const T& value,
691  LessPrefer)
692 {
693  return [&value](rapidjson::Writer<rapidjson::StringBuffer>* writer) {
694  json(WriterProxy(writer), value);
695  };
696 }
697 
698 } // namespace internal {
699 } // namespace JSON {
700 
701 template <typename T>
702 JSON::Proxy jsonify(const T& t)
703 {
705 }
706 
707 #endif // __STOUT_JSONIFY__
StringWriter(rapidjson::Writer< rapidjson::StringBuffer > *writer)
Definition: jsonify.hpp:258
void set(short int value)
Definition: jsonify.hpp:197
~BooleanWriter()
Definition: jsonify.hpp:146
double double_
Definition: jsonify.hpp:247
WriterProxy(rapidjson::Writer< rapidjson::StringBuffer > *writer)
Definition: jsonify.hpp:560
Definition: jsonify.hpp:364
Definition: jsonify.hpp:137
Definition: jsonify.hpp:484
BooleanWriter(rapidjson::Writer< rapidjson::StringBuffer > *writer)
Definition: jsonify.hpp:140
friend std::ostream & operator<<(std::ostream &stream, Proxy &&that)
Definition: jsonify.hpp:128
Definition: jsonify.hpp:255
void element(const T &value)
Definition: jsonify.hpp:317
friend Proxy() jsonify(const T &)
Definition: jsonify.hpp:702
void json(BooleanWriter *writer, const Boolean &boolean)
Definition: json.hpp:735
~ArrayWriter()
Definition: jsonify.hpp:308
NullWriter(rapidjson::Writer< rapidjson::StringBuffer > *writer)
Definition: jsonify.hpp:367
void field(const std::string &key, const T &value)
Definition: jsonify.hpp:347
std::function< void(rapidjson::Writer< rapidjson::StringBuffer > *)> write
Definition: jsonify.hpp:124
Definition: jsonify.hpp:86
Definition: jsonify.hpp:446
Definition: jsonify.hpp:450
Definition: jsonify.hpp:326
#define foreachpair(KEY, VALUE, ELEMS)
Definition: foreach.hpp:51
ArrayWriter(rapidjson::Writer< rapidjson::StringBuffer > *writer)
Definition: jsonify.hpp:299
~WriterProxy()
Definition: jsonify.hpp:563
Definition: jsonify.hpp:161
JSON::Proxy jsonify(const T &)
Definition: jsonify.hpp:702
~NumberWriter()
Definition: jsonify.hpp:170
std::function< void(rapidjson::Writer< rapidjson::StringBuffer > *)> jsonify(const F &write, Prefer)
Definition: jsonify.hpp:674
long long int int_
Definition: jsonify.hpp:245
Definition: attributes.hpp:24
~StringWriter()
Definition: jsonify.hpp:264
~ObjectWriter()
Definition: jsonify.hpp:338
Try< uint32_t > type(const std::string &path)
ObjectWriter(rapidjson::Writer< rapidjson::StringBuffer > *writer)
Definition: jsonify.hpp:329
Definition: jsonify.hpp:445
unsigned long long int uint_
Definition: jsonify.hpp:246
NumberWriter(rapidjson::Writer< rapidjson::StringBuffer > *writer)
Definition: jsonify.hpp:164
void set(bool value)
Definition: jsonify.hpp:151
~NullWriter()
Definition: jsonify.hpp:373
Definition: json.hpp:51
Definition: jsonify.hpp:557
Definition: jsonify.hpp:296
void set(const char(&value)[N])
Definition: jsonify.hpp:270