xref: /aosp_15_r20/external/skia/src/utils/SkJSON.h (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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