blob: 4cb312c64ff9f636bbb6cf463cba4c3438bf12a8 [file] [log] [blame]
/*
* 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