aboutsummaryrefslogtreecommitdiffhomepage
path: root/modules
diff options
context:
space:
mode:
authorGravatar Florin Malita <fmalita@chromium.org>2018-06-19 11:27:20 -0400
committerGravatar Kevin Lubick <kjlubick@google.com>2018-06-19 18:23:30 +0000
commit80452bee11ebe6708ea459ea34e526a44c04bdb0 (patch)
tree2e74fe66a6554f81909188b423f7ce4055cdaea3 /modules
parent96aa535b782f31df0f063213c2958acba32a808d (diff)
Fold SkJSON into Skia/utils
It's a tiny, core-ish component -- might as well treat as such to simplify dependencies. Change-Id: I6f31ce2d151f9a629d88bfc7f15d64891d5150c0 Reviewed-on: https://skia-review.googlesource.com/135780 Reviewed-by: Mike Klein <mtklein@google.com> Reviewed-by: Kevin Lubick <kjlubick@google.com> Commit-Queue: Florin Malita <fmalita@chromium.org>
Diffstat (limited to 'modules')
-rw-r--r--modules/skjson/BUILD.gn86
-rw-r--r--modules/skjson/include/SkJSON.h360
-rw-r--r--modules/skjson/src/FuzzSkJSON.cpp24
-rw-r--r--modules/skjson/src/SkJSON.cpp803
-rw-r--r--modules/skjson/src/SkJSONBench.cpp161
-rw-r--r--modules/skjson/src/SkJSONTest.cpp388
-rw-r--r--modules/skottie/BUILD.gn1
7 files changed, 0 insertions, 1823 deletions
diff --git a/modules/skjson/BUILD.gn b/modules/skjson/BUILD.gn
deleted file mode 100644
index dd8ca65973..0000000000
--- a/modules/skjson/BUILD.gn
+++ /dev/null
@@ -1,86 +0,0 @@
-# Copyright 2018 Google Inc.
-#
-# Use of this source code is governed by a BSD-style license that can be
-# found in the LICENSE file.
-
-declare_args() {
- skia_enable_skjson = true
-}
-
-config("public_config") {
- if (skia_enable_skjson) {
- defines = [ "SK_ENABLE_SKJSON" ]
- include_dirs = [ "include" ]
- }
-}
-
-source_set("skjson") {
- if (skia_enable_skjson) {
- public_configs = [ ":public_config" ]
- public = [
- "include/SkJSON.h",
- ]
- sources = [
- "src/SkJSON.cpp",
- ]
- configs += [ "../../:skia_private" ]
- deps = [
- "../..:skia",
- ]
- }
-}
-
-source_set("tests") {
- if (skia_enable_skjson) {
- testonly = true
-
- configs += [
- "../..:skia_private",
- "../..:tests_config",
- ]
- sources = [
- "src/SkJSONTest.cpp",
- ]
-
- deps = [
- ":skjson",
- "../..:gpu_tool_utils",
- "../..:skia",
- ]
- }
-}
-
-source_set("bench") {
- if (skia_enable_skjson) {
- testonly = true
-
- configs += [
- "../..:bench_config",
- "../..:skia_private",
- ]
- sources = [
- "src/SkJSONBench.cpp",
- ]
-
- deps = [
- ":skjson",
- "../..:skia",
- ]
- }
-}
-
-source_set("fuzz") {
- if (skia_enable_skjson) {
- testonly = true
-
- configs += [ "../..:skia_private" ]
- sources = [
- "src/FuzzSkJSON.cpp",
- ]
-
- deps = [
- ":skjson",
- "../..:skia",
- ]
- }
-}
diff --git a/modules/skjson/include/SkJSON.h b/modules/skjson/include/SkJSON.h
deleted file mode 100644
index 8baf9fb8fc..0000000000
--- a/modules/skjson/include/SkJSON.h
+++ /dev/null
@@ -1,360 +0,0 @@
-/*
- * Copyright 2018 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#ifndef SkJSON_DEFINED
-#define SkJSON_DEFINED
-
-#include "SkArenaAlloc.h"
-#include "SkTo.h"
-#include "SkTypes.h"
-
-#include <cstring>
-
-class SkString;
-class SkWStream;
-
-namespace skjson {
-
-/**
- * A fast and likely non-conforming JSON parser.
- *
- * Some known limitations/compromises:
- *
- * -- single-precision FP numbers
- *
- * -- missing string unescaping (no current users, could be easily added)
- *
- *
- * Values are opaque, fixed-size (64 bits), immutable records.
- *
- * They can be converted to facade types for type-specific functionality.
- *
- * E.g.:
- *
- * if (v.is<ArrayValue>()) {
- * for (const auto& item : v.as<ArrayValue>()) {
- * if (const NumberValue* n = item) {
- * printf("Found number: %f", **n);
- * }
- * }
- * }
- *
- * if (v.is<ObjectValue>()) {
- * const StringValue* id = v.as<ObjectValue>()["id"];
- * if (id) {
- * printf("Found object ID: %s", id->begin());
- * } else {
- * printf("Missing object ID");
- * }
- * }
- */
-class alignas(8) Value {
-public:
- enum class Type {
- kNull,
- kBool,
- kNumber,
- kString,
- kArray,
- kObject,
- };
-
- /**
- * @return The type of this value.
- */
- Type getType() const;
-
- /**
- * @return True if the record matches the facade type T.
- */
- template <typename T>
- bool is() const { return this->getType() == T::kType; }
-
- /**
- * Unguarded conversion to facade types.
- *
- * @return The record cast as facade type T&.
- */
- template <typename T>
- const T& as() const {
- SkASSERT(this->is<T>());
- return *reinterpret_cast<const T*>(this);
- }
-
- /**
- * Guarded conversion to facade types.
- *
- * @return The record cast as facade type T*.
- */
- template <typename T>
- operator const T*() const {
- return this->is<T>() ? &this->as<T>() : nullptr;
- }
-
- /**
- * @return The string representation of this value.
- */
- SkString toString() const;
-
-protected:
- /*
- Value implementation notes:
-
- -- fixed 64-bit size
-
- -- 8-byte aligned
-
- -- union of:
-
- bool
- int32
- float
- char[8] (short string storage)
- external payload (tagged) pointer
-
- -- highest 3 bits reserved for type storage
-
- */
- enum class Tag : uint8_t {
- // We picked kShortString == 0 so that tag 0x00 and stored max_size-size (7-7=0)
- // conveniently overlap the '\0' terminator, allowing us to store a 7 character
- // C string inline.
- kShortString = 0b00000000, // inline payload
- kNull = 0b00100000, // no payload
- kBool = 0b01000000, // inline payload
- kInt = 0b01100000, // inline payload
- kFloat = 0b10000000, // inline payload
- kString = 0b10100000, // ptr to external storage
- kArray = 0b11000000, // ptr to external storage
- kObject = 0b11100000, // ptr to external storage
- };
- static constexpr uint8_t kTagMask = 0b11100000;
-
- void init_tagged(Tag);
- void init_tagged_pointer(Tag, void*);
-
- Tag getTag() const {
- return static_cast<Tag>(fData8[kTagOffset] & kTagMask);
- }
-
- // Access the record data as T.
- //
- // This is also used to access the payload for inline records. Since the record type lives in
- // the high bits, sizeof(T) must be less than sizeof(Value) when accessing inline payloads.
- //
- // E.g.
- //
- // uint8_t
- // -----------------------------------------------------------------------
- // | val8 | val8 | val8 | val8 | val8 | val8 | val8 | TYPE|
- // -----------------------------------------------------------------------
- //
- // uint32_t
- // -----------------------------------------------------------------------
- // | val32 | unused | TYPE|
- // -----------------------------------------------------------------------
- //
- // T* (64b)
- // -----------------------------------------------------------------------
- // | T* (kTypeShift bits) |TYPE|
- // -----------------------------------------------------------------------
- //
- template <typename T>
- const T* cast() const {
- static_assert(sizeof (T) <= sizeof(Value), "");
- static_assert(alignof(T) <= alignof(Value), "");
- return reinterpret_cast<const T*>(this);
- }
-
- template <typename T>
- T* cast() { return const_cast<T*>(const_cast<const Value*>(this)->cast<T>()); }
-
- // Access the pointer payload.
- template <typename T>
- const T* ptr() const {
- static_assert(sizeof(uintptr_t) == sizeof(Value) ||
- sizeof(uintptr_t) * 2 == sizeof(Value), "");
-
- return (sizeof(uintptr_t) < sizeof(Value))
- // For 32-bit, pointers are stored unmodified.
- ? *this->cast<const T*>()
- // For 64-bit, we use the high bits of the pointer as tag storage.
- : reinterpret_cast<T*>(*this->cast<uintptr_t>() & kTagPointerMask);
- }
-
-private:
- static constexpr size_t kValueSize = 8;
-
- uint8_t fData8[kValueSize];
-
-#if defined(SK_CPU_LENDIAN)
- static constexpr size_t kTagOffset = kValueSize - 1;
-
- static constexpr uintptr_t kTagPointerMask =
- ~(static_cast<uintptr_t>(kTagMask) << ((sizeof(uintptr_t) - 1) * 8));
-#else
- // The current value layout assumes LE and will take some tweaking for BE.
- static_assert(false, "Big-endian builds are not supported at this time.");
-#endif
-};
-
-class NullValue final : public Value {
-public:
- static constexpr Type kType = Type::kNull;
-
- NullValue();
-};
-
-class BoolValue final : public Value {
-public:
- static constexpr Type kType = Type::kBool;
-
- explicit BoolValue(bool);
-
- bool operator *() const {
- SkASSERT(this->getTag() == Tag::kBool);
- return *this->cast<bool>();
- }
-};
-
-class NumberValue final : public Value {
-public:
- static constexpr Type kType = Type::kNumber;
-
- explicit NumberValue(int32_t);
- explicit NumberValue(float);
-
- double operator *() const {
- SkASSERT(this->getTag() == Tag::kInt ||
- this->getTag() == Tag::kFloat);
-
- return this->getTag() == Tag::kInt
- ? static_cast<double>(*this->cast<int32_t>())
- : static_cast<double>(*this->cast<float>());
- }
-};
-
-template <typename T, Value::Type vtype>
-class VectorValue : public Value {
-public:
- using ValueT = T;
- static constexpr Type kType = vtype;
-
- size_t size() const {
- SkASSERT(this->getType() == kType);
- return *this->ptr<size_t>();
- }
-
- const T* begin() const {
- SkASSERT(this->getType() == kType);
- const auto* size_ptr = this->ptr<size_t>();
- return reinterpret_cast<const T*>(size_ptr + 1);
- }
-
- const T* end() const {
- SkASSERT(this->getType() == kType);
- const auto* size_ptr = this->ptr<size_t>();
- return reinterpret_cast<const T*>(size_ptr + 1) + *size_ptr;
- }
-
- const T& operator[](size_t i) const {
- SkASSERT(this->getType() == kType);
- SkASSERT(i < this->size());
-
- return *(this->begin() + i);
- }
-};
-
-class ArrayValue final : public VectorValue<Value, Value::Type::kArray> {
-public:
- ArrayValue(const Value* src, size_t size, SkArenaAlloc& alloc);
-};
-
-class StringValue final : public Value {
-public:
- static constexpr Type kType = Type::kString;
-
- StringValue();
- StringValue(const char* src, size_t size, SkArenaAlloc& alloc);
-
- size_t size() const {
- switch (this->getTag()) {
- case Tag::kShortString:
- // We don't bother storing a length for short strings on the assumption
- // that strlen is fast in this case. If this becomes problematic, we
- // can either go back to storing (7-len) in the tag byte or write a fast
- // short_strlen.
- return strlen(this->cast<char>());
- case Tag::kString:
- return this->cast<VectorValue<char, Value::Type::kString>>()->size();
- default:
- return 0;
- }
- }
-
- const char* begin() const {
- return this->getTag() == Tag::kShortString
- ? this->cast<char>()
- : this->cast<VectorValue<char, Value::Type::kString>>()->begin();
- }
-
- const char* end() const {
- return this->getTag() == Tag::kShortString
- ? strchr(this->cast<char>(), '\0')
- : this->cast<VectorValue<char, Value::Type::kString>>()->end();
- }
-};
-
-struct Member {
- StringValue fKey;
- Value fValue;
-};
-
-class ObjectValue final : public VectorValue<Member, Value::Type::kObject> {
-public:
- ObjectValue(const Member* src, size_t size, SkArenaAlloc& alloc);
-
- const Value& operator[](const char*) const;
-
-private:
- // Not particularly interesting - hiding for disambiguation.
- const Member& operator[](size_t i) const = delete;
-};
-
-class DOM final : public SkNoncopyable {
-public:
- DOM(const char*, size_t);
-
- const Value& root() const { return fRoot; }
-
- void write(SkWStream*) const;
-
-private:
- SkArenaAlloc fAlloc;
- Value fRoot;
-};
-
-inline Value::Type Value::getType() const {
- switch (this->getTag()) {
- case Tag::kNull: return Type::kNull;
- case Tag::kBool: return Type::kBool;
- case Tag::kInt: return Type::kNumber;
- case Tag::kFloat: return Type::kNumber;
- case Tag::kShortString: return Type::kString;
- case Tag::kString: return Type::kString;
- case Tag::kArray: return Type::kArray;
- case Tag::kObject: return Type::kObject;
- }
-
- SkASSERT(false); // unreachable
- return Type::kNull;
-}
-
-} // namespace skjson
-
-#endif // SkJSON_DEFINED
-
diff --git a/modules/skjson/src/FuzzSkJSON.cpp b/modules/skjson/src/FuzzSkJSON.cpp
deleted file mode 100644
index 2e971ce249..0000000000
--- a/modules/skjson/src/FuzzSkJSON.cpp
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright 2018 Google, LLC
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "SkData.h"
-#include "SkJSON.h"
-#include "SkStream.h"
-
-void FuzzSkJSON(sk_sp<SkData> bytes) {
- skjson::DOM dom(static_cast<const char*>(bytes->data()), bytes->size());
- SkDynamicMemoryWStream wstream;
- dom.write(&wstream);
-}
-
-#if defined(IS_FUZZING_WITH_LIBFUZZER)
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
- auto bytes = SkData::MakeWithoutCopy(data, size);
- FuzzSkJSON(bytes);
- return 0;
-}
-#endif
diff --git a/modules/skjson/src/SkJSON.cpp b/modules/skjson/src/SkJSON.cpp
deleted file mode 100644
index 2548f4ef41..0000000000
--- a/modules/skjson/src/SkJSON.cpp
+++ /dev/null
@@ -1,803 +0,0 @@
-/*
- * Copyright 2018 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "SkJSON.h"
-
-#include "SkMalloc.h"
-#include "SkStream.h"
-#include "SkString.h"
-
-#include <cmath>
-#include <tuple>
-#include <vector>
-
-namespace skjson {
-
-// #define SK_JSON_REPORT_ERRORS
-
-static_assert( sizeof(Value) == 8, "");
-static_assert(alignof(Value) == 8, "");
-
-static constexpr size_t kRecAlign = alignof(Value);
-
-void Value::init_tagged(Tag t) {
- memset(fData8, 0, sizeof(fData8));
- fData8[Value::kTagOffset] = SkTo<uint8_t>(t);
- SkASSERT(this->getTag() == t);
-}
-
-// Pointer values store a type (in the upper kTagBits bits) and a pointer.
-void Value::init_tagged_pointer(Tag t, void* p) {
- *this->cast<uintptr_t>() = reinterpret_cast<uintptr_t>(p);
-
- if (sizeof(Value) == sizeof(uintptr_t)) {
- // For 64-bit, we rely on the pointer upper bits being unused/zero.
- SkASSERT(!(fData8[kTagOffset] & kTagMask));
- fData8[kTagOffset] |= SkTo<uint8_t>(t);
- } else {
- // For 32-bit, we need to zero-initialize the upper 32 bits
- SkASSERT(sizeof(Value) == sizeof(uintptr_t) * 2);
- this->cast<uintptr_t>()[kTagOffset >> 2] = 0;
- fData8[kTagOffset] = SkTo<uint8_t>(t);
- }
-
- SkASSERT(this->getTag() == t);
- SkASSERT(this->ptr<void>() == p);
-}
-
-NullValue::NullValue() {
- this->init_tagged(Tag::kNull);
- SkASSERT(this->getTag() == Tag::kNull);
-}
-
-BoolValue::BoolValue(bool b) {
- this->init_tagged(Tag::kBool);
- *this->cast<bool>() = b;
- SkASSERT(this->getTag() == Tag::kBool);
-}
-
-NumberValue::NumberValue(int32_t i) {
- this->init_tagged(Tag::kInt);
- *this->cast<int32_t>() = i;
- SkASSERT(this->getTag() == Tag::kInt);
-}
-
-NumberValue::NumberValue(float f) {
- this->init_tagged(Tag::kFloat);
- *this->cast<float>() = f;
- SkASSERT(this->getTag() == Tag::kFloat);
-}
-
-// Vector recs point to externally allocated slabs with the following layout:
-//
-// [size_t n] [REC_0] ... [REC_n-1] [optional extra trailing storage]
-//
-// Long strings use extra_alloc_size == 1 to store the \0 terminator.
-//
-template <typename T, size_t extra_alloc_size = 0>
-static void* MakeVector(const void* src, size_t size, SkArenaAlloc& alloc) {
- // The Ts are already in memory, so their size should be safe.
- const auto total_size = sizeof(size_t) + size * sizeof(T) + extra_alloc_size;
- auto* size_ptr = reinterpret_cast<size_t*>(alloc.makeBytesAlignedTo(total_size, kRecAlign));
-
- *size_ptr = size;
- sk_careful_memcpy(size_ptr + 1, src, size * sizeof(T));
-
- return size_ptr;
-}
-
-ArrayValue::ArrayValue(const Value* src, size_t size, SkArenaAlloc& alloc) {
- this->init_tagged_pointer(Tag::kArray, MakeVector<Value>(src, size, alloc));
- SkASSERT(this->getTag() == Tag::kArray);
-}
-
-// Strings have two flavors:
-//
-// -- short strings (len <= 7) -> these are stored inline, in the record
-// (one byte reserved for null terminator/type):
-//
-// [str] [\0]|[max_len - actual_len]
-//
-// Storing [max_len - actual_len] allows the 'len' field to double-up as a
-// null terminator when size == max_len (this works 'cause kShortString == 0).
-//
-// -- long strings (len > 7) -> these are externally allocated vectors (VectorRec<char>).
-//
-// The string data plus a null-char terminator are copied over.
-//
-namespace {
-
-// An internal string builder with a fast 8 byte short string load path
-// (for the common case where the string is not at the end of the stream).
-class FastString final : public Value {
-public:
- FastString(const char* src, size_t size, const char* eos, SkArenaAlloc& alloc) {
- SkASSERT(src <= eos);
-
- if (size > kMaxInlineStringSize) {
- this->initLongString(src, size, alloc);
- SkASSERT(this->getTag() == Tag::kString);
- return;
- }
-
- static_assert(static_cast<uint8_t>(Tag::kShortString) == 0, "please don't break this");
- static_assert(sizeof(Value) == 8, "");
-
- // TODO: LIKELY
- if (src + 7 <= eos) {
- this->initFastShortString(src, size);
- } else {
- this->initShortString(src, size);
- }
-
- SkASSERT(this->getTag() == Tag::kShortString);
- }
-
-private:
- static constexpr size_t kMaxInlineStringSize = sizeof(Value) - 1;
-
- void initLongString(const char* src, size_t size, SkArenaAlloc& alloc) {
- SkASSERT(size > kMaxInlineStringSize);
-
- this->init_tagged_pointer(Tag::kString, MakeVector<char, 1>(src, size, alloc));
-
- auto* data = this->cast<VectorValue<char, Value::Type::kString>>()->begin();
- const_cast<char*>(data)[size] = '\0';
- }
-
- void initShortString(const char* src, size_t size) {
- SkASSERT(size <= kMaxInlineStringSize);
-
- this->init_tagged(Tag::kShortString);
- sk_careful_memcpy(this->cast<char>(), src, size);
- // Null terminator provided by init_tagged() above (fData8 is zero-initialized).
- }
-
- void initFastShortString(const char* src, size_t size) {
- SkASSERT(size <= kMaxInlineStringSize);
-
- // Load 8 chars and mask out the tag and \0 terminator.
- uint64_t* s64 = this->cast<uint64_t>();
- memcpy(s64, src, 8);
-
-#if defined(SK_CPU_LENDIAN)
- *s64 &= 0x00ffffffffffffffULL >> ((kMaxInlineStringSize - size) * 8);
-#else
- static_assert(false, "Big-endian builds are not supported at this time.");
-#endif
- }
-};
-
-} // namespace
-
-StringValue::StringValue(const char* src, size_t size, SkArenaAlloc& alloc) {
- new (this) FastString(src, size, src, alloc);
-}
-
-ObjectValue::ObjectValue(const Member* src, size_t size, SkArenaAlloc& alloc) {
- this->init_tagged_pointer(Tag::kObject, MakeVector<Member>(src, size, alloc));
- SkASSERT(this->getTag() == Tag::kObject);
-}
-
-
-// Boring public Value glue.
-
-const Value& ObjectValue::operator[](const char* key) const {
- // Reverse search for duplicates resolution (policy: return last).
- const auto* begin = this->begin();
- const auto* member = this->end();
-
- while (member > begin) {
- --member;
- if (0 == strcmp(key, member->fKey.as<StringValue>().begin())) {
- return member->fValue;
- }
- }
-
- static const Value g_null = NullValue();
- return g_null;
-}
-
-namespace {
-
-// Lexer/parser inspired by rapidjson [1], sajson [2] and pjson [3].
-//
-// [1] https://github.com/Tencent/rapidjson/
-// [2] https://github.com/chadaustin/sajson
-// [3] https://pastebin.com/hnhSTL3h
-
-
-// bit 0 (0x01) - plain ASCII string character
-// bit 1 (0x02) - whitespace
-// bit 2 (0x04) - string terminator (" \0 [control chars] **AND } ]** <- see matchString notes)
-// bit 3 (0x08) - 0-9
-// bit 4 (0x10) - 0-9 e E .
-// bit 5 (0x20) - scope terminator (} ])
-static constexpr uint8_t g_token_flags[256] = {
- // 0 1 2 3 4 5 6 7 8 9 A B C D E F
- 4, 4, 4, 4, 4, 4, 4, 4, 4, 6, 6, 4, 4, 6, 4, 4, // 0
- 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, // 1
- 3, 1, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0x11,1, // 2
- 0x19,0x19,0x19,0x19,0x19,0x19,0x19,0x19, 0x19,0x19, 1, 1, 1, 1, 1, 1, // 3
- 1, 1, 1, 1, 1, 0x11,1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 4
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0,0x25, 1, 1, // 5
- 1, 1, 1, 1, 1, 0x11,1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 6
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,0x25, 1, 1, // 7
-
- // 128-255
- 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,
- 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,
- 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,
- 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
-};
-
-static inline bool is_ws(char c) { return g_token_flags[static_cast<uint8_t>(c)] & 0x02; }
-static inline bool is_eostring(char c) { return g_token_flags[static_cast<uint8_t>(c)] & 0x04; }
-static inline bool is_digit(char c) { return g_token_flags[static_cast<uint8_t>(c)] & 0x08; }
-static inline bool is_numeric(char c) { return g_token_flags[static_cast<uint8_t>(c)] & 0x10; }
-static inline bool is_eoscope(char c) { return g_token_flags[static_cast<uint8_t>(c)] & 0x20; }
-
-static inline const char* skip_ws(const char* p) {
- while (is_ws(*p)) ++p;
- return p;
-}
-
-static inline float pow10(int32_t exp) {
- static constexpr float g_pow10_table[63] =
- {
- 1.e-031f, 1.e-030f, 1.e-029f, 1.e-028f, 1.e-027f, 1.e-026f, 1.e-025f, 1.e-024f,
- 1.e-023f, 1.e-022f, 1.e-021f, 1.e-020f, 1.e-019f, 1.e-018f, 1.e-017f, 1.e-016f,
- 1.e-015f, 1.e-014f, 1.e-013f, 1.e-012f, 1.e-011f, 1.e-010f, 1.e-009f, 1.e-008f,
- 1.e-007f, 1.e-006f, 1.e-005f, 1.e-004f, 1.e-003f, 1.e-002f, 1.e-001f, 1.e+000f,
- 1.e+001f, 1.e+002f, 1.e+003f, 1.e+004f, 1.e+005f, 1.e+006f, 1.e+007f, 1.e+008f,
- 1.e+009f, 1.e+010f, 1.e+011f, 1.e+012f, 1.e+013f, 1.e+014f, 1.e+015f, 1.e+016f,
- 1.e+017f, 1.e+018f, 1.e+019f, 1.e+020f, 1.e+021f, 1.e+022f, 1.e+023f, 1.e+024f,
- 1.e+025f, 1.e+026f, 1.e+027f, 1.e+028f, 1.e+029f, 1.e+030f, 1.e+031f
- };
-
- static constexpr int32_t k_exp_offset = SK_ARRAY_COUNT(g_pow10_table) / 2;
-
- // We only support negative exponents for now.
- SkASSERT(exp <= 0);
-
- return (exp >= -k_exp_offset) ? g_pow10_table[exp + k_exp_offset]
- : std::pow(10.0f, static_cast<float>(exp));
-}
-
-class DOMParser {
-public:
- explicit DOMParser(SkArenaAlloc& alloc)
- : fAlloc(alloc) {
-
- fValueStack.reserve(kValueStackReserve);
- fScopeStack.reserve(kScopeStackReserve);
- }
-
- const Value parse(const char* p, size_t size) {
- if (!size) {
- return this->error(NullValue(), p, "invalid empty input");
- }
-
- const char* p_stop = p + size - 1;
-
- // We're only checking for end-of-stream on object/array close('}',']'),
- // so we must trim any whitespace from the buffer tail.
- while (p_stop > p && is_ws(*p_stop)) --p_stop;
-
- SkASSERT(p_stop >= p && p_stop < p + size);
- if (!is_eoscope(*p_stop)) {
- return this->error(NullValue(), p_stop, "invalid top-level value");
- }
-
- p = skip_ws(p);
-
- switch (*p) {
- case '{':
- goto match_object;
- case '[':
- goto match_array;
- default:
- return this->error(NullValue(), p, "invalid top-level value");
- }
-
- match_object:
- SkASSERT(*p == '{');
- p = skip_ws(p + 1);
-
- this->pushObjectScope();
-
- if (*p == '}') goto pop_object;
-
- // goto match_object_key;
- match_object_key:
- p = skip_ws(p);
- if (*p != '"') return this->error(NullValue(), p, "expected object key");
-
- p = this->matchString(p, p_stop, [this](const char* key, size_t size, const char* eos) {
- this->pushObjectKey(key, size, eos);
- });
- if (!p) return NullValue();
-
- p = skip_ws(p);
- if (*p != ':') return this->error(NullValue(), p, "expected ':' separator");
-
- ++p;
-
- // goto match_value;
- match_value:
- p = skip_ws(p);
-
- switch (*p) {
- case '\0':
- return this->error(NullValue(), p, "unexpected input end");
- case '"':
- p = this->matchString(p, p_stop, [this](const char* str, size_t size, const char* eos) {
- this->pushString(str, size, eos);
- });
- break;
- case '[':
- goto match_array;
- case 'f':
- p = this->matchFalse(p);
- break;
- case 'n':
- p = this->matchNull(p);
- break;
- case 't':
- p = this->matchTrue(p);
- break;
- case '{':
- goto match_object;
- default:
- p = this->matchNumber(p);
- break;
- }
-
- if (!p) return NullValue();
-
- // goto match_post_value;
- match_post_value:
- SkASSERT(!fScopeStack.empty());
-
- p = skip_ws(p);
- switch (*p) {
- case ',':
- ++p;
- if (fScopeStack.back() >= 0) {
- goto match_object_key;
- } else {
- goto match_value;
- }
- case ']':
- goto pop_array;
- case '}':
- goto pop_object;
- default:
- return this->error(NullValue(), p - 1, "unexpected value-trailing token");
- }
-
- // unreachable
- SkASSERT(false);
-
- pop_object:
- SkASSERT(*p == '}');
-
- if (fScopeStack.back() < 0) {
- return this->error(NullValue(), p, "unexpected object terminator");
- }
-
- this->popObjectScope();
-
- // goto pop_common
- pop_common:
- SkASSERT(is_eoscope(*p));
-
- if (fScopeStack.empty()) {
- SkASSERT(fValueStack.size() == 1);
-
- // Success condition: parsed the top level element and reached the stop token.
- return p == p_stop
- ? fValueStack.front()
- : this->error(NullValue(), p + 1, "trailing root garbage");
- }
-
- if (p == p_stop) {
- return this->error(NullValue(), p, "unexpected end-of-input");
- }
-
- ++p;
-
- goto match_post_value;
-
- match_array:
- SkASSERT(*p == '[');
- p = skip_ws(p + 1);
-
- this->pushArrayScope();
-
- if (*p != ']') goto match_value;
-
- // goto pop_array;
- pop_array:
- SkASSERT(*p == ']');
-
- if (fScopeStack.back() >= 0) {
- return this->error(NullValue(), p, "unexpected array terminator");
- }
-
- this->popArrayScope();
-
- goto pop_common;
-
- SkASSERT(false);
- return NullValue();
- }
-
- std::tuple<const char*, const SkString> getError() const {
- return std::make_tuple(fErrorToken, fErrorMessage);
- }
-
-private:
- SkArenaAlloc& fAlloc;
-
- static constexpr size_t kValueStackReserve = 256;
- static constexpr size_t kScopeStackReserve = 128;
- std::vector<Value > fValueStack;
- std::vector<intptr_t> fScopeStack;
-
- const char* fErrorToken = nullptr;
- SkString fErrorMessage;
-
- template <typename VectorT>
- void popScopeAsVec(size_t scope_start) {
- SkASSERT(scope_start > 0);
- SkASSERT(scope_start <= fValueStack.size());
-
- using T = typename VectorT::ValueT;
- static_assert( sizeof(T) >= sizeof(Value), "");
- static_assert( sizeof(T) % sizeof(Value) == 0, "");
- static_assert(alignof(T) == alignof(Value), "");
-
- const auto scope_count = fValueStack.size() - scope_start,
- count = scope_count / (sizeof(T) / sizeof(Value));
- SkASSERT(scope_count % (sizeof(T) / sizeof(Value)) == 0);
-
- const auto* begin = reinterpret_cast<const T*>(fValueStack.data() + scope_start);
-
- // Instantiate the placeholder value added in onPush{Object/Array}.
- fValueStack[scope_start - 1] = VectorT(begin, count, fAlloc);
-
- // Drop the current scope.
- fScopeStack.pop_back();
- fValueStack.resize(scope_start);
- }
-
- void pushObjectScope() {
- // Object placeholder.
- fValueStack.emplace_back();
-
- // Object scope marker (size).
- fScopeStack.push_back(SkTo<intptr_t>(fValueStack.size()));
- }
-
- void popObjectScope() {
- const auto scope_start = fScopeStack.back();
- SkASSERT(scope_start > 0);
- this->popScopeAsVec<ObjectValue>(SkTo<size_t>(scope_start));
-
- SkDEBUGCODE(
- const auto& obj = fValueStack.back().as<ObjectValue>();
- SkASSERT(obj.is<ObjectValue>());
- for (const auto& member : obj) {
- SkASSERT(member.fKey.is<StringValue>());
- }
- )
- }
-
- void pushArrayScope() {
- // Array placeholder.
- fValueStack.emplace_back();
-
- // Array scope marker (-size).
- fScopeStack.push_back(-SkTo<intptr_t>(fValueStack.size()));
- }
-
- void popArrayScope() {
- const auto scope_start = -fScopeStack.back();
- SkASSERT(scope_start > 0);
- this->popScopeAsVec<ArrayValue>(SkTo<size_t>(scope_start));
-
- SkDEBUGCODE(
- const auto& arr = fValueStack.back().as<ArrayValue>();
- SkASSERT(arr.is<ArrayValue>());
- )
- }
-
- void pushObjectKey(const char* key, size_t size, const char* eos) {
- SkASSERT(fScopeStack.back() >= 0);
- SkASSERT(fValueStack.size() >= SkTo<size_t>(fScopeStack.back()));
- SkASSERT(!((fValueStack.size() - SkTo<size_t>(fScopeStack.back())) & 1));
- this->pushString(key, size, eos);
- }
-
- void pushTrue() {
- fValueStack.push_back(BoolValue(true));
- }
-
- void pushFalse() {
- fValueStack.push_back(BoolValue(false));
- }
-
- void pushNull() {
- fValueStack.push_back(NullValue());
- }
-
- void pushString(const char* s, size_t size, const char* eos) {
- fValueStack.push_back(FastString(s, size, eos, fAlloc));
- }
-
- void pushInt32(int32_t i) {
- fValueStack.push_back(NumberValue(i));
- }
-
- void pushFloat(float f) {
- fValueStack.push_back(NumberValue(f));
- }
-
- template <typename T>
- T error(T&& ret_val, const char* p, const char* msg) {
-#if defined(SK_JSON_REPORT_ERRORS)
- fErrorToken = p;
- fErrorMessage.set(msg);
-#endif
- return ret_val;
- }
-
- const char* matchTrue(const char* p) {
- SkASSERT(p[0] == 't');
-
- if (p[1] == 'r' && p[2] == 'u' && p[3] == 'e') {
- this->pushTrue();
- return p + 4;
- }
-
- return this->error(nullptr, p, "invalid token");
- }
-
- const char* matchFalse(const char* p) {
- SkASSERT(p[0] == 'f');
-
- if (p[1] == 'a' && p[2] == 'l' && p[3] == 's' && p[4] == 'e') {
- this->pushFalse();
- return p + 5;
- }
-
- return this->error(nullptr, p, "invalid token");
- }
-
- const char* matchNull(const char* p) {
- SkASSERT(p[0] == 'n');
-
- if (p[1] == 'u' && p[2] == 'l' && p[3] == 'l') {
- this->pushNull();
- return p + 4;
- }
-
- return this->error(nullptr, p, "invalid token");
- }
-
- template <typename MatchFunc>
- const char* matchString(const char* p, const char* p_stop, MatchFunc&& func) {
- SkASSERT(*p == '"');
- const auto* s_begin = p + 1;
-
- // TODO: unescape
-
- do {
- // Consume string chars.
- for (p = p + 1; !is_eostring(*p); ++p);
-
- if (*p == '"') {
- // Valid string found.
- func(s_begin, p - s_begin, p_stop);
- return p + 1;
- }
-
- // End-of-scope chars are special: we use them to tag the end of the input.
- // Thus they cannot be consumed indiscriminately -- we need to check if we hit the
- // end of the input. To that effect, we treat them as string terminators above,
- // then we catch them here.
- } while (is_eoscope(*p) && (p != p_stop)); // Safe scope terminator char, keep going.
-
- // Premature end-of-input, or illegal string char.
- return this->error(nullptr, s_begin - 1, "invalid string");
- }
-
- const char* matchFastFloatDecimalPart(const char* p, int sign, float f, int exp) {
- SkASSERT(exp <= 0);
-
- for (;;) {
- if (!is_digit(*p)) break;
- f = f * 10.f + (*p++ - '0'); --exp;
- if (!is_digit(*p)) break;
- f = f * 10.f + (*p++ - '0'); --exp;
- }
-
- if (is_numeric(*p)) {
- SkASSERT(*p == '.' || *p == 'e' || *p == 'E');
- // We either have malformed input, or an (unsupported) exponent.
- return nullptr;
- }
-
- this->pushFloat(sign * f * pow10(exp));
-
- return p;
- }
-
- const char* matchFastFloatPart(const char* p, int sign, float f) {
- for (;;) {
- if (!is_digit(*p)) break;
- f = f * 10.f + (*p++ - '0');
- if (!is_digit(*p)) break;
- f = f * 10.f + (*p++ - '0');
- }
-
- if (!is_numeric(*p)) {
- // Matched (integral) float.
- this->pushFloat(sign * f);
- return p;
- }
-
- return (*p == '.') ? this->matchFastFloatDecimalPart(p + 1, sign, f, 0)
- : nullptr;
- }
-
- const char* matchFast32OrFloat(const char* p) {
- int sign = 1;
- if (*p == '-') {
- sign = -1;
- ++p;
- }
-
- const auto* digits_start = p;
-
- int32_t n32 = 0;
-
- // This is the largest absolute int32 value we can handle before
- // risking overflow *on the next digit* (214748363).
- static constexpr int32_t kMaxInt32 = (std::numeric_limits<int32_t>::max() - 9) / 10;
-
- if (is_digit(*p)) {
- n32 = (*p++ - '0');
- for (;;) {
- if (!is_digit(*p) || n32 > kMaxInt32) break;
- n32 = n32 * 10 + (*p++ - '0');
- }
- }
-
- if (!is_numeric(*p)) {
- // Did we actually match any digits?
- if (p > digits_start) {
- this->pushInt32(sign * n32);
- return p;
- }
- return nullptr;
- }
-
- if (*p == '.') {
- const auto* decimals_start = ++p;
-
- int exp = 0;
-
- for (;;) {
- if (!is_digit(*p) || n32 > kMaxInt32) break;
- n32 = n32 * 10 + (*p++ - '0'); --exp;
- if (!is_digit(*p) || n32 > kMaxInt32) break;
- n32 = n32 * 10 + (*p++ - '0'); --exp;
- }
-
- if (!is_numeric(*p)) {
- // Did we actually match any digits?
- if (p > decimals_start) {
- this->pushFloat(sign * n32 * pow10(exp));
- return p;
- }
- return nullptr;
- }
-
- if (n32 > kMaxInt32) {
- // we ran out on n32 bits
- return this->matchFastFloatDecimalPart(p, sign, n32, exp);
- }
- }
-
- return this->matchFastFloatPart(p, sign, n32);
- }
-
- const char* matchNumber(const char* p) {
- if (const auto* fast = this->matchFast32OrFloat(p)) return fast;
-
- // slow fallback
- char* matched;
- float f = strtof(p, &matched);
- if (matched > p) {
- this->pushFloat(f);
- return matched;
- }
- return this->error(nullptr, p, "invalid numeric token");
- }
-};
-
-void Write(const Value& v, SkWStream* stream) {
- switch (v.getType()) {
- case Value::Type::kNull:
- stream->writeText("null");
- break;
- case Value::Type::kBool:
- stream->writeText(*v.as<BoolValue>() ? "true" : "false");
- break;
- case Value::Type::kNumber:
- stream->writeScalarAsText(*v.as<NumberValue>());
- break;
- case Value::Type::kString:
- stream->writeText("\"");
- stream->writeText(v.as<StringValue>().begin());
- stream->writeText("\"");
- break;
- case Value::Type::kArray: {
- const auto& array = v.as<ArrayValue>();
- stream->writeText("[");
- bool first_value = true;
- for (const auto& v : array) {
- if (!first_value) stream->writeText(",");
- Write(v, stream);
- first_value = false;
- }
- stream->writeText("]");
- break;
- }
- case Value::Type::kObject:
- const auto& object = v.as<ObjectValue>();
- stream->writeText("{");
- bool first_member = true;
- for (const auto& member : object) {
- SkASSERT(member.fKey.getType() == Value::Type::kString);
- if (!first_member) stream->writeText(",");
- Write(member.fKey, stream);
- stream->writeText(":");
- Write(member.fValue, stream);
- first_member = false;
- }
- stream->writeText("}");
- break;
- }
-}
-
-} // namespace
-
-SkString Value::toString() const {
- SkDynamicMemoryWStream wstream;
- Write(*this, &wstream);
- const auto data = wstream.detachAsData();
- // TODO: is there a better way to pass data around without copying?
- return SkString(static_cast<const char*>(data->data()), data->size());
-}
-
-static constexpr size_t kMinChunkSize = 4096;
-
-DOM::DOM(const char* data, size_t size)
- : fAlloc(kMinChunkSize) {
- DOMParser parser(fAlloc);
-
- fRoot = parser.parse(data, size);
-}
-
-void DOM::write(SkWStream* stream) const {
- Write(fRoot, stream);
-}
-
-} // namespace skjson
diff --git a/modules/skjson/src/SkJSONBench.cpp b/modules/skjson/src/SkJSONBench.cpp
deleted file mode 100644
index 4ef1d6c01b..0000000000
--- a/modules/skjson/src/SkJSONBench.cpp
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright 2018 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "Benchmark.h"
-#include "SkData.h"
-#include "SkJSON.h"
-#include "SkStream.h"
-
-#if defined(SK_BUILD_FOR_ANDROID)
-static constexpr const char* kBenchFile = "/data/local/tmp/bench.json";
-#else
-static constexpr const char* kBenchFile = "/tmp/bench.json";
-#endif
-
-class JsonBench : public Benchmark {
-public:
-
-protected:
- const char* onGetName() override { return "json_skjson"; }
-
- bool isSuitableFor(Backend backend) override { return backend == kNonRendering_Backend; }
-
- void onPerCanvasPreDraw(SkCanvas*) override {
- fData = SkData::MakeFromFileName(kBenchFile);
- if (!fData) {
- SkDebugf("!! Could not open bench file: %s\n", kBenchFile);
- }
- }
-
- void onPerCanvasPostDraw(SkCanvas*) override {
- fData = nullptr;
- }
-
- void onDraw(int loops, SkCanvas*) override {
- if (!fData) return;
-
- for (int i = 0; i < loops; i++) {
- skjson::DOM dom(static_cast<const char*>(fData->data()), fData->size());
- if (dom.root().is<skjson::NullValue>()) {
- SkDebugf("!! Parsing failed.\n");
- return;
- }
- }
- }
-
-private:
- sk_sp<SkData> fData;
-
- using INHERITED = Benchmark;
-};
-
-DEF_BENCH( return new JsonBench; )
-
-#if (0)
-
-#include "rapidjson/document.h"
-
-class RapidJsonBench : public Benchmark {
-public:
-
-protected:
- const char* onGetName() override { return "json_rapidjson"; }
-
- bool isSuitableFor(Backend backend) override { return backend == kNonRendering_Backend; }
-
- void onPerCanvasPreDraw(SkCanvas*) override {
- if (auto stream = SkStream::MakeFromFile(kBenchFile)) {
- SkASSERT(stream->hasLength());
- fCStringData = SkData::MakeUninitialized(stream->getLength() + 1);
- auto* data8 = reinterpret_cast<uint8_t*>(fCStringData->writable_data());
- SkAssertResult(stream->read(data8, stream->getLength()) == stream->getLength());
- data8[stream->getLength()] = '\0';
-
- } else {
- SkDebugf("!! Could not open bench file: %s\n", kBenchFile);
- }
- }
-
- void onPerCanvasPostDraw(SkCanvas*) override {
- fCStringData = nullptr;
- }
-
- void onDraw(int loops, SkCanvas*) override {
- if (!fCStringData) return;
-
- for (int i = 0; i < loops; i++) {
- rapidjson::Document doc;
- doc.Parse(static_cast<const char*>(fCStringData->data()));
- if (doc.HasParseError()) {
- SkDebugf("!! Parsing failed.\n");
- return;
- }
- }
- }
-
-private:
- sk_sp<SkData> fCStringData;
-
- using INHERITED = Benchmark;
-};
-
-DEF_BENCH( return new RapidJsonBench; )
-
-#endif
-
-#if (0)
-
-#include "pjson.h"
-
-class PJsonBench : public Benchmark {
-public:
-
-protected:
- const char* onGetName() override { return "json_pjson"; }
-
- bool isSuitableFor(Backend backend) override { return backend == kNonRendering_Backend; }
-
- void onPerCanvasPreDraw(SkCanvas*) override {
- if (auto stream = SkStream::MakeFromFile(kBenchFile)) {
- SkASSERT(stream->hasLength());
- fCStringData = SkData::MakeUninitialized(stream->getLength() + 1);
- auto* data8 = reinterpret_cast<uint8_t*>(fCStringData->writable_data());
- SkAssertResult(stream->read(data8, stream->getLength()) == stream->getLength());
- data8[stream->getLength()] = '\0';
-
- } else {
- SkDebugf("!! Could not open bench file: %s\n", kBenchFile);
- }
- }
-
- void onPerCanvasPostDraw(SkCanvas*) override {
- fCStringData = nullptr;
- }
-
- void onDraw(int loops, SkCanvas*) override {
- if (!fCStringData) return;
-
- for (int i = 0; i < loops; i++) {
- // Copy needed for in-place operation.
- auto data = SkData::MakeWithCopy(fCStringData->data(), fCStringData->size());
- pjson::document doc;
- if (!doc.deserialize_in_place(static_cast<char*>(data->writable_data()))) {
- SkDebugf("!! Parsing failed.\n");
- return;
- }
- }
- }
-
-private:
- sk_sp<SkData> fCStringData;
-
- using INHERITED = Benchmark;
-};
-
-DEF_BENCH( return new PJsonBench; )
-
-#endif
diff --git a/modules/skjson/src/SkJSONTest.cpp b/modules/skjson/src/SkJSONTest.cpp
deleted file mode 100644
index df04ac3529..0000000000
--- a/modules/skjson/src/SkJSONTest.cpp
+++ /dev/null
@@ -1,388 +0,0 @@
-/*
- * Copyright 2018 Google Inc.
- *
- * Use of this source code is governed by a BSD-style license that can be
- * found in the LICENSE file.
- */
-
-#include "Test.h"
-
-#include "SkArenaAlloc.h"
-#include "SkJSON.h"
-#include "SkString.h"
-#include "SkStream.h"
-
-using namespace skjson;
-
-DEF_TEST(SkJSON_Parse, reporter) {
- static constexpr struct {
- const char* in;
- const char* out;
- } g_tests[] = {
- { "" , nullptr },
- { "[" , nullptr },
- { "]" , nullptr },
- { "[[]" , nullptr },
- { "[]]" , nullptr },
- { "[]f" , nullptr },
- { "{" , nullptr },
- { "}" , nullptr },
- { "{{}" , nullptr },
- { "{}}" , nullptr },
- { "{}f" , nullptr },
- { "{]" , nullptr },
- { "[}" , nullptr },
- { "{\"}" , nullptr },
- { "[\"]" , nullptr },
- { "1" , nullptr },
- { "true" , nullptr },
- { "false", nullptr },
- { "null" , nullptr },
-
- { "[nulll]" , nullptr },
- { "[false2]", nullptr },
- { "[true:]" , nullptr },
-
- { "[1 2]" , nullptr },
- { "[1,,2]" , nullptr },
- { "[1,2,]" , nullptr },
- { "[,1,2]" , nullptr },
-
- { "[ \"foo" , nullptr },
- { "[ \"fo\0o\" ]" , nullptr },
-
- { "{\"\":{}" , nullptr },
- { "{ null }" , nullptr },
- { "{ \"k\" : }" , nullptr },
- { "{ : null }" , nullptr },
- { "{ \"k\" : : null }" , nullptr },
- { "{ \"k\" : null , }" , nullptr },
- { "{ \"k\" : null \"k\" : 1 }", nullptr },
-
-
- { "[]" , "[]" },
- { " \n\r\t [ \n\r\t ] \n\r\t " , "[]" },
- { "[[]]" , "[[]]" },
- { "[ null ]" , "[null]" },
- { "[ true ]" , "[true]" },
- { "[ false ]" , "[false]" },
- { "[ 0 ]" , "[0]" },
- { "[ 1 ]" , "[1]" },
- { "[ 1.248 ]" , "[1.248]" },
- { "[ \"\" ]" , "[\"\"]" },
- { "[ \"foo{bar}baz\" ]" , "[\"foo{bar}baz\"]" },
- { "[ \" f o o \" ]" , "[\" f o o \"]" },
- { "[ \"123456\" ]" , "[\"123456\"]" },
- { "[ \"1234567\" ]" , "[\"1234567\"]" },
- { "[ \"12345678\" ]" , "[\"12345678\"]" },
- { "[ \"123456789\" ]" , "[\"123456789\"]" },
- { "[ null , true, false,0,12.8 ]", "[null,true,false,0,12.8]" },
-
- { "{}" , "{}" },
- { " \n\r\t { \n\r\t } \n\r\t " , "{}" },
- { "{ \"k\" : null }" , "{\"k\":null}" },
- { "{ \"foo{\" : \"bar}baz\" }" , "{\"foo{\":\"bar}baz\"}" },
- { "{ \"k1\" : null, \"k2 \":0 }", "{\"k1\":null,\"k2 \":0}" },
- { "{ \"k1\" : null, \"k1\":0 }" , "{\"k1\":null,\"k1\":0}" },
-
- { "{ \"k1\" : null, \n\
- \"k2\" : 0, \n\
- \"k3\" : [ \n\
- true, \r\n\
- { \"kk1\" : \"foo\" , \n\
- \"kk2\" : \"bar\" , \n\
- \"kk3\" : 1.28 , \n\
- \"kk4\" : [ 42 ] \n\
- } , \n\
- \"boo\" , \n\
- null \n\
- ] \n\
- }",
- "{\"k1\":null,\"k2\":0,\"k3\":[true,"
- "{\"kk1\":\"foo\",\"kk2\":\"bar\",\"kk3\":1.28,\"kk4\":[42]},\"boo\",null]}" },
- };
-
- for (const auto& tst : g_tests) {
- DOM dom(tst.in, strlen(tst.in));
- const auto success = !dom.root().is<NullValue>();
- REPORTER_ASSERT(reporter, success == (tst.out != nullptr));
- if (!success) continue;
-
- SkDynamicMemoryWStream str;
- dom.write(&str);
- str.write8('\0');
-
- auto data = str.detachAsData();
- REPORTER_ASSERT(reporter, !strcmp(tst.out, static_cast<const char*>(data->data())));
- }
-
-}
-
-template <typename T, typename VT>
-static void check_primitive(skiatest::Reporter* reporter, const Value& v, T pv,
- bool is_type) {
-
- REPORTER_ASSERT(reporter, v.is<VT>() == is_type);
- const VT* cast_t = v;
- REPORTER_ASSERT(reporter, (cast_t != nullptr) == is_type);
-
- if (is_type) {
- REPORTER_ASSERT(reporter, &v.as<VT>() == cast_t);
- REPORTER_ASSERT(reporter, *v.as<VT>() == pv);
- }
-}
-
-template <typename T>
-static void check_vector(skiatest::Reporter* reporter, const Value& v, size_t expected_size,
- bool is_vector) {
- REPORTER_ASSERT(reporter, v.is<T>() == is_vector);
- const T* cast_t = v;
- REPORTER_ASSERT(reporter, (cast_t != nullptr) == is_vector);
-
- if (is_vector) {
- const auto& vec = v.as<T>();
- REPORTER_ASSERT(reporter, &vec == cast_t);
- REPORTER_ASSERT(reporter, vec.size() == expected_size);
- REPORTER_ASSERT(reporter, vec.begin() != nullptr);
- REPORTER_ASSERT(reporter, vec.end() == vec.begin() + expected_size);
- }
-}
-
-static void check_string(skiatest::Reporter* reporter, const Value& v, const char* s) {
- check_vector<StringValue>(reporter, v, s ? strlen(s) : 0, !!s);
- if (s) {
- REPORTER_ASSERT(reporter, !strcmp(v.as<StringValue>().begin(), s));
- }
-}
-
-DEF_TEST(SkJSON_DOM_visit, reporter) {
- static constexpr char json[] = "{ \n\
- \"k1\": null, \n\
- \"k2\": false, \n\
- \"k3\": true, \n\
- \"k4\": 42, \n\
- \"k5\": .75, \n\
- \"k6\": \"foo\", \n\
- \"k7\": [ 1, true, \"bar\" ], \n\
- \"k8\": { \"kk1\": 2, \"kk2\": false, \"kk1\": \"baz\" } \n\
- }";
-
- DOM dom(json, strlen(json));
-
- const auto& jroot = dom.root().as<ObjectValue>();
- REPORTER_ASSERT(reporter, jroot.is<ObjectValue>());
-
- {
- const auto& v = jroot["k1"];
- REPORTER_ASSERT(reporter, v.is<NullValue>());
-
- check_primitive<bool, BoolValue>(reporter, v, false, false);
- check_primitive<float, NumberValue>(reporter, v, 0, false);
-
- check_string(reporter, v, nullptr);
- check_vector<ArrayValue >(reporter, v, 0, false);
- check_vector<ObjectValue>(reporter, v, 0, false);
- }
-
- {
- const auto& v = jroot["k2"];
- REPORTER_ASSERT(reporter, !v.is<NullValue>());
-
- check_primitive<bool, BoolValue>(reporter, v, false, true);
- check_primitive<float, NumberValue>(reporter, v, 0, false);
-
- check_string(reporter, v, nullptr);
- check_vector<ArrayValue >(reporter, v, 0, false);
- check_vector<ObjectValue>(reporter, v, 0, false);
- }
-
- {
- const auto& v = jroot["k3"];
- REPORTER_ASSERT(reporter, !v.is<NullValue>());
-
- check_primitive<bool, BoolValue>(reporter, v, true, true);
- check_primitive<float, NumberValue>(reporter, v, 0, false);
-
- check_string(reporter, v, nullptr);
- check_vector<ArrayValue >(reporter, v, 0, false);
- check_vector<ObjectValue>(reporter, v, 0, false);
- }
-
- {
- const auto& v = jroot["k4"];
- REPORTER_ASSERT(reporter, !v.is<NullValue>());
-
- check_primitive<bool, BoolValue>(reporter, v, false, false);
- check_primitive<float, NumberValue>(reporter, v, 42, true);
-
- check_string(reporter, v, nullptr);
- check_vector<ArrayValue >(reporter, v, 0, false);
- check_vector<ObjectValue>(reporter, v, 0, false);
- }
-
- {
- const auto& v = jroot["k5"];
- REPORTER_ASSERT(reporter, !v.is<NullValue>());
-
- check_primitive<bool, BoolValue>(reporter, v, false, false);
- check_primitive<float, NumberValue>(reporter, v, .75f, true);
-
- check_string(reporter, v, nullptr);
- check_vector<ArrayValue >(reporter, v, 0, false);
- check_vector<ObjectValue>(reporter, v, 0, false);
- }
-
- {
- const auto& v = jroot["k6"];
- REPORTER_ASSERT(reporter, !v.is<NullValue>());
-
- check_primitive<bool, BoolValue>(reporter, v, false, false);
- check_primitive<float, NumberValue>(reporter, v, 0, false);
-
- check_string(reporter, v, "foo");
- check_vector<ArrayValue >(reporter, v, 0, false);
- check_vector<ObjectValue>(reporter, v, 0, false);
- }
-
- {
- const auto& v = jroot["k7"];
- REPORTER_ASSERT(reporter, !v.is<NullValue>());
-
- check_primitive<bool, BoolValue>(reporter, v, false, false);
- check_primitive<float, NumberValue>(reporter, v, 0, false);
-
- check_string(reporter, v, nullptr);
- check_vector<ObjectValue>(reporter, v, 0, false);
-
- check_vector<ArrayValue >(reporter, v, 3, true);
- check_primitive<float, NumberValue>(reporter, v.as<ArrayValue>()[0], 1, true);
- check_primitive<bool, BoolValue>(reporter, v.as<ArrayValue>()[1], true, true);
- check_vector<StringValue>(reporter, v.as<ArrayValue>()[2], 3, true);
- }
-
- {
- const auto& v = jroot["k8"];
- REPORTER_ASSERT(reporter, !v.is<NullValue>());
-
- check_primitive<bool, BoolValue>(reporter, v, false, false);
- check_primitive<float, NumberValue>(reporter, v, 0, false);
-
- check_string(reporter, v, nullptr);
- check_vector<ArrayValue >(reporter, v, 0, false);
-
- check_vector<ObjectValue>(reporter, v, 3, true);
-
- const auto& m0 = v.as<ObjectValue>().begin()[0];
- check_string(reporter, m0.fKey, "kk1");
- check_primitive<float, NumberValue>(reporter, m0.fValue, 2, true);
-
- const auto& m1 = v.as<ObjectValue>().begin()[1];
- check_string(reporter, m1.fKey, "kk2");
- check_primitive<bool, BoolValue>(reporter, m1.fValue, false, true);
-
- const auto& m2 = v.as<ObjectValue>().begin()[2];
- check_string(reporter, m2.fKey, "kk1");
- check_string(reporter, m2.fValue, "baz");
-
- REPORTER_ASSERT(reporter, v.as<ObjectValue>()[""].is<NullValue>());
- REPORTER_ASSERT(reporter, v.as<ObjectValue>()["nosuchkey"].is<NullValue>());
- check_string(reporter, v.as<ObjectValue>()["kk1"], "baz");
- check_primitive<bool, BoolValue>(reporter, v.as<ObjectValue>()["kk2"], false, true);
- }
-}
-
-template <typename T>
-void check_value(skiatest::Reporter* reporter, const Value& v, const char* expected_string) {
- REPORTER_ASSERT(reporter, v.is<T>());
-
- const T* cast_t = v;
- REPORTER_ASSERT(reporter, cast_t == &v.as<T>());
-
- const auto vstr = v.toString();
- REPORTER_ASSERT(reporter, 0 == strcmp(expected_string, vstr.c_str()));
-}
-
-DEF_TEST(SkJSON_DOM_build, reporter) {
- SkArenaAlloc alloc(4096);
-
- const auto v0 = NullValue();
- check_value<NullValue>(reporter, v0, "null");
-
- const auto v1 = BoolValue(true);
- check_value<BoolValue>(reporter, v1, "true");
-
- const auto v2 = BoolValue(false);
- check_value<BoolValue>(reporter, v2, "false");
-
- const auto v3 = NumberValue(0);
- check_value<NumberValue>(reporter, v3, "0");
-
- const auto v4 = NumberValue(42);
- check_value<NumberValue>(reporter, v4, "42");
-
- const auto v5 = NumberValue(42.75f);
- check_value<NumberValue>(reporter, v5, "42.75");
-
- const auto v6 = StringValue(nullptr, 0, alloc);
- check_value<StringValue>(reporter, v6, "\"\"");
-
- const auto v7 = StringValue(" foo ", 5, alloc);
- check_value<StringValue>(reporter, v7, "\" foo \"");
-
- const auto v8 = StringValue(" foo bar baz ", 13, alloc);
- check_value<StringValue>(reporter, v8, "\" foo bar baz \"");
-
- const auto v9 = ArrayValue(nullptr, 0, alloc);
- check_value<ArrayValue>(reporter, v9, "[]");
-
- const Value values0[] = { v0, v3, v9 };
- const auto v10 = ArrayValue(values0, SK_ARRAY_COUNT(values0), alloc);
- check_value<ArrayValue>(reporter, v10, "[null,0,[]]");
-
- const auto v11 = ObjectValue(nullptr, 0, alloc);
- check_value<ObjectValue>(reporter, v11, "{}");
-
- const Member members0[] = {
- { StringValue("key_0", 5, alloc), v1 },
- { StringValue("key_1", 5, alloc), v4 },
- { StringValue("key_2", 5, alloc), v11 },
- };
- const auto v12 = ObjectValue(members0, SK_ARRAY_COUNT(members0), alloc);
- check_value<ObjectValue>(reporter, v12, "{"
- "\"key_0\":true,"
- "\"key_1\":42,"
- "\"key_2\":{}"
- "}");
-
- const Value values1[] = { v2, v6, v12 };
- const auto v13 = ArrayValue(values1, SK_ARRAY_COUNT(values1), alloc);
- check_value<ArrayValue>(reporter, v13, "["
- "false,"
- "\"\","
- "{"
- "\"key_0\":true,"
- "\"key_1\":42,"
- "\"key_2\":{}"
- "}"
- "]");
-
- const Member members1[] = {
- { StringValue("key_00", 6, alloc), v5 },
- { StringValue("key_01", 6, alloc), v7 },
- { StringValue("key_02", 6, alloc), v13 },
- };
- const auto v14 = ObjectValue(members1, SK_ARRAY_COUNT(members1), alloc);
- check_value<ObjectValue>(reporter, v14, "{"
- "\"key_00\":42.75,"
- "\"key_01\":\" foo \","
- "\"key_02\":["
- "false,"
- "\"\","
- "{"
- "\"key_0\":true,"
- "\"key_1\":42,"
- "\"key_2\":{}"
- "}"
- "]"
- "}");
-}
diff --git a/modules/skottie/BUILD.gn b/modules/skottie/BUILD.gn
index 9442592968..afa2769add 100644
--- a/modules/skottie/BUILD.gn
+++ b/modules/skottie/BUILD.gn
@@ -34,7 +34,6 @@ source_set("skottie") {
configs += [ "../../:skia_private" ]
deps = [
"../..:skia",
- "../skjson",
"../sksg",
]
}