blob: 4cb312c64ff9f636bbb6cf463cba4c3438bf12a8 [file] [log] [blame]
Florin Malita7796f002018-06-08 12:25:38 -04001/*
2 * Copyright 2018 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#ifndef SkJSON_DEFINED
9#define SkJSON_DEFINED
10
11#include "SkArenaAlloc.h"
12#include "SkTypes.h"
13
14class SkWStream;
15
16namespace skjson {
17
18/**
19 * A fast and likely non-conforming JSON parser.
20 *
21 * Some known limitations/compromises:
22 *
23 * -- single-precision FP numbers
24 *
25 * -- missing string unescaping (no current users, could be easily added)
26 *
27 *
28 * Values are opaque, fixed-size (64 bits), immutable records.
29 *
30 * They can be freely converted to any of the facade types for type-specific functionality.
31 *
32 * Note: type checking is lazy/deferred, to facilitate chained property access - e.g.
33 *
34 * if (!v.as<ObjectValue>()["foo"].as<ObjectValue>()["bar"].is<NullValue>())
35 * LOG("found v.foo.bar!");
36 */
37class alignas(8) Value {
38public:
39 enum class Type {
40 kNull,
41 kBool,
42 kNumber,
43 kString,
44 kArray,
45 kObject,
46 };
47
48 /**
49 * @return The public type of this record.
50 */
51 Type getType() const;
52
53 /**
54 * @return True if the record matches the facade type T.
55 */
56 template <typename T>
57 bool is() const { return T::IsType(this->getType()); }
58
59 /**
60 * @return The record cast as facade type T.
61 *
62 * Note: this is always safe, as proper typing is enforced in the facade methods.
63 */
64 template <typename T>
65 const T& as() const {
66 return *reinterpret_cast<const T*>(this->is<T>() ? this : &Value::Null());
67 }
68
69 /**
70 * @return Null value singleton.
71 */
72 static const Value& Null();
73
74protected:
75 uint8_t fData8[8];
76};
77
78class NullValue final : public Value {
79public:
80 static bool IsType(Value::Type t) { return t == Type::kNull; }
81};
82
83template <typename T, Value::Type vtype>
84class PrimitiveValue final : public Value {
85public:
86 static bool IsType(Value::Type t) { return t == vtype; }
87
88 T operator *() const;
89};
90
91template <typename T, Value::Type vtype>
92class VectorValue : public Value {
93public:
94 static bool IsType(Value::Type t) { return t == vtype; }
95
96 size_t size() const;
97
98 const T* begin() const;
99 const T* end() const;
100
101 const T& operator[](size_t i) const {
102 return (i < this->size()) ? *(this->begin() + i) : T::Null();
103 }
104};
105
106using BoolValue = PrimitiveValue<bool , Value::Type::kBool >;
107using NumberValue = PrimitiveValue<double, Value::Type::kNumber>;
108using StringValue = VectorValue<char , Value::Type::kString>;
109using ArrayValue = VectorValue<Value , Value::Type::kArray >;
110
111struct Member {
112 StringValue fKey;
113 Value fValue;
114
115 static const Member& Null();
116};
117
118class ObjectValue final : public VectorValue<Member, Value::Type::kObject> {
119public:
120 const Value& operator[](const char*) const;
121};
122
123class DOM final : public SkNoncopyable {
124public:
125 explicit DOM(const char*);
126
127 const Value& root() const { return *fRoot; }
128
129 void write(SkWStream*) const;
130
131private:
132 SkArenaAlloc fAlloc;
133 const Value* fRoot;
134};
135
136} // namespace skjson
137
138#endif // SkJSON_DEFINED
139