diff options
Diffstat (limited to 'modules/skjson/include/SkJSON.h')
-rw-r--r-- | modules/skjson/include/SkJSON.h | 360 |
1 files changed, 0 insertions, 360 deletions
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 - |