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