Initial release
This commit is contained in:
@@ -0,0 +1,407 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
// Project : VST SDK
|
||||
// Flags : clang-format SMTGSequencer
|
||||
//
|
||||
// Category :
|
||||
// Filename : public.sdk/source/vst/moduleinfo/jsoncxx.h
|
||||
// Created by : Steinberg, 12/2021
|
||||
// Description :
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
// This file is part of a Steinberg SDK. It is subject to the license terms
|
||||
// in the LICENSE file found in the top-level directory of this distribution
|
||||
// and at www.steinberg.net/sdklicenses.
|
||||
// No part of the SDK, including this file, may be copied, modified, propagated,
|
||||
// or distributed except according to the terms contained in the LICENSE file.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "json.h"
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <variant>
|
||||
|
||||
#if defined(_MSC_VER) || __has_include(<charconv>)
|
||||
#include <charconv>
|
||||
#define SMTG_HAS_CHARCONV
|
||||
#endif
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
namespace JSON {
|
||||
namespace Detail {
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template <typename JsonT>
|
||||
struct Base
|
||||
{
|
||||
explicit Base (JsonT* o) : object_ (o) {}
|
||||
explicit Base (const Base& o) : object_ (o.object_) {}
|
||||
|
||||
Base& operator= (const Base& o) = default;
|
||||
|
||||
operator JsonT* () const { return object_; }
|
||||
JsonT* jsonValue () const { return object_; }
|
||||
|
||||
protected:
|
||||
Base () : object_ (nullptr) {}
|
||||
|
||||
JsonT* object_;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template <typename JsonElement>
|
||||
struct Iterator
|
||||
{
|
||||
explicit Iterator (JsonElement el) : el (el) {}
|
||||
|
||||
bool operator== (const Iterator& other) const { return other.el == el; }
|
||||
bool operator!= (const Iterator& other) const { return other.el != el; }
|
||||
|
||||
const JsonElement& operator* () const { return el; }
|
||||
const JsonElement& operator-> () const { return el; }
|
||||
|
||||
Iterator& operator++ ()
|
||||
{
|
||||
if (el)
|
||||
el = el.next ();
|
||||
return *this;
|
||||
}
|
||||
|
||||
Iterator operator++ (int)
|
||||
{
|
||||
auto it = Iterator (el);
|
||||
operator++ ();
|
||||
return it;
|
||||
}
|
||||
|
||||
private:
|
||||
JsonElement el;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
} // Detail
|
||||
|
||||
struct Object;
|
||||
struct Array;
|
||||
struct String;
|
||||
struct Number;
|
||||
struct Boolean;
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
enum class Type
|
||||
{
|
||||
Object,
|
||||
Array,
|
||||
String,
|
||||
Number,
|
||||
True,
|
||||
False,
|
||||
Null,
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
struct SourceLocation
|
||||
{
|
||||
size_t offset;
|
||||
size_t line;
|
||||
size_t row;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
struct Value : Detail::Base<json_value_s>
|
||||
{
|
||||
using Detail::Base<json_value_s>::Base;
|
||||
using VariantT = std::variant<Object, Array, String, Number, Boolean, std::nullptr_t>;
|
||||
|
||||
std::optional<Object> asObject () const;
|
||||
std::optional<Array> asArray () const;
|
||||
std::optional<String> asString () const;
|
||||
std::optional<Number> asNumber () const;
|
||||
std::optional<Boolean> asBoolean () const;
|
||||
std::optional<std::nullptr_t> asNull () const;
|
||||
|
||||
VariantT asVariant () const;
|
||||
Type type () const;
|
||||
|
||||
SourceLocation getSourceLocation () const;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
struct Boolean
|
||||
{
|
||||
Boolean (size_t type) : value (type == json_type_true) {}
|
||||
|
||||
operator bool () const { return value; }
|
||||
|
||||
private:
|
||||
bool value;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
struct String : Detail::Base<json_string_s>
|
||||
{
|
||||
using Detail::Base<json_string_s>::Base;
|
||||
|
||||
std::string_view text () const { return {jsonValue ()->string, jsonValue ()->string_size}; }
|
||||
|
||||
SourceLocation getSourceLocation () const;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
struct Number : Detail::Base<json_number_s>
|
||||
{
|
||||
using Detail::Base<json_number_s>::Base;
|
||||
|
||||
std::string_view text () const { return {jsonValue ()->number, jsonValue ()->number_size}; }
|
||||
|
||||
std::optional<int64_t> getInteger () const;
|
||||
std::optional<double> getDouble () const;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
struct ObjectElement : Detail::Base<json_object_element_s>
|
||||
{
|
||||
using Detail::Base<json_object_element_s>::Base;
|
||||
|
||||
String name () const { return String (jsonValue ()->name); }
|
||||
Value value () const { return Value (jsonValue ()->value); }
|
||||
|
||||
ObjectElement next () const { return ObjectElement (jsonValue ()->next); }
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
struct Object : Detail::Base<json_object_s>
|
||||
{
|
||||
using Detail::Base<json_object_s>::Base;
|
||||
using Iterator = Detail::Iterator<ObjectElement>;
|
||||
|
||||
size_t size () const { return jsonValue ()->length; }
|
||||
|
||||
Iterator begin () const { return Iterator (ObjectElement (jsonValue ()->start)); }
|
||||
Iterator end () const { return Iterator (ObjectElement (nullptr)); }
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
struct ArrayElement : Detail::Base<json_array_element_s>
|
||||
{
|
||||
using Detail::Base<json_array_element_s>::Base;
|
||||
|
||||
Value value () const { return Value (jsonValue ()->value); }
|
||||
|
||||
ArrayElement next () const { return ArrayElement (jsonValue ()->next); }
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
struct Array : Detail::Base<json_array_s>
|
||||
{
|
||||
using Detail::Base<json_array_s>::Base;
|
||||
using Iterator = Detail::Iterator<ArrayElement>;
|
||||
|
||||
size_t size () const { return jsonValue ()->length; }
|
||||
|
||||
Iterator begin () const { return Iterator (ArrayElement (jsonValue ()->start)); }
|
||||
Iterator end () const { return Iterator (ArrayElement (nullptr)); }
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
struct Document : Value
|
||||
{
|
||||
static std::variant<Document, json_parse_result_s> parse (std::string_view data)
|
||||
{
|
||||
auto allocate = [] (void*, size_t allocSize) { return std::malloc (allocSize); };
|
||||
json_parse_result_s parse_result {};
|
||||
auto value = json_parse_ex (data.data (), data.size (),
|
||||
json_parse_flags_allow_json5 |
|
||||
json_parse_flags_allow_location_information,
|
||||
allocate, nullptr, &parse_result);
|
||||
if (value)
|
||||
return Document (value);
|
||||
return parse_result;
|
||||
}
|
||||
~Document () noexcept
|
||||
{
|
||||
if (object_)
|
||||
std::free (object_);
|
||||
}
|
||||
|
||||
Document (Document&& doc) noexcept { *this = std::move (doc); }
|
||||
Document& operator= (Document&& doc) noexcept
|
||||
{
|
||||
std::swap (object_, doc.object_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
using Value::Value;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline std::optional<Object> Value::asObject () const
|
||||
{
|
||||
if (type () != Type::Object)
|
||||
return {};
|
||||
return Object (json_value_as_object (jsonValue ()));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline std::optional<Array> Value::asArray () const
|
||||
{
|
||||
if (type () != Type::Array)
|
||||
return {};
|
||||
return Array (json_value_as_array (jsonValue ()));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline std::optional<String> Value::asString () const
|
||||
{
|
||||
if (type () != Type::String)
|
||||
return {};
|
||||
return String (json_value_as_string (jsonValue ()));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline std::optional<Number> Value::asNumber () const
|
||||
{
|
||||
if (type () != Type::Number)
|
||||
return {};
|
||||
return Number (json_value_as_number (jsonValue ()));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline std::optional<Boolean> Value::asBoolean () const
|
||||
{
|
||||
if (type () == Type::True || type () == Type::False)
|
||||
return Boolean (jsonValue ()->type);
|
||||
return {};
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline std::optional<std::nullptr_t> Value::asNull () const
|
||||
{
|
||||
if (type () != Type::Null)
|
||||
return {};
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline Type Value::type () const
|
||||
{
|
||||
switch (jsonValue ()->type)
|
||||
{
|
||||
case json_type_string: return Type::String;
|
||||
case json_type_number: return Type::Number;
|
||||
case json_type_object: return Type::Object;
|
||||
case json_type_array: return Type::Array;
|
||||
case json_type_true: return Type::True;
|
||||
case json_type_false: return Type::False;
|
||||
case json_type_null: return Type::Null;
|
||||
}
|
||||
assert (false);
|
||||
return Type::Null;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline Value::VariantT Value::asVariant () const
|
||||
{
|
||||
switch (type ())
|
||||
{
|
||||
case Type::String: return *asString ();
|
||||
case Type::Number: return *asNumber ();
|
||||
case Type::Object: return *asObject ();
|
||||
case Type::Array: return *asArray ();
|
||||
case Type::True: return *asBoolean ();
|
||||
case Type::False: return *asBoolean ();
|
||||
case Type::Null: return *asNull ();
|
||||
}
|
||||
assert (false);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline SourceLocation Value::getSourceLocation () const
|
||||
{
|
||||
auto exValue = reinterpret_cast<json_value_ex_s*> (jsonValue ());
|
||||
return {exValue->offset, exValue->line_no, exValue->row_no};
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline SourceLocation String::getSourceLocation () const
|
||||
{
|
||||
auto exValue = reinterpret_cast<json_string_ex_s*> (jsonValue ());
|
||||
return {exValue->offset, exValue->line_no, exValue->row_no};
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline std::optional<int64_t> Number::getInteger () const
|
||||
{
|
||||
#if defined(SMTG_HAS_CHARCONV)
|
||||
int64_t result {0};
|
||||
auto res = std::from_chars (jsonValue ()->number,
|
||||
jsonValue ()->number + jsonValue ()->number_size, result);
|
||||
if (res.ec == std::errc ())
|
||||
return result;
|
||||
return {};
|
||||
#else
|
||||
int64_t result {0};
|
||||
std::string str (jsonValue ()->number, jsonValue ()->number + jsonValue ()->number_size);
|
||||
if (std::sscanf (str.data (), "%lld", &result) != 1)
|
||||
return {};
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline std::optional<double> Number::getDouble () const
|
||||
{
|
||||
#if 1 // clang still has no floting point from_chars version
|
||||
size_t ctrl {0};
|
||||
auto result = std::stod (std::string (jsonValue ()->number, jsonValue ()->number_size), &ctrl);
|
||||
if (ctrl > 0)
|
||||
return result;
|
||||
#else
|
||||
double result {0.};
|
||||
auto res = std::from_chars (jsonValue ()->number,
|
||||
jsonValue ()->number + jsonValue ()->number_size, result);
|
||||
if (res.ec == std::errc ())
|
||||
return result;
|
||||
#endif
|
||||
return {};
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline std::string_view errorToString (json_parse_error_e error)
|
||||
{
|
||||
switch (error)
|
||||
{
|
||||
case json_parse_error_e::json_parse_error_none: return {};
|
||||
case json_parse_error_e::json_parse_error_expected_comma_or_closing_bracket:
|
||||
return "json_parse_error_expected_comma_or_closing_bracket";
|
||||
case json_parse_error_e::json_parse_error_expected_colon:
|
||||
return "json_parse_error_expected_colon";
|
||||
case json_parse_error_e::json_parse_error_expected_opening_quote:
|
||||
return "json_parse_error_expected_opening_quote";
|
||||
case json_parse_error_e::json_parse_error_invalid_string_escape_sequence:
|
||||
return "json_parse_error_invalid_string_escape_sequence";
|
||||
case json_parse_error_e::json_parse_error_invalid_number_format:
|
||||
return "json_parse_error_invalid_number_format";
|
||||
case json_parse_error_e::json_parse_error_invalid_value:
|
||||
return "json_parse_error_invalid_value";
|
||||
case json_parse_error_e::json_parse_error_premature_end_of_buffer:
|
||||
return "json_parse_error_premature_end_of_buffer";
|
||||
case json_parse_error_e::json_parse_error_invalid_string:
|
||||
return "json_parse_error_invalid_string";
|
||||
case json_parse_error_e::json_parse_error_allocator_failed:
|
||||
return "json_parse_error_allocator_failed";
|
||||
case json_parse_error_e::json_parse_error_unexpected_trailing_characters:
|
||||
return "json_parse_error_unexpected_trailing_characters";
|
||||
case json_parse_error_e::json_parse_error_unknown: return "json_parse_error_unknown";
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
} // JSON
|
||||
Reference in New Issue
Block a user