/src/skia/modules/jsonreader/SkJSONReader.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* |
2 | | * Copyright 2024 Google LLC |
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/base/SkNoncopyable.h" |
13 | | #include "src/base/SkArenaAlloc.h" |
14 | | |
15 | | #include <cstdint> |
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> |
77 | 56.4M | bool is() const { return this->getType() == T::kType; } bool skjson::Value::is<skjson::ArrayValue>() const Line | Count | Source | 77 | 15.4M | bool is() const { return this->getType() == T::kType; } |
bool skjson::Value::is<skjson::ObjectValue>() const Line | Count | Source | 77 | 15.7M | bool is() const { return this->getType() == T::kType; } |
bool skjson::Value::is<skjson::StringValue>() const Line | Count | Source | 77 | 7.74M | bool is() const { return this->getType() == T::kType; } |
bool skjson::Value::is<skjson::NumberValue>() const Line | Count | Source | 77 | 16.3M | bool is() const { return this->getType() == T::kType; } |
bool skjson::Value::is<skjson::BoolValue>() const Line | Count | Source | 77 | 716k | bool is() const { return this->getType() == T::kType; } |
bool skjson::Value::is<skjson::NullValue>() const Line | Count | Source | 77 | 497k | 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> |
85 | 229M | const T& as() const { |
86 | 229M | SkASSERT(this->is<T>()); |
87 | 229M | return *reinterpret_cast<const T*>(this); |
88 | 229M | } skjson::ObjectValue const& skjson::Value::as<skjson::ObjectValue>() const Line | Count | Source | 85 | 6.22M | const T& as() const { | 86 | 6.22M | SkASSERT(this->is<T>()); | 87 | 6.22M | return *reinterpret_cast<const T*>(this); | 88 | 6.22M | } |
skjson::StringValue const& skjson::Value::as<skjson::StringValue>() const Line | Count | Source | 85 | 201M | const T& as() const { | 86 | 201M | SkASSERT(this->is<T>()); | 87 | 201M | return *reinterpret_cast<const T*>(this); | 88 | 201M | } |
skjson::ArrayValue const& skjson::Value::as<skjson::ArrayValue>() const Line | Count | Source | 85 | 3.94M | const T& as() const { | 86 | 3.94M | SkASSERT(this->is<T>()); | 87 | 3.94M | return *reinterpret_cast<const T*>(this); | 88 | 3.94M | } |
skjson::NumberValue const& skjson::Value::as<skjson::NumberValue>() const Line | Count | Source | 85 | 17.7M | const T& as() const { | 86 | 17.7M | SkASSERT(this->is<T>()); | 87 | 17.7M | return *reinterpret_cast<const T*>(this); | 88 | 17.7M | } |
skjson::BoolValue const& skjson::Value::as<skjson::BoolValue>() const Line | Count | Source | 85 | 284k | const T& as() const { | 86 | 284k | SkASSERT(this->is<T>()); | 87 | 284k | return *reinterpret_cast<const T*>(this); | 88 | 284k | } |
|
89 | | |
90 | | /** |
91 | | * Guarded conversion to facade types. |
92 | | * |
93 | | * @return The record cast as facade type T*. |
94 | | */ |
95 | | template <typename T> |
96 | 55.1M | operator const T*() const { |
97 | 55.1M | return this->is<T>() ? &this->as<T>() : nullptr; |
98 | 55.1M | } skjson::Value::operator skjson::ArrayValue const*<skjson::ArrayValue>() const Line | Count | Source | 96 | 14.8M | operator const T*() const { | 97 | 14.8M | return this->is<T>() ? &this->as<T>() : nullptr; | 98 | 14.8M | } |
skjson::Value::operator skjson::ObjectValue const*<skjson::ObjectValue>() const Line | Count | Source | 96 | 15.4M | operator const T*() const { | 97 | 15.4M | return this->is<T>() ? &this->as<T>() : nullptr; | 98 | 15.4M | } |
skjson::Value::operator skjson::StringValue const*<skjson::StringValue>() const Line | Count | Source | 96 | 7.74M | operator const T*() const { | 97 | 7.74M | return this->is<T>() ? &this->as<T>() : nullptr; | 98 | 7.74M | } |
skjson::Value::operator skjson::NumberValue const*<skjson::NumberValue>() const Line | Count | Source | 96 | 16.3M | operator const T*() const { | 97 | 16.3M | return this->is<T>() ? &this->as<T>() : nullptr; | 98 | 16.3M | } |
skjson::Value::operator skjson::BoolValue const*<skjson::BoolValue>() const Line | Count | Source | 96 | 716k | operator const T*() const { | 97 | 716k | return this->is<T>() ? &this->as<T>() : nullptr; | 98 | 716k | } |
|
99 | | |
100 | | /** |
101 | | * @return The string representation of this value. |
102 | | */ |
103 | | SkString toString() const; |
104 | | |
105 | | /** |
106 | | * Helper for fluent key lookup: v["foo"]["bar"]["baz"] |
107 | | * |
108 | | * @return The lookup result value on success, otherwise NullValue. |
109 | | */ |
110 | | const Value& operator[](const char* key) const; |
111 | | |
112 | | protected: |
113 | | /* |
114 | | Value implementation notes: |
115 | | |
116 | | -- fixed 64-bit size |
117 | | |
118 | | -- 8-byte aligned |
119 | | |
120 | | -- union of: |
121 | | |
122 | | bool |
123 | | int32 |
124 | | float |
125 | | char[8] (short string storage) |
126 | | external payload (tagged) pointer |
127 | | |
128 | | -- lowest 3 bits reserved for tag storage |
129 | | |
130 | | */ |
131 | | enum class Tag : uint8_t { |
132 | | // n.b.: we picked kShortString == 0 on purpose, |
133 | | // to enable certain short-string optimizations. |
134 | | kShortString = 0b00000000, // inline payload |
135 | | kNull = 0b00000001, // no payload |
136 | | kBool = 0b00000010, // inline payload |
137 | | kInt = 0b00000011, // inline payload |
138 | | kFloat = 0b00000100, // inline payload |
139 | | kString = 0b00000101, // ptr to external storage |
140 | | kArray = 0b00000110, // ptr to external storage |
141 | | kObject = 0b00000111, // ptr to external storage |
142 | | }; |
143 | | inline static constexpr uint8_t kTagMask = 0b00000111; |
144 | | |
145 | | void init_tagged(Tag); |
146 | | void init_tagged_pointer(Tag, void*); |
147 | | |
148 | 290M | Tag getTag() const { |
149 | 290M | return static_cast<Tag>(fData8[0] & kTagMask); |
150 | 290M | } |
151 | | |
152 | | // Access the record payload as T. |
153 | | // |
154 | | // Since the tag is stored in the lower bits, we skip the first word whenever feasible. |
155 | | // |
156 | | // E.g. (U == unused) |
157 | | // |
158 | | // uint8_t |
159 | | // ----------------------------------------------------------------------- |
160 | | // |TAG| U | val8 | U | U | U | U | U | U | |
161 | | // ----------------------------------------------------------------------- |
162 | | // |
163 | | // uint16_t |
164 | | // ----------------------------------------------------------------------- |
165 | | // |TAG| U | val16 | U | U | |
166 | | // ----------------------------------------------------------------------- |
167 | | // |
168 | | // uint32_t |
169 | | // ----------------------------------------------------------------------- |
170 | | // |TAG| U | val32 | |
171 | | // ----------------------------------------------------------------------- |
172 | | // |
173 | | // T* (32b) |
174 | | // ----------------------------------------------------------------------- |
175 | | // |TAG| U | T* (32bits) | |
176 | | // ----------------------------------------------------------------------- |
177 | | // |
178 | | // T* (64b) |
179 | | // ----------------------------------------------------------------------- |
180 | | // |TAG| T* (61bits) | |
181 | | // ----------------------------------------------------------------------- |
182 | | // |
183 | | template <typename T> |
184 | 395M | const T* cast() const { |
185 | 395M | static_assert(sizeof (T) <= sizeof(Value), ""); |
186 | 395M | static_assert(alignof(T) <= alignof(Value), ""); |
187 | | |
188 | 395M | return (sizeof(T) > sizeof(*this) / 2) |
189 | 395M | ? reinterpret_cast<const T*>(this) + 0 // need all the bits |
190 | 395M | : reinterpret_cast<const T*>(this) + 1; // skip the first word (where the tag lives) |
191 | 395M | } char const* skjson::Value::cast<char>() const Line | Count | Source | 184 | 185M | const T* cast() const { | 185 | 185M | static_assert(sizeof (T) <= sizeof(Value), ""); | 186 | 185M | static_assert(alignof(T) <= alignof(Value), ""); | 187 | | | 188 | 185M | return (sizeof(T) > sizeof(*this) / 2) | 189 | 185M | ? reinterpret_cast<const T*>(this) + 0 // need all the bits | 190 | 185M | : reinterpret_cast<const T*>(this) + 1; // skip the first word (where the tag lives) | 191 | 185M | } |
skjson::VectorValue<char, (skjson::Value::Type)3> const* skjson::Value::cast<skjson::VectorValue<char, (skjson::Value::Type)3> >() const Line | Count | Source | 184 | 16.8M | const T* cast() const { | 185 | 16.8M | static_assert(sizeof (T) <= sizeof(Value), ""); | 186 | 16.8M | static_assert(alignof(T) <= alignof(Value), ""); | 187 | | | 188 | 16.8M | return (sizeof(T) > sizeof(*this) / 2) | 189 | 16.8M | ? reinterpret_cast<const T*>(this) + 0 // need all the bits | 190 | 16.8M | : reinterpret_cast<const T*>(this) + 1; // skip the first word (where the tag lives) | 191 | 16.8M | } |
unsigned long const* skjson::Value::cast<unsigned long>() const Line | Count | Source | 184 | 139M | const T* cast() const { | 185 | 139M | static_assert(sizeof (T) <= sizeof(Value), ""); | 186 | 139M | static_assert(alignof(T) <= alignof(Value), ""); | 187 | | | 188 | 139M | return (sizeof(T) > sizeof(*this) / 2) | 189 | 139M | ? reinterpret_cast<const T*>(this) + 0 // need all the bits | 190 | 139M | : reinterpret_cast<const T*>(this) + 1; // skip the first word (where the tag lives) | 191 | 139M | } |
bool const* skjson::Value::cast<bool>() const Line | Count | Source | 184 | 621k | const T* cast() const { | 185 | 621k | static_assert(sizeof (T) <= sizeof(Value), ""); | 186 | 621k | static_assert(alignof(T) <= alignof(Value), ""); | 187 | | | 188 | 621k | return (sizeof(T) > sizeof(*this) / 2) | 189 | 621k | ? reinterpret_cast<const T*>(this) + 0 // need all the bits | 190 | 621k | : reinterpret_cast<const T*>(this) + 1; // skip the first word (where the tag lives) | 191 | 621k | } |
int const* skjson::Value::cast<int>() const Line | Count | Source | 184 | 28.4M | const T* cast() const { | 185 | 28.4M | static_assert(sizeof (T) <= sizeof(Value), ""); | 186 | 28.4M | static_assert(alignof(T) <= alignof(Value), ""); | 187 | | | 188 | 28.4M | return (sizeof(T) > sizeof(*this) / 2) | 189 | 28.4M | ? reinterpret_cast<const T*>(this) + 0 // need all the bits | 190 | 28.4M | : reinterpret_cast<const T*>(this) + 1; // skip the first word (where the tag lives) | 191 | 28.4M | } |
float const* skjson::Value::cast<float>() const Line | Count | Source | 184 | 3.46M | const T* cast() const { | 185 | 3.46M | static_assert(sizeof (T) <= sizeof(Value), ""); | 186 | 3.46M | static_assert(alignof(T) <= alignof(Value), ""); | 187 | | | 188 | 3.46M | return (sizeof(T) > sizeof(*this) / 2) | 189 | 3.46M | ? reinterpret_cast<const T*>(this) + 0 // need all the bits | 190 | 3.46M | : reinterpret_cast<const T*>(this) + 1; // skip the first word (where the tag lives) | 191 | 3.46M | } |
Unexecuted instantiation: unsigned long const* const* skjson::Value::cast<unsigned long const*>() const long const* skjson::Value::cast<long>() const Line | Count | Source | 184 | 21.3M | const T* cast() const { | 185 | 21.3M | static_assert(sizeof (T) <= sizeof(Value), ""); | 186 | 21.3M | static_assert(alignof(T) <= alignof(Value), ""); | 187 | | | 188 | 21.3M | return (sizeof(T) > sizeof(*this) / 2) | 189 | 21.3M | ? reinterpret_cast<const T*>(this) + 0 // need all the bits | 190 | 21.3M | : reinterpret_cast<const T*>(this) + 1; // skip the first word (where the tag lives) | 191 | 21.3M | } |
Unexecuted instantiation: void const* const* skjson::Value::cast<void const*>() const |
192 | | |
193 | | template <typename T> |
194 | 44.9M | T* cast() { return const_cast<T*>(const_cast<const Value*>(this)->cast<T>()); } skjson::VectorValue<char, (skjson::Value::Type)3>* skjson::Value::cast<skjson::VectorValue<char, (skjson::Value::Type)3> >() Line | Count | Source | 194 | 691k | T* cast() { return const_cast<T*>(const_cast<const Value*>(this)->cast<T>()); } |
char* skjson::Value::cast<char>() Line | Count | Source | 194 | 14.1k | T* cast() { return const_cast<T*>(const_cast<const Value*>(this)->cast<T>()); } |
long* skjson::Value::cast<long>() Line | Count | Source | 194 | 17.4M | T* cast() { return const_cast<T*>(const_cast<const Value*>(this)->cast<T>()); } |
unsigned long* skjson::Value::cast<unsigned long>() Line | Count | Source | 194 | 12.2M | T* cast() { return const_cast<T*>(const_cast<const Value*>(this)->cast<T>()); } |
bool* skjson::Value::cast<bool>() Line | Count | Source | 194 | 336k | T* cast() { return const_cast<T*>(const_cast<const Value*>(this)->cast<T>()); } |
int* skjson::Value::cast<int>() Line | Count | Source | 194 | 12.8M | T* cast() { return const_cast<T*>(const_cast<const Value*>(this)->cast<T>()); } |
float* skjson::Value::cast<float>() Line | Count | Source | 194 | 1.27M | T* cast() { return const_cast<T*>(const_cast<const Value*>(this)->cast<T>()); } |
|
195 | | |
196 | | // Access the pointer payload. |
197 | | template <typename T> |
198 | 127M | const T* ptr() const { |
199 | 127M | static_assert(sizeof(uintptr_t) == sizeof(Value) || |
200 | 127M | sizeof(uintptr_t) * 2 == sizeof(Value), ""); |
201 | | |
202 | 127M | return (sizeof(uintptr_t) < sizeof(Value)) |
203 | | // For 32-bit, pointers are stored unmodified. |
204 | 127M | ? *this->cast<const T*>() |
205 | | // For 64-bit, we use the lower bits of the pointer as tag storage. |
206 | 127M | : reinterpret_cast<T*>(*this->cast<uintptr_t>() & ~static_cast<uintptr_t>(kTagMask)); |
207 | 127M | } unsigned long const* skjson::Value::ptr<unsigned long>() const Line | Count | Source | 198 | 127M | const T* ptr() const { | 199 | 127M | static_assert(sizeof(uintptr_t) == sizeof(Value) || | 200 | 127M | sizeof(uintptr_t) * 2 == sizeof(Value), ""); | 201 | | | 202 | 127M | return (sizeof(uintptr_t) < sizeof(Value)) | 203 | | // For 32-bit, pointers are stored unmodified. | 204 | 127M | ? *this->cast<const T*>() | 205 | | // For 64-bit, we use the lower bits of the pointer as tag storage. | 206 | 127M | : reinterpret_cast<T*>(*this->cast<uintptr_t>() & ~static_cast<uintptr_t>(kTagMask)); | 207 | 127M | } |
Unexecuted instantiation: void const* skjson::Value::ptr<void>() const |
208 | | |
209 | | private: |
210 | | inline static constexpr size_t kValueSize = 8; |
211 | | |
212 | | uint8_t fData8[kValueSize]; |
213 | | |
214 | | #if !defined(SK_CPU_LENDIAN) |
215 | | // The current value layout assumes LE and will take some tweaking for BE. |
216 | | static_assert(false, "Big-endian builds are not supported at this time."); |
217 | | #endif |
218 | | }; |
219 | | |
220 | | class NullValue final : public Value { |
221 | | public: |
222 | | inline static constexpr Type kType = Type::kNull; |
223 | | |
224 | | NullValue(); |
225 | | }; |
226 | | |
227 | | class BoolValue final : public Value { |
228 | | public: |
229 | | inline static constexpr Type kType = Type::kBool; |
230 | | |
231 | | explicit BoolValue(bool); |
232 | | |
233 | 284k | bool operator*() const { |
234 | 284k | SkASSERT(this->getTag() == Tag::kBool); |
235 | 284k | return *this->cast<bool>(); |
236 | 284k | } |
237 | | }; |
238 | | |
239 | | class NumberValue final : public Value { |
240 | | public: |
241 | | inline static constexpr Type kType = Type::kNumber; |
242 | | |
243 | | explicit NumberValue(int32_t); |
244 | | explicit NumberValue(float); |
245 | | |
246 | 17.7M | double operator*() const { |
247 | 17.7M | SkASSERT(this->getTag() == Tag::kInt || this->getTag() == Tag::kFloat); |
248 | | |
249 | 17.7M | return this->getTag() == Tag::kInt ? static_cast<double>(*this->cast<int32_t>()) |
250 | 17.7M | : static_cast<double>(*this->cast<float>()); |
251 | 17.7M | } |
252 | | }; |
253 | | |
254 | | template <typename T, Value::Type vtype> |
255 | | class VectorValue : public Value { |
256 | | public: |
257 | | using ValueT = T; |
258 | | inline static constexpr Type kType = vtype; |
259 | | |
260 | 8.97M | size_t size() const { |
261 | 8.97M | SkASSERT(this->getType() == kType); |
262 | 8.97M | return *this->ptr<size_t>(); |
263 | 8.97M | } skjson::VectorValue<char, (skjson::Value::Type)3>::size() const Line | Count | Source | 260 | 26.1k | size_t size() const { | 261 | 26.1k | SkASSERT(this->getType() == kType); | 262 | 26.1k | return *this->ptr<size_t>(); | 263 | 26.1k | } |
skjson::VectorValue<skjson::Value, (skjson::Value::Type)4>::size() const Line | Count | Source | 260 | 8.94M | size_t size() const { | 261 | 8.94M | SkASSERT(this->getType() == kType); | 262 | 8.94M | return *this->ptr<size_t>(); | 263 | 8.94M | } |
skjson::VectorValue<skjson::Member, (skjson::Value::Type)5>::size() const Line | Count | Source | 260 | 1.08k | size_t size() const { | 261 | 1.08k | SkASSERT(this->getType() == kType); | 262 | 1.08k | return *this->ptr<size_t>(); | 263 | 1.08k | } |
|
264 | | |
265 | 75.3M | const T* begin() const { |
266 | 75.3M | SkASSERT(this->getType() == kType); |
267 | 75.3M | const auto* size_ptr = this->ptr<size_t>(); |
268 | 75.3M | return reinterpret_cast<const T*>(size_ptr + 1); |
269 | 75.3M | } skjson::VectorValue<char, (skjson::Value::Type)3>::begin() const Line | Count | Source | 265 | 16.8M | const T* begin() const { | 266 | 16.8M | SkASSERT(this->getType() == kType); | 267 | 16.8M | const auto* size_ptr = this->ptr<size_t>(); | 268 | 16.8M | return reinterpret_cast<const T*>(size_ptr + 1); | 269 | 16.8M | } |
skjson::VectorValue<skjson::Value, (skjson::Value::Type)4>::begin() const Line | Count | Source | 265 | 15.6M | const T* begin() const { | 266 | 15.6M | SkASSERT(this->getType() == kType); | 267 | 15.6M | const auto* size_ptr = this->ptr<size_t>(); | 268 | 15.6M | return reinterpret_cast<const T*>(size_ptr + 1); | 269 | 15.6M | } |
skjson::VectorValue<skjson::Member, (skjson::Value::Type)5>::begin() const Line | Count | Source | 265 | 42.8M | const T* begin() const { | 266 | 42.8M | SkASSERT(this->getType() == kType); | 267 | 42.8M | const auto* size_ptr = this->ptr<size_t>(); | 268 | 42.8M | return reinterpret_cast<const T*>(size_ptr + 1); | 269 | 42.8M | } |
|
270 | | |
271 | 42.6M | const T* end() const { |
272 | 42.6M | SkASSERT(this->getType() == kType); |
273 | 42.6M | const auto* size_ptr = this->ptr<size_t>(); |
274 | 42.6M | return reinterpret_cast<const T*>(size_ptr + 1) + *size_ptr; |
275 | 42.6M | } Unexecuted instantiation: skjson::VectorValue<char, (skjson::Value::Type)3>::end() const skjson::VectorValue<skjson::Value, (skjson::Value::Type)4>::end() const Line | Count | Source | 271 | 600k | const T* end() const { | 272 | 600k | SkASSERT(this->getType() == kType); | 273 | 600k | const auto* size_ptr = this->ptr<size_t>(); | 274 | 600k | return reinterpret_cast<const T*>(size_ptr + 1) + *size_ptr; | 275 | 600k | } |
skjson::VectorValue<skjson::Member, (skjson::Value::Type)5>::end() const Line | Count | Source | 271 | 42.0M | const T* end() const { | 272 | 42.0M | SkASSERT(this->getType() == kType); | 273 | 42.0M | const auto* size_ptr = this->ptr<size_t>(); | 274 | 42.0M | return reinterpret_cast<const T*>(size_ptr + 1) + *size_ptr; | 275 | 42.0M | } |
|
276 | | |
277 | 7.63M | const T& operator[](size_t i) const { |
278 | 7.63M | SkASSERT(this->getType() == kType); |
279 | 7.63M | SkASSERT(i < this->size()); |
280 | | |
281 | 7.63M | return *(this->begin() + i); |
282 | 7.63M | } |
283 | | }; |
284 | | |
285 | | class ArrayValue final : public VectorValue<Value, Value::Type::kArray> { |
286 | | public: |
287 | | ArrayValue(const Value* src, size_t size, SkArenaAlloc& alloc); |
288 | | }; |
289 | | |
290 | | class StringValue final : public Value { |
291 | | public: |
292 | | inline static constexpr Type kType = Type::kString; |
293 | | |
294 | | StringValue(); |
295 | | StringValue(const char* src, SkArenaAlloc& alloc); |
296 | | StringValue(const char* src, size_t size, SkArenaAlloc& alloc); |
297 | | |
298 | 296k | size_t size() const { |
299 | 296k | switch (this->getTag()) { |
300 | 270k | case Tag::kShortString: |
301 | | // We don't bother storing a length for short strings on the assumption |
302 | | // that strlen is fast in this case. If this becomes problematic, we |
303 | | // can either go back to storing (7-len) in the tag byte or write a fast |
304 | | // short_strlen. |
305 | 270k | return strlen(this->cast<char>()); |
306 | 26.1k | case Tag::kString: |
307 | 26.1k | return this->cast<VectorValue<char, Value::Type::kString>>()->size(); |
308 | 0 | default: |
309 | 0 | return 0; |
310 | 296k | } |
311 | 296k | } |
312 | | |
313 | 201M | const char* begin() const { |
314 | 201M | return this->getTag() == Tag::kShortString |
315 | 201M | ? this->cast<char>() |
316 | 201M | : this->cast<VectorValue<char, Value::Type::kString>>()->begin(); |
317 | 201M | } |
318 | | |
319 | 0 | const char* end() const { |
320 | 0 | return this->getTag() == Tag::kShortString |
321 | 0 | ? strchr(this->cast<char>(), '\0') |
322 | 0 | : this->cast<VectorValue<char, Value::Type::kString>>()->end(); |
323 | 0 | } |
324 | | |
325 | 0 | std::string_view str() const { return std::string_view(this->begin(), this->size()); } |
326 | | }; |
327 | | |
328 | | struct Member { |
329 | | StringValue fKey; |
330 | | Value fValue; |
331 | | }; |
332 | | |
333 | | class ObjectValue final : public VectorValue<Member, Value::Type::kObject> { |
334 | | public: |
335 | | ObjectValue(const Member* src, size_t size, SkArenaAlloc& alloc); |
336 | | |
337 | 42.0M | const Value& operator[](const char* key) const { |
338 | 42.0M | static const Value gNullValue = NullValue(); |
339 | | |
340 | 42.0M | const auto* member = this->find(key); |
341 | 42.0M | return member ? member->fValue : gNullValue; |
342 | 42.0M | } |
343 | | |
344 | | // Writable access to the value associated with the given key. |
345 | | // If the key is not present, it is added with a default NullValue. |
346 | | Value& writable(const char* key, SkArenaAlloc&) const; |
347 | | |
348 | | private: |
349 | | const Member* find(const char*) const; |
350 | | }; |
351 | | |
352 | | class DOM final : public SkNoncopyable { |
353 | | public: |
354 | | DOM(const char*, size_t); |
355 | | |
356 | 31.9k | const Value& root() const { return fRoot; } |
357 | | |
358 | | void write(SkWStream*) const; |
359 | | |
360 | | private: |
361 | | SkArenaAlloc fAlloc; |
362 | | Value fRoot; |
363 | | }; |
364 | | |
365 | 70.5M | inline Value::Type Value::getType() const { |
366 | 70.5M | switch (this->getTag()) { |
367 | 32.3M | case Tag::kNull: return Type::kNull; |
368 | 284k | case Tag::kBool: return Type::kBool; |
369 | 20.6M | case Tag::kInt: return Type::kNumber; |
370 | 3.84M | case Tag::kFloat: return Type::kNumber; |
371 | 2.76M | case Tag::kShortString: return Type::kString; |
372 | 157k | case Tag::kString: return Type::kString; |
373 | 3.94M | case Tag::kArray: return Type::kArray; |
374 | 6.51M | case Tag::kObject: return Type::kObject; |
375 | 70.5M | } |
376 | | |
377 | 0 | SkASSERT(false); // unreachable |
378 | 0 | return Type::kNull; |
379 | 70.5M | } |
380 | | |
381 | 0 | inline const Value& Value::operator[](const char* key) const { |
382 | 0 | static const Value gNullValue = NullValue(); |
383 | 0 |
|
384 | 0 | return this->is<ObjectValue>() ? this->as<ObjectValue>()[key] : gNullValue; |
385 | 0 | } |
386 | | |
387 | | } // namespace skjson |
388 | | |
389 | | #endif // SkJSON_DEFINED |