annotate json/json11/json11.hpp @ 66:6f160dee1192

Instead of using separate values and b64values entries in JSON serialisations, allow numeric arrays to be replaced by b64 variants wherever they appear (discriminating by type). Also rename values to featureValues in feature throughout, as values turns out to be a hazardous name in a JS context. Finally use Array instead of Text for array encoding (seems clearer).
author Chris Cannam <c.cannam@qmul.ac.uk>
date Tue, 27 Sep 2016 15:04:59 +0100
parents 6e8607ebad03
children
rev   line source
c@5 1 /* json11
c@5 2 *
c@5 3 * json11 is a tiny JSON library for C++11, providing JSON parsing and serialization.
c@5 4 *
c@5 5 * The core object provided by the library is json11::Json. A Json object represents any JSON
c@5 6 * value: null, bool, number (int or double), string (std::string), array (std::vector), or
c@5 7 * object (std::map).
c@5 8 *
c@5 9 * Json objects act like values: they can be assigned, copied, moved, compared for equality or
c@5 10 * order, etc. There are also helper methods Json::dump, to serialize a Json to a string, and
c@5 11 * Json::parse (static) to parse a std::string as a Json object.
c@5 12 *
c@5 13 * Internally, the various types of Json object are represented by the JsonValue class
c@5 14 * hierarchy.
c@5 15 *
c@5 16 * A note on numbers - JSON specifies the syntax of number formatting but not its semantics,
c@5 17 * so some JSON implementations distinguish between integers and floating-point numbers, while
c@5 18 * some don't. In json11, we choose the latter. Because some JSON implementations (namely
c@5 19 * Javascript itself) treat all numbers as the same type, distinguishing the two leads
c@5 20 * to JSON that will be *silently* changed by a round-trip through those implementations.
c@5 21 * Dangerous! To avoid that risk, json11 stores all numbers as double internally, but also
c@5 22 * provides integer helpers.
c@5 23 *
c@5 24 * Fortunately, double-precision IEEE754 ('double') can precisely store any integer in the
c@5 25 * range +/-2^53, which includes every 'int' on most systems. (Timestamps often use int64
c@5 26 * or long long to avoid the Y2038K problem; a double storing microseconds since some epoch
c@5 27 * will be exact for +/- 275 years.)
c@5 28 */
c@5 29
c@5 30 /* Copyright (c) 2013 Dropbox, Inc.
c@5 31 *
c@5 32 * Permission is hereby granted, free of charge, to any person obtaining a copy
c@5 33 * of this software and associated documentation files (the "Software"), to deal
c@5 34 * in the Software without restriction, including without limitation the rights
c@5 35 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
c@5 36 * copies of the Software, and to permit persons to whom the Software is
c@5 37 * furnished to do so, subject to the following conditions:
c@5 38 *
c@5 39 * The above copyright notice and this permission notice shall be included in
c@5 40 * all copies or substantial portions of the Software.
c@5 41 *
c@5 42 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
c@5 43 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
c@5 44 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
c@5 45 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
c@5 46 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
c@5 47 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
c@5 48 * THE SOFTWARE.
c@5 49 */
c@5 50
c@5 51 #pragma once
c@5 52
c@5 53 #include <string>
c@5 54 #include <vector>
c@5 55 #include <map>
c@5 56 #include <memory>
c@5 57 #include <initializer_list>
c@5 58
c@5 59 namespace json11 {
c@5 60
c@5 61 enum JsonParse {
c@5 62 STANDARD, COMMENTS
c@5 63 };
c@5 64
c@5 65 class JsonValue;
c@5 66
c@5 67 class Json final {
c@5 68 public:
c@5 69 // Types
c@5 70 enum Type {
c@5 71 NUL, NUMBER, BOOL, STRING, ARRAY, OBJECT
c@5 72 };
c@5 73
c@5 74 // Array and object typedefs
c@5 75 typedef std::vector<Json> array;
c@5 76 typedef std::map<std::string, Json> object;
c@5 77
c@5 78 // Constructors for the various types of JSON value.
c@5 79 Json() noexcept; // NUL
c@5 80 Json(std::nullptr_t) noexcept; // NUL
c@5 81 Json(double value); // NUMBER
c@5 82 Json(int value); // NUMBER
c@5 83 Json(bool value); // BOOL
c@5 84 Json(const std::string &value); // STRING
c@5 85 Json(std::string &&value); // STRING
c@5 86 Json(const char * value); // STRING
c@5 87 Json(const array &values); // ARRAY
c@5 88 Json(array &&values); // ARRAY
c@5 89 Json(const object &values); // OBJECT
c@5 90 Json(object &&values); // OBJECT
c@5 91
c@5 92 // Implicit constructor: anything with a to_json() function.
c@5 93 template <class T, class = decltype(&T::to_json)>
c@5 94 Json(const T & t) : Json(t.to_json()) {}
c@5 95
c@5 96 // Implicit constructor: map-like objects (std::map, std::unordered_map, etc)
c@5 97 template <class M, typename std::enable_if<
c@5 98 std::is_constructible<std::string, typename M::key_type>::value
c@5 99 && std::is_constructible<Json, typename M::mapped_type>::value,
c@5 100 int>::type = 0>
c@5 101 Json(const M & m) : Json(object(m.begin(), m.end())) {}
c@5 102
c@5 103 // Implicit constructor: vector-like objects (std::list, std::vector, std::set, etc)
c@5 104 template <class V, typename std::enable_if<
c@5 105 std::is_constructible<Json, typename V::value_type>::value,
c@5 106 int>::type = 0>
c@5 107 Json(const V & v) : Json(array(v.begin(), v.end())) {}
c@5 108
c@5 109 // This prevents Json(some_pointer) from accidentally producing a bool. Use
c@5 110 // Json(bool(some_pointer)) if that behavior is desired.
c@5 111 Json(void *) = delete;
c@5 112
c@5 113 // Accessors
c@5 114 Type type() const;
c@5 115
c@5 116 bool is_null() const { return type() == NUL; }
c@5 117 bool is_number() const { return type() == NUMBER; }
c@5 118 bool is_bool() const { return type() == BOOL; }
c@5 119 bool is_string() const { return type() == STRING; }
c@5 120 bool is_array() const { return type() == ARRAY; }
c@5 121 bool is_object() const { return type() == OBJECT; }
c@5 122
c@5 123 // Return the enclosed value if this is a number, 0 otherwise. Note that json11 does not
c@5 124 // distinguish between integer and non-integer numbers - number_value() and int_value()
c@5 125 // can both be applied to a NUMBER-typed object.
c@5 126 double number_value() const;
c@5 127 int int_value() const;
c@5 128
c@5 129 // Return the enclosed value if this is a boolean, false otherwise.
c@5 130 bool bool_value() const;
c@5 131 // Return the enclosed string if this is a string, "" otherwise.
c@5 132 const std::string &string_value() const;
c@5 133 // Return the enclosed std::vector if this is an array, or an empty vector otherwise.
c@5 134 const array &array_items() const;
c@5 135 // Return the enclosed std::map if this is an object, or an empty map otherwise.
c@5 136 const object &object_items() const;
c@5 137
c@5 138 // Return a reference to arr[i] if this is an array, Json() otherwise.
c@5 139 const Json & operator[](size_t i) const;
c@5 140 // Return a reference to obj[key] if this is an object, Json() otherwise.
c@5 141 const Json & operator[](const std::string &key) const;
c@5 142
c@5 143 // Serialize.
c@5 144 void dump(std::string &out) const;
c@5 145 std::string dump() const {
c@5 146 std::string out;
c@5 147 dump(out);
c@5 148 return out;
c@5 149 }
c@5 150
c@5 151 // Parse. If parse fails, return Json() and assign an error message to err.
c@5 152 static Json parse(const std::string & in,
c@5 153 std::string & err,
c@5 154 JsonParse strategy = JsonParse::STANDARD);
c@5 155 static Json parse(const char * in,
c@5 156 std::string & err,
c@5 157 JsonParse strategy = JsonParse::STANDARD) {
c@5 158 if (in) {
c@5 159 return parse(std::string(in), err, strategy);
c@5 160 } else {
c@5 161 err = "null input";
c@5 162 return nullptr;
c@5 163 }
c@5 164 }
c@5 165 // Parse multiple objects, concatenated or separated by whitespace
c@5 166 static std::vector<Json> parse_multi(
c@5 167 const std::string & in,
c@5 168 std::string & err,
c@5 169 JsonParse strategy = JsonParse::STANDARD);
c@5 170
c@5 171 bool operator== (const Json &rhs) const;
c@5 172 bool operator< (const Json &rhs) const;
c@5 173 bool operator!= (const Json &rhs) const { return !(*this == rhs); }
c@5 174 bool operator<= (const Json &rhs) const { return !(rhs < *this); }
c@5 175 bool operator> (const Json &rhs) const { return (rhs < *this); }
c@5 176 bool operator>= (const Json &rhs) const { return !(*this < rhs); }
c@5 177
c@5 178 /* has_shape(types, err)
c@5 179 *
c@5 180 * Return true if this is a JSON object and, for each item in types, has a field of
c@5 181 * the given type. If not, return false and set err to a descriptive message.
c@5 182 */
c@5 183 typedef std::initializer_list<std::pair<std::string, Type>> shape;
c@5 184 bool has_shape(const shape & types, std::string & err) const;
c@5 185
c@5 186 private:
c@5 187 std::shared_ptr<JsonValue> m_ptr;
c@5 188 };
c@5 189
c@5 190 // Internal class hierarchy - JsonValue objects are not exposed to users of this API.
c@5 191 class JsonValue {
c@5 192 protected:
c@5 193 friend class Json;
c@5 194 friend class JsonInt;
c@5 195 friend class JsonDouble;
c@5 196 virtual Json::Type type() const = 0;
c@5 197 virtual bool equals(const JsonValue * other) const = 0;
c@5 198 virtual bool less(const JsonValue * other) const = 0;
c@5 199 virtual void dump(std::string &out) const = 0;
c@5 200 virtual double number_value() const;
c@5 201 virtual int int_value() const;
c@5 202 virtual bool bool_value() const;
c@5 203 virtual const std::string &string_value() const;
c@5 204 virtual const Json::array &array_items() const;
c@5 205 virtual const Json &operator[](size_t i) const;
c@5 206 virtual const Json::object &object_items() const;
c@5 207 virtual const Json &operator[](const std::string &key) const;
c@5 208 virtual ~JsonValue() {}
c@5 209 };
c@5 210
c@5 211 } // namespace json11