33static_assert(
sizeof(
Value) == 8,
"");
34static_assert(
alignof(
Value) == 8,
"");
39 memset(fData8, 0,
sizeof(fData8));
40 fData8[0] = SkTo<uint8_t>(t);
46 if (
sizeof(
Value) ==
sizeof(uintptr_t)) {
47 *this->cast<uintptr_t>() =
reinterpret_cast<uintptr_t
>(
p);
50 fData8[0] |= SkTo<uint8_t>(t);
55 *this->cast<uintptr_t>() =
reinterpret_cast<uintptr_t
>(
p);
69 *this->cast<bool>() =
b;
75 *this->cast<int32_t>() =
i;
81 *this->cast<float>() =
f;
91template <
typename T,
size_t extra_alloc_size = 0>
94 const auto total_size =
sizeof(size_t) + vec_size *
sizeof(
T) + extra_alloc_size;
103template <
typename T,
size_t extra_alloc_size = 0>
105 return MakeVector<T, extra_alloc_size>(vec_size,
src, vec_size, alloc);
131class FastString final :
public Value {
136 if (
size > kMaxInlineStringSize) {
137 this->initLongString(
src,
size, alloc);
138 SkASSERT(this->getTag() == Tag::kString);
143 if (
src &&
src + 6 <= eos) {
144 this->initFastShortString(
src,
size);
146 this->initShortString(
src,
size);
149 SkASSERT(this->getTag() == Tag::kShortString);
154 inline static constexpr size_t kMaxInlineStringSize =
sizeof(
Value) - 2;
159 this->init_tagged_pointer(Tag::kString, MakeVector<char, 1>(
size,
src, alloc));
161 auto*
data = this->cast<VectorValue<char, Value::Type::kString>>()->
begin();
162 const_cast<char*
>(
data)[
size] =
'\0';
165 void initShortString(
const char*
src,
size_t size) {
168 this->init_tagged(Tag::kShortString);
173 void initFastShortString(
const char*
src,
size_t size) {
176 uint64_t* s64 = this->cast<uint64_t>();
180 static_assert(
SkToU8(Tag::kShortString) == 0,
"please don't break this");
185 memcpy(s64,
src - 1, 8);
187#if defined(SK_CPU_LENDIAN)
191 *s64 &= (0x0000ffffffffffffULL >> ((kMaxInlineStringSize -
size) * 8))
194 static_assert(
false,
"Big-endian builds are not supported at this time.");
229const Member* ObjectValue::find(
const char*
key)
const {
232 const auto* member = this->
end();
234 while (member >
begin) {
247 if (!writable_member) {
253 writable_member =
const_cast<Member*
>(writable_obj->
end() - 1);
259 return writable_member->
fValue;
277static constexpr uint8_t g_token_flags[256] = {
279 4, 4, 4, 4, 4, 4, 4, 4, 4, 6, 6, 4, 4, 6, 4, 4,
280 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
281 3, 1, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0x11,1,
282 0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19, 0x19,0x19, 1, 1, 1, 1, 1, 1,
283 1, 1, 1, 1, 1, 0x11,1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
284 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4,0x25, 1, 1,
285 1, 1, 1, 1, 1, 0x11,1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
286 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,0x25, 1, 1,
289 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
290 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
291 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,
292 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0
295static inline bool is_ws(
char c) {
return g_token_flags[
static_cast<uint8_t
>(c)] & 0x02; }
296static inline bool is_eostring(
char c) {
return g_token_flags[
static_cast<uint8_t
>(c)] & 0x04; }
297static inline bool is_digit(
char c) {
return g_token_flags[
static_cast<uint8_t
>(c)] & 0x08; }
298static inline bool is_numeric(
char c) {
return g_token_flags[
static_cast<uint8_t
>(c)] & 0x10; }
299static inline bool is_eoscope(
char c) {
return g_token_flags[
static_cast<uint8_t
>(c)] & 0x20; }
301static inline const char*
skip_ws(
const char*
p) {
306static inline float pow10(int32_t exp) {
307 static constexpr float g_pow10_table[63] =
309 1.e-031f, 1.e-030f, 1.e-029f, 1.e-028f, 1.e-027f, 1.e-026f, 1.e-025f, 1.e-024f,
310 1.e-023f, 1.e-022f, 1.e-021f, 1.e-020f, 1.e-019f, 1.e-018f, 1.e-017f, 1.e-016f,
311 1.e-015f, 1.e-014f, 1.e-013f, 1.e-012f, 1.e-011f, 1.e-010f, 1.e-009f, 1.e-008f,
312 1.e-007f, 1.e-006f, 1.e-005f, 1.e-004f, 1.e-003f, 1.e-002f, 1.e-001f, 1.e+000f,
313 1.e+001f, 1.e+002f, 1.e+003f, 1.e+004f, 1.e+005f, 1.e+006f, 1.e+007f, 1.e+008f,
314 1.e+009f, 1.e+010f, 1.e+011f, 1.e+012f, 1.e+013f, 1.e+014f, 1.e+015f, 1.e+016f,
315 1.e+017f, 1.e+018f, 1.e+019f, 1.e+020f, 1.e+021f, 1.e+022f, 1.e+023f, 1.e+024f,
316 1.e+025f, 1.e+026f, 1.e+027f, 1.e+028f, 1.e+029f, 1.e+030f, 1.e+031f
319 static constexpr int32_t k_exp_offset =
std::size(g_pow10_table) / 2;
324 return (exp >= -k_exp_offset) ? g_pow10_table[exp + k_exp_offset]
325 : std::pow(10.0f,
static_cast<float>(exp));
332 fValueStack.reserve(kValueStackReserve);
333 fUnescapeBuffer.reserve(kUnescapeBufferReserve);
338 return this->
error(NullValue(),
p,
"invalid empty input");
341 const char* p_stop =
p +
size - 1;
345 while (p_stop >
p &&
is_ws(*p_stop)) --p_stop;
348 if (!is_eoscope(*p_stop)) {
349 return this->
error(NullValue(), p_stop,
"invalid top-level value");
360 return this->
error(NullValue(),
p,
"invalid top-level value");
367 this->pushObjectScope();
369 if (*
p ==
'}')
goto pop_object;
374 if (*
p !=
'"')
return this->
error(NullValue(),
p,
"expected object key");
376 p = this->matchString(
p, p_stop, [
this](
const char*
key,
size_t size,
const char* eos) {
377 this->pushObjectKey(
key,
size, eos);
379 if (!
p)
return NullValue();
382 if (*
p !=
':')
return this->
error(NullValue(),
p,
"expected ':' separator");
392 return this->
error(NullValue(),
p,
"unexpected input end");
394 p = this->matchString(
p, p_stop, [
this](
const char* str,
size_t size,
const char* eos) {
395 this->pushString(str,
size, eos);
401 p = this->matchFalse(
p);
404 p = this->matchNull(
p);
407 p = this->matchTrue(
p);
412 p = this->matchNumber(
p);
416 if (!
p)
return NullValue();
426 if (this->inObjectScope()) {
427 goto match_object_key;
437 return this->
error(NullValue(),
p - 1,
"unexpected value-trailing token");
446 if (this->inArrayScope()) {
447 return this->
error(NullValue(),
p,
"unexpected object terminator");
450 this->popObjectScope();
456 if (this->inTopLevelScope()) {
461 ? fValueStack.front()
462 : this->
error(NullValue(),
p + 1,
"trailing root garbage");
466 return this->
error(NullValue(),
p,
"unexpected end-of-input");
471 goto match_post_value;
477 this->pushArrayScope();
479 if (*
p !=
']')
goto match_value;
485 if (this->inObjectScope()) {
486 return this->
error(NullValue(),
p,
"unexpected array terminator");
489 this->popArrayScope();
497 std::tuple<const char*, const SkString> getError()
const {
498 return std::make_tuple(fErrorToken, fErrorMessage);
505 inline static constexpr size_t kValueStackReserve = 256;
506 std::vector<Value> fValueStack;
509 inline static constexpr size_t kUnescapeBufferReserve = 512;
510 std::vector<char> fUnescapeBuffer;
518 intptr_t fScopeIndex = 0;
521 const char* fErrorToken =
nullptr;
524 bool inTopLevelScope()
const {
return fScopeIndex == 0; }
525 bool inObjectScope()
const {
return fScopeIndex > 0; }
526 bool inArrayScope()
const {
return fScopeIndex < 0; }
529 template <
typename T>
530 class RawValue final :
public Value {
532 explicit RawValue(
T v) {
533 static_assert(
sizeof(
T) <=
sizeof(
Value),
"");
534 *this->cast<T>() = v;
540 template <
typename VectorT>
541 void popScopeAsVec(
size_t scope_start) {
543 SkASSERT(scope_start <= fValueStack.size());
545 using T =
typename VectorT::ValueT;
546 static_assert(
sizeof(
T) >=
sizeof(
Value),
"");
547 static_assert(
sizeof(
T) %
sizeof(
Value) == 0,
"");
548 static_assert(
alignof(
T) ==
alignof(
Value),
"");
550 const auto scope_count = fValueStack.size() - scope_start,
554 const auto*
begin =
reinterpret_cast<const T*
>(fValueStack.data() + scope_start);
558 auto& placeholder = fValueStack[scope_start - 1];
559 fScopeIndex = *
static_cast<RawValue<intptr_t>&
>(placeholder);
563 fValueStack.resize(scope_start);
566 void pushObjectScope() {
568 fValueStack.push_back(RawValue<intptr_t>(fScopeIndex));
571 fScopeIndex = SkTo<intptr_t>(fValueStack.size());
574 void popObjectScope() {
576 this->popScopeAsVec<ObjectValue>(SkTo<size_t>(fScopeIndex));
579 const auto& obj = fValueStack.back().as<ObjectValue>();
581 for (
const auto& member : obj) {
582 SkASSERT(member.fKey.is<StringValue>());
587 void pushArrayScope() {
589 fValueStack.push_back(RawValue<intptr_t>(fScopeIndex));
592 fScopeIndex = -SkTo<intptr_t>(fValueStack.size());
595 void popArrayScope() {
597 this->popScopeAsVec<ArrayValue>(SkTo<size_t>(-fScopeIndex));
600 const auto& arr = fValueStack.back().as<ArrayValue>();
605 void pushObjectKey(
const char*
key,
size_t size,
const char* eos) {
607 SkASSERT(fValueStack.size() >= SkTo<size_t>(fScopeIndex));
608 SkASSERT(!((fValueStack.size() - SkTo<size_t>(fScopeIndex)) & 1));
609 this->pushString(
key,
size, eos);
613 fValueStack.push_back(BoolValue(
true));
617 fValueStack.push_back(BoolValue(
false));
621 fValueStack.push_back(NullValue());
624 void pushString(
const char*
s,
size_t size,
const char* eos) {
625 fValueStack.push_back(FastString(
s,
size, eos, fAlloc));
628 void pushInt32(int32_t
i) {
629 fValueStack.push_back(NumberValue(
i));
632 void pushFloat(
float f) {
633 fValueStack.push_back(NumberValue(
f));
636 template <
typename T>
637 T error(
T&& ret_val,
const char*
p,
const char* msg) {
638#if defined(SK_JSON_REPORT_ERRORS)
640 fErrorMessage.
set(msg);
645 const char* matchTrue(
const char*
p) {
648 if (
p[1] ==
'r' &&
p[2] ==
'u' &&
p[3] ==
'e') {
653 return this->
error(
nullptr, p,
"invalid token");
656 const char* matchFalse(
const char*
p) {
659 if (
p[1] ==
'a' &&
p[2] ==
'l' &&
p[3] ==
's' &&
p[4] ==
'e') {
664 return this->
error(
nullptr, p,
"invalid token");
667 const char* matchNull(
const char*
p) {
670 if (
p[1] ==
'u' &&
p[2] ==
'l' &&
p[3] ==
'l') {
675 return this->
error(
nullptr, p,
"invalid token");
678 const std::vector<char>* unescapeString(
const char*
begin,
const char* end) {
679 fUnescapeBuffer.clear();
683 fUnescapeBuffer.push_back(*
p);
692 case '"': fUnescapeBuffer.push_back(
'"');
break;
693 case '\\': fUnescapeBuffer.push_back(
'\\');
break;
694 case '/': fUnescapeBuffer.push_back(
'/');
break;
695 case 'b': fUnescapeBuffer.push_back(
'\b');
break;
696 case 'f': fUnescapeBuffer.push_back(
'\f');
break;
697 case 'n': fUnescapeBuffer.push_back(
'\n');
break;
698 case 'r': fUnescapeBuffer.push_back(
'\r');
break;
699 case 't': fUnescapeBuffer.push_back(
'\t');
break;
706 const char hex_str[] = {
p[1],
p[2],
p[3],
p[4],
'\0'};
714 fUnescapeBuffer.insert(fUnescapeBuffer.end(),
utf8,
utf8 + utf8_len);
717 default:
return nullptr;
721 return &fUnescapeBuffer;
724 template <
typename MatchFunc>
725 const char* matchString(
const char*
p,
const char* p_stop, MatchFunc&& func) {
727 const auto* s_begin =
p + 1;
728 bool requires_unescape =
false;
733 for (
p =
p + 1; !is_eostring(*
p); ++
p);
737 if (!requires_unescape) {
738 func(s_begin,
p - s_begin, p_stop);
742 const auto* buf = this->unescapeString(s_begin,
p);
748 func(buf->data(), buf->size(), buf->data() + buf->size() - 1);
754 requires_unescape =
true;
763 if (is_eoscope(*
p)) {
769 }
while (
p != p_stop);
772 return this->
error(
nullptr, s_begin - 1,
"invalid string");
775 const char* matchFastFloatDecimalPart(
const char*
p,
int sign,
float f,
int exp) {
780 f =
f * 10.f + (*
p++ -
'0'); --exp;
782 f =
f * 10.f + (*
p++ -
'0'); --exp;
785 const auto decimal_scale =
pow10(exp);
786 if (is_numeric(*
p) || !decimal_scale) {
787 SkASSERT((*
p ==
'.' || *
p ==
'e' || *
p ==
'E') || !decimal_scale);
792 this->pushFloat(
sign *
f * decimal_scale);
797 const char* matchFastFloatPart(
const char*
p,
int sign,
float f) {
800 f =
f * 10.f + (*
p++ -
'0');
802 f =
f * 10.f + (*
p++ -
'0');
805 if (!is_numeric(*
p)) {
807 this->pushFloat(
sign *
f);
811 return (*
p ==
'.') ? this->matchFastFloatDecimalPart(
p + 1,
sign,
f, 0)
815 const char* matchFast32OrFloat(
const char*
p) {
822 const auto* digits_start =
p;
834 n32 = n32 * 10 + (*
p++ -
'0');
838 if (!is_numeric(*
p)) {
840 if (
p > digits_start) {
841 this->pushInt32(
sign * n32);
848 const auto* decimals_start = ++
p;
854 n32 = n32 * 10 + (*
p++ -
'0'); --exp;
856 n32 = n32 * 10 + (*
p++ -
'0'); --exp;
859 if (!is_numeric(*
p)) {
861 if (
p > decimals_start) {
862 this->pushFloat(
sign * n32 *
pow10(exp));
870 return this->matchFastFloatDecimalPart(
p,
sign, n32, exp);
874 return this->matchFastFloatPart(
p,
sign, n32);
877 const char* matchNumber(
const char*
p) {
878 if (
const auto* fast = this->matchFast32OrFloat(
p))
return fast;
882 float f = strtof(
p, &matched);
887 return this->
error(
nullptr, p,
"invalid numeric token");
892 switch (v.getType()) {
894 stream->writeText(
"null");
897 stream->writeText(*v.as<BoolValue>() ?
"true" :
"false");
900 stream->writeScalarAsText(*v.as<NumberValue>());
904 stream->writeText(v.as<StringValue>().begin());
908 const auto& array = v.as<ArrayValue>();
910 bool first_value =
true;
911 for (
const auto& entry : array) {
912 if (!first_value)
stream->writeText(
",");
920 const auto&
object = v.as<ObjectValue>();
922 bool first_member =
true;
923 for (
const auto& member :
object) {
925 if (!first_member)
stream->writeText(
",");
926 Write(member.fKey,
stream);
928 Write(member.fValue,
stream);
929 first_member =
false;
940 Write(*
this, &wstream);
for(const auto glyph :glyphs)
static size_t total_size(SkSBlockAllocator< N > &pool)
static double pow10(int e)
static void * sk_careful_memcpy(void *dst, const void *src, size_t len)
static bool is_digit(int c)
static const char * skip_ws(const char str[])
static int sign(SkScalar x)
SkDEBUGCODE(SK_SPI) SkThreadID SkGetThreadID()
constexpr uint8_t SkToU8(S x)
void * makeBytesAlignedTo(size_t size, size_t align)
sk_sp< SkData > detachAsData()
static const char * FindHex(const char str[], uint32_t *value)
void set(const SkString &src)
ArrayValue(const Value *src, size_t size, SkArenaAlloc &alloc)
DOM(const char *, size_t)
void write(SkWStream *) const
Value & writable(const char *key, SkArenaAlloc &) const
ObjectValue(const Member *src, size_t size, SkArenaAlloc &alloc)
static constexpr uint8_t kTagMask
SkString toString() const
void init_tagged_pointer(Tag, void *)
const Member * end() const
const Member * begin() const
static const char * begin(const StringSlice &s)
const uint8_t uint32_t uint32_t GError ** error
static float max(float r, float g, float b)
SK_SPI size_t ToUTF8(SkUnichar uni, char utf8[kMaxBytesInUTF8Sequence]=nullptr)
constexpr unsigned kMaxBytesInUTF8Sequence
constexpr int32_t kMaxInt32
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
constexpr Color operator*(T value, const Color &c)
def parse(repo_root, recipes_cfg_path)
static int inline_strcmp(const char a[], const char b[])
static void * MakeVector(size_t vec_size, const void *src, size_t src_size, SkArenaAlloc &alloc)
static constexpr size_t kMinChunkSize
static constexpr size_t kRecAlign
std::shared_ptr< const fml::Mapping > data