/* * 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 "SkTypes.h" 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 freely converted to any of the facade types for type-specific functionality. * * Note: type checking is lazy/deferred, to facilitate chained property access - e.g. * * if (!v.as()["foo"].as()["bar"].is()) * LOG("found v.foo.bar!"); */ class alignas(8) Value { public: enum class Type { kNull, kBool, kNumber, kString, kArray, kObject, }; /** * @return The public type of this record. */ Type getType() const; /** * @return True if the record matches the facade type T. */ template bool is() const { return T::IsType(this->getType()); } /** * @return The record cast as facade type T. * * Note: this is always safe, as proper typing is enforced in the facade methods. */ template const T& as() const { return *reinterpret_cast(this->is() ? this : &Value::Null()); } /** * @return Null value singleton. */ static const Value& Null(); protected: uint8_t fData8[8]; }; class NullValue final : public Value { public: static bool IsType(Value::Type t) { return t == Type::kNull; } }; template class PrimitiveValue final : public Value { public: static bool IsType(Value::Type t) { return t == vtype; } T operator *() const; }; template class VectorValue : public Value { public: static bool IsType(Value::Type t) { return t == vtype; } size_t size() const; const T* begin() const; const T* end() const; const T& operator[](size_t i) const { return (i < this->size()) ? *(this->begin() + i) : T::Null(); } }; using BoolValue = PrimitiveValue; using NumberValue = PrimitiveValue; using StringValue = VectorValue; using ArrayValue = VectorValue; struct Member { StringValue fKey; Value fValue; static const Member& Null(); }; class ObjectValue final : public VectorValue { public: const Value& operator[](const char*) const; }; class DOM final : public SkNoncopyable { public: explicit DOM(const char*); const Value& root() const { return *fRoot; } void write(SkWStream*) const; private: SkArenaAlloc fAlloc; const Value* fRoot; }; } // namespace skjson #endif // SkJSON_DEFINED