diff options
Diffstat (limited to 'modules/skjson/include/SkJSON.h')
-rw-r--r-- | modules/skjson/include/SkJSON.h | 139 |
1 files changed, 139 insertions, 0 deletions
diff --git a/modules/skjson/include/SkJSON.h b/modules/skjson/include/SkJSON.h new file mode 100644 index 0000000000..4cb312c64f --- /dev/null +++ b/modules/skjson/include/SkJSON.h @@ -0,0 +1,139 @@ +/* + * 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<ObjectValue>()["foo"].as<ObjectValue>()["bar"].is<NullValue>()) + * 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 <typename T> + 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 <typename T> + const T& as() const { + return *reinterpret_cast<const T*>(this->is<T>() ? 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 <typename T, Value::Type vtype> +class PrimitiveValue final : public Value { +public: + static bool IsType(Value::Type t) { return t == vtype; } + + T operator *() const; +}; + +template <typename T, Value::Type vtype> +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<bool , Value::Type::kBool >; +using NumberValue = PrimitiveValue<double, Value::Type::kNumber>; +using StringValue = VectorValue<char , Value::Type::kString>; +using ArrayValue = VectorValue<Value , Value::Type::kArray >; + +struct Member { + StringValue fKey; + Value fValue; + + static const Member& Null(); +}; + +class ObjectValue final : public VectorValue<Member, Value::Type::kObject> { +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 + |