1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2018 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker *
4*c8dee2aaSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker */
7*c8dee2aaSAndroid Build Coastguard Worker
8*c8dee2aaSAndroid Build Coastguard Worker #ifndef SkJSON_DEFINED
9*c8dee2aaSAndroid Build Coastguard Worker #define SkJSON_DEFINED
10*c8dee2aaSAndroid Build Coastguard Worker
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypes.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkNoncopyable.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkArenaAlloc.h"
14*c8dee2aaSAndroid Build Coastguard Worker
15*c8dee2aaSAndroid Build Coastguard Worker #include <cstdint>
16*c8dee2aaSAndroid Build Coastguard Worker #include <cstring>
17*c8dee2aaSAndroid Build Coastguard Worker #include <string_view>
18*c8dee2aaSAndroid Build Coastguard Worker
19*c8dee2aaSAndroid Build Coastguard Worker class SkString;
20*c8dee2aaSAndroid Build Coastguard Worker class SkWStream;
21*c8dee2aaSAndroid Build Coastguard Worker
22*c8dee2aaSAndroid Build Coastguard Worker namespace skjson {
23*c8dee2aaSAndroid Build Coastguard Worker
24*c8dee2aaSAndroid Build Coastguard Worker /**
25*c8dee2aaSAndroid Build Coastguard Worker * A fast and likely non-conforming JSON parser.
26*c8dee2aaSAndroid Build Coastguard Worker *
27*c8dee2aaSAndroid Build Coastguard Worker * Some known limitations/compromises:
28*c8dee2aaSAndroid Build Coastguard Worker *
29*c8dee2aaSAndroid Build Coastguard Worker * -- single-precision FP numbers
30*c8dee2aaSAndroid Build Coastguard Worker *
31*c8dee2aaSAndroid Build Coastguard Worker * -- missing string unescaping (no current users, could be easily added)
32*c8dee2aaSAndroid Build Coastguard Worker *
33*c8dee2aaSAndroid Build Coastguard Worker *
34*c8dee2aaSAndroid Build Coastguard Worker * Values are opaque, fixed-size (64 bits), immutable records.
35*c8dee2aaSAndroid Build Coastguard Worker *
36*c8dee2aaSAndroid Build Coastguard Worker * They can be converted to facade types for type-specific functionality.
37*c8dee2aaSAndroid Build Coastguard Worker *
38*c8dee2aaSAndroid Build Coastguard Worker * E.g.:
39*c8dee2aaSAndroid Build Coastguard Worker *
40*c8dee2aaSAndroid Build Coastguard Worker * if (v.is<ArrayValue>()) {
41*c8dee2aaSAndroid Build Coastguard Worker * for (const auto& item : v.as<ArrayValue>()) {
42*c8dee2aaSAndroid Build Coastguard Worker * if (const NumberValue* n = item) {
43*c8dee2aaSAndroid Build Coastguard Worker * printf("Found number: %f", **n);
44*c8dee2aaSAndroid Build Coastguard Worker * }
45*c8dee2aaSAndroid Build Coastguard Worker * }
46*c8dee2aaSAndroid Build Coastguard Worker * }
47*c8dee2aaSAndroid Build Coastguard Worker *
48*c8dee2aaSAndroid Build Coastguard Worker * if (v.is<ObjectValue>()) {
49*c8dee2aaSAndroid Build Coastguard Worker * const StringValue* id = v.as<ObjectValue>()["id"];
50*c8dee2aaSAndroid Build Coastguard Worker * if (id) {
51*c8dee2aaSAndroid Build Coastguard Worker * printf("Found object ID: %s", id->begin());
52*c8dee2aaSAndroid Build Coastguard Worker * } else {
53*c8dee2aaSAndroid Build Coastguard Worker * printf("Missing object ID");
54*c8dee2aaSAndroid Build Coastguard Worker * }
55*c8dee2aaSAndroid Build Coastguard Worker * }
56*c8dee2aaSAndroid Build Coastguard Worker */
57*c8dee2aaSAndroid Build Coastguard Worker class alignas(8) Value {
58*c8dee2aaSAndroid Build Coastguard Worker public:
59*c8dee2aaSAndroid Build Coastguard Worker enum class Type {
60*c8dee2aaSAndroid Build Coastguard Worker kNull,
61*c8dee2aaSAndroid Build Coastguard Worker kBool,
62*c8dee2aaSAndroid Build Coastguard Worker kNumber,
63*c8dee2aaSAndroid Build Coastguard Worker kString,
64*c8dee2aaSAndroid Build Coastguard Worker kArray,
65*c8dee2aaSAndroid Build Coastguard Worker kObject,
66*c8dee2aaSAndroid Build Coastguard Worker };
67*c8dee2aaSAndroid Build Coastguard Worker
68*c8dee2aaSAndroid Build Coastguard Worker /**
69*c8dee2aaSAndroid Build Coastguard Worker * @return The type of this value.
70*c8dee2aaSAndroid Build Coastguard Worker */
71*c8dee2aaSAndroid Build Coastguard Worker Type getType() const;
72*c8dee2aaSAndroid Build Coastguard Worker
73*c8dee2aaSAndroid Build Coastguard Worker /**
74*c8dee2aaSAndroid Build Coastguard Worker * @return True if the record matches the facade type T.
75*c8dee2aaSAndroid Build Coastguard Worker */
76*c8dee2aaSAndroid Build Coastguard Worker template <typename T>
is()77*c8dee2aaSAndroid Build Coastguard Worker bool is() const { return this->getType() == T::kType; }
78*c8dee2aaSAndroid Build Coastguard Worker
79*c8dee2aaSAndroid Build Coastguard Worker /**
80*c8dee2aaSAndroid Build Coastguard Worker * Unguarded conversion to facade types.
81*c8dee2aaSAndroid Build Coastguard Worker *
82*c8dee2aaSAndroid Build Coastguard Worker * @return The record cast as facade type T&.
83*c8dee2aaSAndroid Build Coastguard Worker */
84*c8dee2aaSAndroid Build Coastguard Worker template <typename T>
as()85*c8dee2aaSAndroid Build Coastguard Worker const T& as() const {
86*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(this->is<T>());
87*c8dee2aaSAndroid Build Coastguard Worker return *reinterpret_cast<const T*>(this);
88*c8dee2aaSAndroid Build Coastguard Worker }
89*c8dee2aaSAndroid Build Coastguard Worker
90*c8dee2aaSAndroid Build Coastguard Worker /**
91*c8dee2aaSAndroid Build Coastguard Worker * Guarded conversion to facade types.
92*c8dee2aaSAndroid Build Coastguard Worker *
93*c8dee2aaSAndroid Build Coastguard Worker * @return The record cast as facade type T*.
94*c8dee2aaSAndroid Build Coastguard Worker */
95*c8dee2aaSAndroid Build Coastguard Worker template <typename T>
96*c8dee2aaSAndroid Build Coastguard Worker operator const T*() const {
97*c8dee2aaSAndroid Build Coastguard Worker return this->is<T>() ? &this->as<T>() : nullptr;
98*c8dee2aaSAndroid Build Coastguard Worker }
99*c8dee2aaSAndroid Build Coastguard Worker
100*c8dee2aaSAndroid Build Coastguard Worker /**
101*c8dee2aaSAndroid Build Coastguard Worker * @return The string representation of this value.
102*c8dee2aaSAndroid Build Coastguard Worker */
103*c8dee2aaSAndroid Build Coastguard Worker SkString toString() const;
104*c8dee2aaSAndroid Build Coastguard Worker
105*c8dee2aaSAndroid Build Coastguard Worker /**
106*c8dee2aaSAndroid Build Coastguard Worker * Helper for fluent key lookup: v["foo"]["bar"]["baz"]
107*c8dee2aaSAndroid Build Coastguard Worker *
108*c8dee2aaSAndroid Build Coastguard Worker * @return The lookup result value on success, otherwise NullValue.
109*c8dee2aaSAndroid Build Coastguard Worker */
110*c8dee2aaSAndroid Build Coastguard Worker const Value& operator[](const char* key) const;
111*c8dee2aaSAndroid Build Coastguard Worker
112*c8dee2aaSAndroid Build Coastguard Worker protected:
113*c8dee2aaSAndroid Build Coastguard Worker /*
114*c8dee2aaSAndroid Build Coastguard Worker Value implementation notes:
115*c8dee2aaSAndroid Build Coastguard Worker
116*c8dee2aaSAndroid Build Coastguard Worker -- fixed 64-bit size
117*c8dee2aaSAndroid Build Coastguard Worker
118*c8dee2aaSAndroid Build Coastguard Worker -- 8-byte aligned
119*c8dee2aaSAndroid Build Coastguard Worker
120*c8dee2aaSAndroid Build Coastguard Worker -- union of:
121*c8dee2aaSAndroid Build Coastguard Worker
122*c8dee2aaSAndroid Build Coastguard Worker bool
123*c8dee2aaSAndroid Build Coastguard Worker int32
124*c8dee2aaSAndroid Build Coastguard Worker float
125*c8dee2aaSAndroid Build Coastguard Worker char[8] (short string storage)
126*c8dee2aaSAndroid Build Coastguard Worker external payload (tagged) pointer
127*c8dee2aaSAndroid Build Coastguard Worker
128*c8dee2aaSAndroid Build Coastguard Worker -- lowest 3 bits reserved for tag storage
129*c8dee2aaSAndroid Build Coastguard Worker
130*c8dee2aaSAndroid Build Coastguard Worker */
131*c8dee2aaSAndroid Build Coastguard Worker enum class Tag : uint8_t {
132*c8dee2aaSAndroid Build Coastguard Worker // n.b.: we picked kShortString == 0 on purpose,
133*c8dee2aaSAndroid Build Coastguard Worker // to enable certain short-string optimizations.
134*c8dee2aaSAndroid Build Coastguard Worker kShortString = 0b00000000, // inline payload
135*c8dee2aaSAndroid Build Coastguard Worker kNull = 0b00000001, // no payload
136*c8dee2aaSAndroid Build Coastguard Worker kBool = 0b00000010, // inline payload
137*c8dee2aaSAndroid Build Coastguard Worker kInt = 0b00000011, // inline payload
138*c8dee2aaSAndroid Build Coastguard Worker kFloat = 0b00000100, // inline payload
139*c8dee2aaSAndroid Build Coastguard Worker kString = 0b00000101, // ptr to external storage
140*c8dee2aaSAndroid Build Coastguard Worker kArray = 0b00000110, // ptr to external storage
141*c8dee2aaSAndroid Build Coastguard Worker kObject = 0b00000111, // ptr to external storage
142*c8dee2aaSAndroid Build Coastguard Worker };
143*c8dee2aaSAndroid Build Coastguard Worker inline static constexpr uint8_t kTagMask = 0b00000111;
144*c8dee2aaSAndroid Build Coastguard Worker
145*c8dee2aaSAndroid Build Coastguard Worker void init_tagged(Tag);
146*c8dee2aaSAndroid Build Coastguard Worker void init_tagged_pointer(Tag, void*);
147*c8dee2aaSAndroid Build Coastguard Worker
getTag()148*c8dee2aaSAndroid Build Coastguard Worker Tag getTag() const {
149*c8dee2aaSAndroid Build Coastguard Worker return static_cast<Tag>(fData8[0] & kTagMask);
150*c8dee2aaSAndroid Build Coastguard Worker }
151*c8dee2aaSAndroid Build Coastguard Worker
152*c8dee2aaSAndroid Build Coastguard Worker // Access the record payload as T.
153*c8dee2aaSAndroid Build Coastguard Worker //
154*c8dee2aaSAndroid Build Coastguard Worker // Since the tag is stored in the lower bits, we skip the first word whenever feasible.
155*c8dee2aaSAndroid Build Coastguard Worker //
156*c8dee2aaSAndroid Build Coastguard Worker // E.g. (U == unused)
157*c8dee2aaSAndroid Build Coastguard Worker //
158*c8dee2aaSAndroid Build Coastguard Worker // uint8_t
159*c8dee2aaSAndroid Build Coastguard Worker // -----------------------------------------------------------------------
160*c8dee2aaSAndroid Build Coastguard Worker // |TAG| U | val8 | U | U | U | U | U | U |
161*c8dee2aaSAndroid Build Coastguard Worker // -----------------------------------------------------------------------
162*c8dee2aaSAndroid Build Coastguard Worker //
163*c8dee2aaSAndroid Build Coastguard Worker // uint16_t
164*c8dee2aaSAndroid Build Coastguard Worker // -----------------------------------------------------------------------
165*c8dee2aaSAndroid Build Coastguard Worker // |TAG| U | val16 | U | U |
166*c8dee2aaSAndroid Build Coastguard Worker // -----------------------------------------------------------------------
167*c8dee2aaSAndroid Build Coastguard Worker //
168*c8dee2aaSAndroid Build Coastguard Worker // uint32_t
169*c8dee2aaSAndroid Build Coastguard Worker // -----------------------------------------------------------------------
170*c8dee2aaSAndroid Build Coastguard Worker // |TAG| U | val32 |
171*c8dee2aaSAndroid Build Coastguard Worker // -----------------------------------------------------------------------
172*c8dee2aaSAndroid Build Coastguard Worker //
173*c8dee2aaSAndroid Build Coastguard Worker // T* (32b)
174*c8dee2aaSAndroid Build Coastguard Worker // -----------------------------------------------------------------------
175*c8dee2aaSAndroid Build Coastguard Worker // |TAG| U | T* (32bits) |
176*c8dee2aaSAndroid Build Coastguard Worker // -----------------------------------------------------------------------
177*c8dee2aaSAndroid Build Coastguard Worker //
178*c8dee2aaSAndroid Build Coastguard Worker // T* (64b)
179*c8dee2aaSAndroid Build Coastguard Worker // -----------------------------------------------------------------------
180*c8dee2aaSAndroid Build Coastguard Worker // |TAG| T* (61bits) |
181*c8dee2aaSAndroid Build Coastguard Worker // -----------------------------------------------------------------------
182*c8dee2aaSAndroid Build Coastguard Worker //
183*c8dee2aaSAndroid Build Coastguard Worker template <typename T>
cast()184*c8dee2aaSAndroid Build Coastguard Worker const T* cast() const {
185*c8dee2aaSAndroid Build Coastguard Worker static_assert(sizeof (T) <= sizeof(Value), "");
186*c8dee2aaSAndroid Build Coastguard Worker static_assert(alignof(T) <= alignof(Value), "");
187*c8dee2aaSAndroid Build Coastguard Worker
188*c8dee2aaSAndroid Build Coastguard Worker return (sizeof(T) > sizeof(*this) / 2)
189*c8dee2aaSAndroid Build Coastguard Worker ? reinterpret_cast<const T*>(this) + 0 // need all the bits
190*c8dee2aaSAndroid Build Coastguard Worker : reinterpret_cast<const T*>(this) + 1; // skip the first word (where the tag lives)
191*c8dee2aaSAndroid Build Coastguard Worker }
192*c8dee2aaSAndroid Build Coastguard Worker
193*c8dee2aaSAndroid Build Coastguard Worker template <typename T>
cast()194*c8dee2aaSAndroid Build Coastguard Worker T* cast() { return const_cast<T*>(const_cast<const Value*>(this)->cast<T>()); }
195*c8dee2aaSAndroid Build Coastguard Worker
196*c8dee2aaSAndroid Build Coastguard Worker // Access the pointer payload.
197*c8dee2aaSAndroid Build Coastguard Worker template <typename T>
ptr()198*c8dee2aaSAndroid Build Coastguard Worker const T* ptr() const {
199*c8dee2aaSAndroid Build Coastguard Worker static_assert(sizeof(uintptr_t) == sizeof(Value) ||
200*c8dee2aaSAndroid Build Coastguard Worker sizeof(uintptr_t) * 2 == sizeof(Value), "");
201*c8dee2aaSAndroid Build Coastguard Worker
202*c8dee2aaSAndroid Build Coastguard Worker return (sizeof(uintptr_t) < sizeof(Value))
203*c8dee2aaSAndroid Build Coastguard Worker // For 32-bit, pointers are stored unmodified.
204*c8dee2aaSAndroid Build Coastguard Worker ? *this->cast<const T*>()
205*c8dee2aaSAndroid Build Coastguard Worker // For 64-bit, we use the lower bits of the pointer as tag storage.
206*c8dee2aaSAndroid Build Coastguard Worker : reinterpret_cast<T*>(*this->cast<uintptr_t>() & ~static_cast<uintptr_t>(kTagMask));
207*c8dee2aaSAndroid Build Coastguard Worker }
208*c8dee2aaSAndroid Build Coastguard Worker
209*c8dee2aaSAndroid Build Coastguard Worker private:
210*c8dee2aaSAndroid Build Coastguard Worker inline static constexpr size_t kValueSize = 8;
211*c8dee2aaSAndroid Build Coastguard Worker
212*c8dee2aaSAndroid Build Coastguard Worker uint8_t fData8[kValueSize];
213*c8dee2aaSAndroid Build Coastguard Worker
214*c8dee2aaSAndroid Build Coastguard Worker #if !defined(SK_CPU_LENDIAN)
215*c8dee2aaSAndroid Build Coastguard Worker // The current value layout assumes LE and will take some tweaking for BE.
216*c8dee2aaSAndroid Build Coastguard Worker static_assert(false, "Big-endian builds are not supported at this time.");
217*c8dee2aaSAndroid Build Coastguard Worker #endif
218*c8dee2aaSAndroid Build Coastguard Worker };
219*c8dee2aaSAndroid Build Coastguard Worker
220*c8dee2aaSAndroid Build Coastguard Worker class NullValue final : public Value {
221*c8dee2aaSAndroid Build Coastguard Worker public:
222*c8dee2aaSAndroid Build Coastguard Worker inline static constexpr Type kType = Type::kNull;
223*c8dee2aaSAndroid Build Coastguard Worker
224*c8dee2aaSAndroid Build Coastguard Worker NullValue();
225*c8dee2aaSAndroid Build Coastguard Worker };
226*c8dee2aaSAndroid Build Coastguard Worker
227*c8dee2aaSAndroid Build Coastguard Worker class BoolValue final : public Value {
228*c8dee2aaSAndroid Build Coastguard Worker public:
229*c8dee2aaSAndroid Build Coastguard Worker inline static constexpr Type kType = Type::kBool;
230*c8dee2aaSAndroid Build Coastguard Worker
231*c8dee2aaSAndroid Build Coastguard Worker explicit BoolValue(bool);
232*c8dee2aaSAndroid Build Coastguard Worker
233*c8dee2aaSAndroid Build Coastguard Worker bool operator *() const {
234*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(this->getTag() == Tag::kBool);
235*c8dee2aaSAndroid Build Coastguard Worker return *this->cast<bool>();
236*c8dee2aaSAndroid Build Coastguard Worker }
237*c8dee2aaSAndroid Build Coastguard Worker };
238*c8dee2aaSAndroid Build Coastguard Worker
239*c8dee2aaSAndroid Build Coastguard Worker class NumberValue final : public Value {
240*c8dee2aaSAndroid Build Coastguard Worker public:
241*c8dee2aaSAndroid Build Coastguard Worker inline static constexpr Type kType = Type::kNumber;
242*c8dee2aaSAndroid Build Coastguard Worker
243*c8dee2aaSAndroid Build Coastguard Worker explicit NumberValue(int32_t);
244*c8dee2aaSAndroid Build Coastguard Worker explicit NumberValue(float);
245*c8dee2aaSAndroid Build Coastguard Worker
246*c8dee2aaSAndroid Build Coastguard Worker double operator *() const {
247*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(this->getTag() == Tag::kInt ||
248*c8dee2aaSAndroid Build Coastguard Worker this->getTag() == Tag::kFloat);
249*c8dee2aaSAndroid Build Coastguard Worker
250*c8dee2aaSAndroid Build Coastguard Worker return this->getTag() == Tag::kInt
251*c8dee2aaSAndroid Build Coastguard Worker ? static_cast<double>(*this->cast<int32_t>())
252*c8dee2aaSAndroid Build Coastguard Worker : static_cast<double>(*this->cast<float>());
253*c8dee2aaSAndroid Build Coastguard Worker }
254*c8dee2aaSAndroid Build Coastguard Worker };
255*c8dee2aaSAndroid Build Coastguard Worker
256*c8dee2aaSAndroid Build Coastguard Worker template <typename T, Value::Type vtype>
257*c8dee2aaSAndroid Build Coastguard Worker class VectorValue : public Value {
258*c8dee2aaSAndroid Build Coastguard Worker public:
259*c8dee2aaSAndroid Build Coastguard Worker using ValueT = T;
260*c8dee2aaSAndroid Build Coastguard Worker inline static constexpr Type kType = vtype;
261*c8dee2aaSAndroid Build Coastguard Worker
size()262*c8dee2aaSAndroid Build Coastguard Worker size_t size() const {
263*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(this->getType() == kType);
264*c8dee2aaSAndroid Build Coastguard Worker return *this->ptr<size_t>();
265*c8dee2aaSAndroid Build Coastguard Worker }
266*c8dee2aaSAndroid Build Coastguard Worker
begin()267*c8dee2aaSAndroid Build Coastguard Worker const T* begin() const {
268*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(this->getType() == kType);
269*c8dee2aaSAndroid Build Coastguard Worker const auto* size_ptr = this->ptr<size_t>();
270*c8dee2aaSAndroid Build Coastguard Worker return reinterpret_cast<const T*>(size_ptr + 1);
271*c8dee2aaSAndroid Build Coastguard Worker }
272*c8dee2aaSAndroid Build Coastguard Worker
end()273*c8dee2aaSAndroid Build Coastguard Worker const T* end() const {
274*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(this->getType() == kType);
275*c8dee2aaSAndroid Build Coastguard Worker const auto* size_ptr = this->ptr<size_t>();
276*c8dee2aaSAndroid Build Coastguard Worker return reinterpret_cast<const T*>(size_ptr + 1) + *size_ptr;
277*c8dee2aaSAndroid Build Coastguard Worker }
278*c8dee2aaSAndroid Build Coastguard Worker
279*c8dee2aaSAndroid Build Coastguard Worker const T& operator[](size_t i) const {
280*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(this->getType() == kType);
281*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(i < this->size());
282*c8dee2aaSAndroid Build Coastguard Worker
283*c8dee2aaSAndroid Build Coastguard Worker return *(this->begin() + i);
284*c8dee2aaSAndroid Build Coastguard Worker }
285*c8dee2aaSAndroid Build Coastguard Worker };
286*c8dee2aaSAndroid Build Coastguard Worker
287*c8dee2aaSAndroid Build Coastguard Worker class ArrayValue final : public VectorValue<Value, Value::Type::kArray> {
288*c8dee2aaSAndroid Build Coastguard Worker public:
289*c8dee2aaSAndroid Build Coastguard Worker ArrayValue(const Value* src, size_t size, SkArenaAlloc& alloc);
290*c8dee2aaSAndroid Build Coastguard Worker };
291*c8dee2aaSAndroid Build Coastguard Worker
292*c8dee2aaSAndroid Build Coastguard Worker class StringValue final : public Value {
293*c8dee2aaSAndroid Build Coastguard Worker public:
294*c8dee2aaSAndroid Build Coastguard Worker inline static constexpr Type kType = Type::kString;
295*c8dee2aaSAndroid Build Coastguard Worker
296*c8dee2aaSAndroid Build Coastguard Worker StringValue();
297*c8dee2aaSAndroid Build Coastguard Worker StringValue(const char* src, SkArenaAlloc& alloc);
298*c8dee2aaSAndroid Build Coastguard Worker StringValue(const char* src, size_t size, SkArenaAlloc& alloc);
299*c8dee2aaSAndroid Build Coastguard Worker
size()300*c8dee2aaSAndroid Build Coastguard Worker size_t size() const {
301*c8dee2aaSAndroid Build Coastguard Worker switch (this->getTag()) {
302*c8dee2aaSAndroid Build Coastguard Worker case Tag::kShortString:
303*c8dee2aaSAndroid Build Coastguard Worker // We don't bother storing a length for short strings on the assumption
304*c8dee2aaSAndroid Build Coastguard Worker // that strlen is fast in this case. If this becomes problematic, we
305*c8dee2aaSAndroid Build Coastguard Worker // can either go back to storing (7-len) in the tag byte or write a fast
306*c8dee2aaSAndroid Build Coastguard Worker // short_strlen.
307*c8dee2aaSAndroid Build Coastguard Worker return strlen(this->cast<char>());
308*c8dee2aaSAndroid Build Coastguard Worker case Tag::kString:
309*c8dee2aaSAndroid Build Coastguard Worker return this->cast<VectorValue<char, Value::Type::kString>>()->size();
310*c8dee2aaSAndroid Build Coastguard Worker default:
311*c8dee2aaSAndroid Build Coastguard Worker return 0;
312*c8dee2aaSAndroid Build Coastguard Worker }
313*c8dee2aaSAndroid Build Coastguard Worker }
314*c8dee2aaSAndroid Build Coastguard Worker
begin()315*c8dee2aaSAndroid Build Coastguard Worker const char* begin() const {
316*c8dee2aaSAndroid Build Coastguard Worker return this->getTag() == Tag::kShortString
317*c8dee2aaSAndroid Build Coastguard Worker ? this->cast<char>()
318*c8dee2aaSAndroid Build Coastguard Worker : this->cast<VectorValue<char, Value::Type::kString>>()->begin();
319*c8dee2aaSAndroid Build Coastguard Worker }
320*c8dee2aaSAndroid Build Coastguard Worker
end()321*c8dee2aaSAndroid Build Coastguard Worker const char* end() const {
322*c8dee2aaSAndroid Build Coastguard Worker return this->getTag() == Tag::kShortString
323*c8dee2aaSAndroid Build Coastguard Worker ? strchr(this->cast<char>(), '\0')
324*c8dee2aaSAndroid Build Coastguard Worker : this->cast<VectorValue<char, Value::Type::kString>>()->end();
325*c8dee2aaSAndroid Build Coastguard Worker }
326*c8dee2aaSAndroid Build Coastguard Worker
str()327*c8dee2aaSAndroid Build Coastguard Worker std::string_view str() const {
328*c8dee2aaSAndroid Build Coastguard Worker return std::string_view(this->begin(), this->size());
329*c8dee2aaSAndroid Build Coastguard Worker }
330*c8dee2aaSAndroid Build Coastguard Worker };
331*c8dee2aaSAndroid Build Coastguard Worker
332*c8dee2aaSAndroid Build Coastguard Worker struct Member {
333*c8dee2aaSAndroid Build Coastguard Worker StringValue fKey;
334*c8dee2aaSAndroid Build Coastguard Worker Value fValue;
335*c8dee2aaSAndroid Build Coastguard Worker };
336*c8dee2aaSAndroid Build Coastguard Worker
337*c8dee2aaSAndroid Build Coastguard Worker class ObjectValue final : public VectorValue<Member, Value::Type::kObject> {
338*c8dee2aaSAndroid Build Coastguard Worker public:
339*c8dee2aaSAndroid Build Coastguard Worker ObjectValue(const Member* src, size_t size, SkArenaAlloc& alloc);
340*c8dee2aaSAndroid Build Coastguard Worker
341*c8dee2aaSAndroid Build Coastguard Worker const Value& operator[](const char* key) const {
342*c8dee2aaSAndroid Build Coastguard Worker static const Value gNullValue = NullValue();
343*c8dee2aaSAndroid Build Coastguard Worker
344*c8dee2aaSAndroid Build Coastguard Worker const auto* member = this->find(key);
345*c8dee2aaSAndroid Build Coastguard Worker return member
346*c8dee2aaSAndroid Build Coastguard Worker ? member->fValue
347*c8dee2aaSAndroid Build Coastguard Worker : gNullValue;
348*c8dee2aaSAndroid Build Coastguard Worker }
349*c8dee2aaSAndroid Build Coastguard Worker
350*c8dee2aaSAndroid Build Coastguard Worker // Writable access to the value associated with the given key.
351*c8dee2aaSAndroid Build Coastguard Worker // If the key is not present, it is added with a default NullValue.
352*c8dee2aaSAndroid Build Coastguard Worker Value& writable(const char* key, SkArenaAlloc&) const;
353*c8dee2aaSAndroid Build Coastguard Worker
354*c8dee2aaSAndroid Build Coastguard Worker private:
355*c8dee2aaSAndroid Build Coastguard Worker const Member* find(const char*) const;
356*c8dee2aaSAndroid Build Coastguard Worker };
357*c8dee2aaSAndroid Build Coastguard Worker
358*c8dee2aaSAndroid Build Coastguard Worker class DOM final : public SkNoncopyable {
359*c8dee2aaSAndroid Build Coastguard Worker public:
360*c8dee2aaSAndroid Build Coastguard Worker DOM(const char*, size_t);
361*c8dee2aaSAndroid Build Coastguard Worker
root()362*c8dee2aaSAndroid Build Coastguard Worker const Value& root() const { return fRoot; }
363*c8dee2aaSAndroid Build Coastguard Worker
364*c8dee2aaSAndroid Build Coastguard Worker void write(SkWStream*) const;
365*c8dee2aaSAndroid Build Coastguard Worker
366*c8dee2aaSAndroid Build Coastguard Worker private:
367*c8dee2aaSAndroid Build Coastguard Worker SkArenaAlloc fAlloc;
368*c8dee2aaSAndroid Build Coastguard Worker Value fRoot;
369*c8dee2aaSAndroid Build Coastguard Worker };
370*c8dee2aaSAndroid Build Coastguard Worker
getType()371*c8dee2aaSAndroid Build Coastguard Worker inline Value::Type Value::getType() const {
372*c8dee2aaSAndroid Build Coastguard Worker switch (this->getTag()) {
373*c8dee2aaSAndroid Build Coastguard Worker case Tag::kNull: return Type::kNull;
374*c8dee2aaSAndroid Build Coastguard Worker case Tag::kBool: return Type::kBool;
375*c8dee2aaSAndroid Build Coastguard Worker case Tag::kInt: return Type::kNumber;
376*c8dee2aaSAndroid Build Coastguard Worker case Tag::kFloat: return Type::kNumber;
377*c8dee2aaSAndroid Build Coastguard Worker case Tag::kShortString: return Type::kString;
378*c8dee2aaSAndroid Build Coastguard Worker case Tag::kString: return Type::kString;
379*c8dee2aaSAndroid Build Coastguard Worker case Tag::kArray: return Type::kArray;
380*c8dee2aaSAndroid Build Coastguard Worker case Tag::kObject: return Type::kObject;
381*c8dee2aaSAndroid Build Coastguard Worker }
382*c8dee2aaSAndroid Build Coastguard Worker
383*c8dee2aaSAndroid Build Coastguard Worker SkASSERT(false); // unreachable
384*c8dee2aaSAndroid Build Coastguard Worker return Type::kNull;
385*c8dee2aaSAndroid Build Coastguard Worker }
386*c8dee2aaSAndroid Build Coastguard Worker
387*c8dee2aaSAndroid Build Coastguard Worker inline const Value& Value::operator[](const char* key) const {
388*c8dee2aaSAndroid Build Coastguard Worker static const Value gNullValue = NullValue();
389*c8dee2aaSAndroid Build Coastguard Worker
390*c8dee2aaSAndroid Build Coastguard Worker return this->is<ObjectValue>()
391*c8dee2aaSAndroid Build Coastguard Worker ? this->as<ObjectValue>()[key]
392*c8dee2aaSAndroid Build Coastguard Worker : gNullValue;
393*c8dee2aaSAndroid Build Coastguard Worker }
394*c8dee2aaSAndroid Build Coastguard Worker
395*c8dee2aaSAndroid Build Coastguard Worker } // namespace skjson
396*c8dee2aaSAndroid Build Coastguard Worker
397*c8dee2aaSAndroid Build Coastguard Worker #endif // SkJSON_DEFINED
398