756 lines
19 KiB
C++
Executable File
756 lines
19 KiB
C++
Executable File
/**
|
|
* @RDE_HEADER@
|
|
* JsonObject
|
|
* $Id$
|
|
* $HeadURL$
|
|
* $Author$
|
|
* Created by Christian Fröbel, SLSE, 2017-10-26
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <QJsonArray>
|
|
#include <QJsonDocument>
|
|
#include <QJsonObject>
|
|
#include <QJsonParseError>
|
|
#include <QJsonValue>
|
|
#include <QVector>
|
|
#include <QMap>
|
|
#include <QString>
|
|
#include <string>
|
|
#include <vector>
|
|
#include <map>
|
|
#include <exception>
|
|
#include <cstdint>
|
|
#include <limits>
|
|
|
|
namespace LtsUtils
|
|
{
|
|
|
|
class JsonParseError : public std::runtime_error
|
|
{
|
|
public:
|
|
JsonParseError(const QJsonParseError &err)
|
|
: std::runtime_error("json parse error: " + err.errorString().toStdString() + " - at offset " + std::to_string(err.offset)){}
|
|
};
|
|
|
|
class JsonError : public std::runtime_error
|
|
{
|
|
public:
|
|
using std::runtime_error::runtime_error;
|
|
};
|
|
|
|
class JsonKeyError : public JsonError
|
|
{
|
|
public:
|
|
using JsonError::JsonError;
|
|
};
|
|
|
|
class JsonRangeError : public JsonError
|
|
{
|
|
public:
|
|
using JsonError::JsonError;
|
|
};
|
|
|
|
class JsonTypeError : public JsonError
|
|
{
|
|
public:
|
|
using JsonError::JsonError;
|
|
};
|
|
|
|
|
|
/**
|
|
* A Wrapper for QJsonObject for typesafe, explicit and strict access.
|
|
* @author Christian Fröbel
|
|
*/
|
|
class JsonObject
|
|
{
|
|
public:
|
|
/**
|
|
* Just a small helper class we use for the key which can
|
|
* be implicitly created from a QString, std::string, const char*.
|
|
* Encoding of std::string and const char* is assumed to be utf-8.
|
|
* Should not be used explicitly be the user.
|
|
*/
|
|
class Key;
|
|
|
|
JsonObject() = default;
|
|
explicit JsonObject(const QJsonObject &json)
|
|
: m_json(json)
|
|
, m_jsonIsSet(true)
|
|
{}
|
|
|
|
explicit JsonObject(QJsonObject &&json)
|
|
: m_json(std::move(json))
|
|
, m_jsonIsSet(true)
|
|
{}
|
|
|
|
// JsonObject(JsonObject &&json)
|
|
// : m_json(std::move(json.m_json))
|
|
// , m_jsonIsSet(true)
|
|
// {}
|
|
|
|
/**
|
|
* create a JsonObject out of some data, returns an empty array if it could not be parsed
|
|
*/
|
|
///@{
|
|
static inline JsonObject fromJson(const char *json, int len = -1);
|
|
static inline JsonObject fromJson(const QByteArray &json) { return fromJson(json.data(), json.size()); }
|
|
static inline JsonObject fromJson(const std::string &json) { return fromJson(json.c_str(), json.size()); }
|
|
|
|
static inline JsonObject fromJsonSafe(const char *json, int len = -1) noexcept(false);
|
|
static inline JsonObject fromJsonSafe(const QByteArray &json) noexcept(false) { return fromJsonSafe(json.data(), json.size()); }
|
|
static inline JsonObject fromJsonSafe(const std::string &json) noexcept(false) { return fromJsonSafe(json.c_str(), json.size()); }
|
|
///@}
|
|
|
|
/**
|
|
* @return true if the JsonObject contains an element with that name and that element is of type T.
|
|
* @see value() for allowed types for T.
|
|
*/
|
|
template<class T>
|
|
bool contains(const Key &key) const;
|
|
|
|
bool isNull(const Key &key) const { return contains<void>(key); }
|
|
|
|
bool isEmpty() const { return m_json.isEmpty(); }
|
|
bool isValid() const { return m_jsonIsSet; }
|
|
|
|
/**
|
|
* Retrieve a value of a given type T.
|
|
* T can be an integer type (unsigned/signed 16-, 32-, 64-bit),
|
|
* double, bool, QString, std::string, QJsonObject, JsonObject, QJsonArray, JsonArray,
|
|
* QVector<T>, std::vector<T>, QMap<QString, T> and std::map<std::string, T>
|
|
* where T is one of the given types (recursively).
|
|
* @throw JsonKeyError if an element with that key does not exist.
|
|
* @throw JsonTypeError if the requested type of the element does not match.
|
|
*/
|
|
template<class T>
|
|
T value(const Key &key) const noexcept(false);
|
|
|
|
/**
|
|
* Same as value() but return a default value if no element with that key exists.
|
|
* @throw JsonTypeError if an element with that key exists but has a non-macthing type.
|
|
*/
|
|
template<class T>
|
|
T valueOr(const Key &key, const T &defaultValue) const noexcept(false);
|
|
|
|
|
|
/**
|
|
* Check whether all values of this JsonObject are of type T.
|
|
* If true, toMap()/toStdMap() will succeed.
|
|
*/
|
|
template<class T>
|
|
bool isMap() const;
|
|
|
|
/**
|
|
* Convert this JsonObject into a map with values of type T.
|
|
* @throw JsonTypeError if some value is not of type T.
|
|
* @see value() for allowed types of T.
|
|
*/
|
|
template<class T>
|
|
QMap<QString, T> toMap() const noexcept(false);
|
|
|
|
/** Same as toMap(). */
|
|
template<class T>
|
|
std::map<std::string, T> toStdMap() const;
|
|
|
|
bool operator==(const JsonObject &other) const { return m_json == other.m_json; }
|
|
bool operator!=(const JsonObject &other) const { return !(*this == other); }
|
|
|
|
class Key
|
|
{
|
|
public:
|
|
Key(const QString &s)
|
|
: m_s(s)
|
|
{}
|
|
|
|
Key(const std::string &s)
|
|
: m_s(QString::fromStdString(s))
|
|
{}
|
|
|
|
Key(const char *s)
|
|
: m_s(QString::fromUtf8(s))
|
|
{}
|
|
|
|
operator const QString &() const { return m_s; }
|
|
|
|
private:
|
|
const QString m_s;
|
|
};
|
|
|
|
operator const QJsonObject &() const { return m_json; }
|
|
const QJsonObject &object() const { return m_json; }
|
|
|
|
private:
|
|
bool containsAny(const QString &key) const { return m_json.contains(key); }
|
|
|
|
QJsonObject m_json;
|
|
bool m_jsonIsSet = false;
|
|
};
|
|
|
|
JsonObject JsonObject::fromJson(const char *json, int len)
|
|
{
|
|
if (len < 0)
|
|
len = strlen(json);
|
|
QJsonParseError error;
|
|
const auto doc = QJsonDocument::fromJson(QByteArray::fromRawData(json, len), &error);
|
|
if (error.error != QJsonParseError::NoError)
|
|
return JsonObject();
|
|
|
|
if (!doc.isObject())
|
|
return JsonObject();
|
|
|
|
return JsonObject(doc.object());
|
|
}
|
|
|
|
JsonObject JsonObject::fromJsonSafe(const char *json, int len) noexcept(false)
|
|
{
|
|
if (len < 0)
|
|
len = strlen(json);
|
|
QJsonParseError error;
|
|
const auto doc = QJsonDocument::fromJson(QByteArray::fromRawData(json, len), &error);
|
|
if (error.error != QJsonParseError::NoError)
|
|
throw JsonParseError(error);
|
|
|
|
if (!doc.isObject())
|
|
throw JsonTypeError("JSON root is not an object");
|
|
|
|
return JsonObject(doc.object());
|
|
}
|
|
|
|
//==============================================================================
|
|
|
|
/**
|
|
* A Wrapper for QJsonArray for typesafe, explicit and strict access.
|
|
* @author Christian Fröbel
|
|
*/
|
|
class JsonArray
|
|
{
|
|
public:
|
|
JsonArray() = default;
|
|
explicit JsonArray(const QJsonArray &json)
|
|
: m_json(json)
|
|
, m_jsonIsSet(true)
|
|
{}
|
|
|
|
explicit JsonArray(QJsonArray &&json)
|
|
: m_json(std::move(json))
|
|
, m_jsonIsSet(true)
|
|
{}
|
|
|
|
// JsonArray(JsonArray &&json)
|
|
// : m_json(std::move(json.m_json))
|
|
// , m_jsonIsSet(true)
|
|
// {}
|
|
|
|
// JsonArray& operator=(JsonArray&& json)
|
|
// {
|
|
// m_json = std::move(json.m_json);
|
|
// m_jsonIsSet = json.m_jsonIsSet;
|
|
// return *this;
|
|
// }
|
|
|
|
/**
|
|
* create a JsonArray out of some data, returns an empty array if it could not be parsed
|
|
*/
|
|
///@{
|
|
static inline JsonArray fromJson(const char *json, int len = -1);
|
|
static inline JsonArray fromJson(const QByteArray &json) { return fromJson(json.data(), json.size()); }
|
|
static inline JsonArray fromJson(const std::string &json) { return fromJson(json.c_str(), json.size()); }
|
|
|
|
static inline JsonArray fromJsonSafe(const char *json, int len = -1) noexcept(false);
|
|
static inline JsonArray fromJsonSafe(const QByteArray &json) noexcept(false) { return fromJson(json.data(), json.size()); }
|
|
static inline JsonArray fromJsonSafe(const std::string &json) noexcept(false) { return fromJson(json.c_str(), json.size()); }
|
|
///@}
|
|
|
|
int size() const { return m_json.size(); }
|
|
bool isEmpty() const { return m_json.isEmpty(); }
|
|
bool isValid() const { return m_jsonIsSet; }
|
|
|
|
/** @throw JsonRangeError if index is out of range. */
|
|
template<class T>
|
|
bool contains(int index) const noexcept(false);
|
|
|
|
/** @throw JsonRangeError if index is out of range. */
|
|
bool isNull(int index) const noexcept(false) { return contains<void>(index); }
|
|
|
|
/** @throw JsonRangeError if index is out of range. */
|
|
template<class T>
|
|
T at(int index) const noexcept(false);
|
|
|
|
/**
|
|
* Check whether all values of this JsonArray are of type T.
|
|
* If true, toVector()/toStdVector() will succeed.
|
|
*/
|
|
template<class T>
|
|
bool isVector() const;
|
|
|
|
/**
|
|
* Convert this JsonArray into a vector with values of type T.
|
|
* @throw JsonTypeError if some value is not of type T.
|
|
*/
|
|
template<class T>
|
|
QVector<T> toVector() const noexcept(false);
|
|
|
|
template<class T>
|
|
std::vector<T> toStdVector() const;
|
|
|
|
bool operator==(const JsonArray &other) const { return m_json == other.m_json; }
|
|
bool operator!=(const JsonArray &other) const { return !(*this == other); }
|
|
|
|
const QJsonArray &operator()() const { return m_json; }
|
|
private:
|
|
QJsonArray m_json;
|
|
bool m_jsonIsSet = false;
|
|
};
|
|
|
|
JsonArray JsonArray::fromJson(const char *json, int len)
|
|
{
|
|
if (len < 0)
|
|
len = strlen(json);
|
|
QJsonParseError error;
|
|
QJsonDocument doc = QJsonDocument::fromJson(QByteArray::fromRawData(json, len), &error);
|
|
if (error.error != QJsonParseError::NoError)
|
|
return JsonArray();
|
|
|
|
if (!doc.isArray())
|
|
return JsonArray();
|
|
|
|
return JsonArray(doc.array());
|
|
}
|
|
|
|
JsonArray JsonArray::fromJsonSafe(const char *json, int len) noexcept(false)
|
|
{
|
|
if (len < 0)
|
|
len = strlen(json);
|
|
QJsonParseError error;
|
|
const auto doc = QJsonDocument::fromJson(QByteArray::fromRawData(json, len), &error);
|
|
if (error.error != QJsonParseError::NoError)
|
|
throw JsonParseError(error);
|
|
|
|
if (!doc.isArray())
|
|
throw JsonTypeError("JSON root is not an array");
|
|
|
|
return JsonArray(doc.array());
|
|
}
|
|
|
|
//==============================================================================
|
|
|
|
/**
|
|
* Primary template without implementation.
|
|
*/
|
|
template<class T>
|
|
struct JsonValue;
|
|
|
|
/**
|
|
* Limits used by JsonIntValue.
|
|
* Defaults to std::numeric_limits, except for int64_t and uint64_t; see below.
|
|
*/
|
|
template<class Int>
|
|
struct JsonLimits
|
|
{
|
|
static constexpr Int lowest() { return std::numeric_limits<Int>::lowest(); }
|
|
static constexpr Int max() { return std::numeric_limits<Int>::max(); }
|
|
};
|
|
|
|
/**
|
|
* Specialization for int64_t.
|
|
* As a JSON number is stored in a 64-bit double, maximum accuracy
|
|
* is limited by bit-width of mantissa (52 bit).
|
|
* @see RFC 7159, IEEE 754-2008
|
|
*/
|
|
template<>
|
|
struct JsonLimits<int64_t>
|
|
{
|
|
static constexpr int64_t lowest() { return -(static_cast<int64_t>(1) << 53) + 1; }
|
|
static constexpr int64_t max() { return (static_cast<int64_t>(1) << 53) - 1; }
|
|
};
|
|
|
|
/**
|
|
* Specialization for uint64_t.
|
|
*/
|
|
template<>
|
|
struct JsonLimits<uint64_t>
|
|
{
|
|
static constexpr uint64_t lowest() { return 0; }
|
|
static constexpr uint64_t max() { return JsonLimits<int64_t>::max(); }
|
|
};
|
|
|
|
/**
|
|
* Implementation for integer values.
|
|
*/
|
|
template<class Int/*, const char *typeName*/>
|
|
struct JsonIntValue
|
|
{
|
|
static bool matchesType(const QJsonValue &value)
|
|
{
|
|
if (!value.isDouble())
|
|
return false;
|
|
double val = value.toDouble();
|
|
|
|
if (val < JsonLimits<Int>::lowest())
|
|
return false;
|
|
if (val > JsonLimits<Int>::max())
|
|
return false;
|
|
|
|
double wholeInt = static_cast<Int>(val);
|
|
return val == wholeInt;
|
|
}
|
|
|
|
static Int value(const QJsonValue &value) noexcept(false)
|
|
{
|
|
if (!matchesType(value))
|
|
throw JsonTypeError("JSON value not of type Int");
|
|
return static_cast<Int>(value.toDouble());
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Specializations for Integers.
|
|
*/
|
|
///@{
|
|
template<>
|
|
struct JsonValue<int16_t> : JsonIntValue<int16_t/*, TYPE_NAME_INT16*/>
|
|
{};
|
|
|
|
template<>
|
|
struct JsonValue<uint16_t> : JsonIntValue<uint16_t/*, TYPE_NAME_UINT16*/>
|
|
{};
|
|
|
|
template<>
|
|
struct JsonValue<int32_t> : JsonIntValue<int32_t/*, TYPE_NAME_INT32*/>
|
|
{};
|
|
|
|
template<>
|
|
struct JsonValue<uint32_t> : JsonIntValue<uint32_t/*, TYPE_NAME_UINT32*/>
|
|
{};
|
|
|
|
template<>
|
|
struct JsonValue<int64_t> : JsonIntValue<int64_t/*, TYPE_NAME_INT64*/>
|
|
{};
|
|
|
|
template<>
|
|
struct JsonValue<uint64_t> : JsonIntValue<uint64_t/*, TYPE_NAME_UINT64*/>
|
|
{};
|
|
///@}
|
|
|
|
/**
|
|
* Specialization for double.
|
|
*/
|
|
template<>
|
|
struct JsonValue<double>
|
|
{
|
|
static bool matchesType(const QJsonValue &value) { return value.isDouble(); }
|
|
|
|
static double value(const QJsonValue &value) noexcept(false)
|
|
{
|
|
if (!matchesType(value))
|
|
throw JsonTypeError("JSON value not of type Double");
|
|
return value.toDouble();
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Specialization for bool.
|
|
*/
|
|
template<>
|
|
struct JsonValue<bool>
|
|
{
|
|
static bool matchesType(const QJsonValue &value) { return value.isBool(); }
|
|
|
|
static bool value(const QJsonValue &value) noexcept(false)
|
|
{
|
|
if (!matchesType(value))
|
|
throw JsonTypeError("JSON value not of type Bool");
|
|
return value.toBool();
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Specialization for QString.
|
|
*/
|
|
template<>
|
|
struct JsonValue<QString>
|
|
{
|
|
static bool matchesType(const QJsonValue &value) { return value.isString(); }
|
|
|
|
static QString value(const QJsonValue &value) noexcept(false)
|
|
{
|
|
if (!matchesType(value))
|
|
throw JsonTypeError("JSON value not of type String");
|
|
return value.toString();
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Specialization for std::string.
|
|
*/
|
|
template<>
|
|
struct JsonValue<std::string>
|
|
{
|
|
static bool matchesType(const QJsonValue &value) { return value.isString(); }
|
|
|
|
static std::string value(const QJsonValue &value)
|
|
{
|
|
return JsonValue<QString>::value(value).toStdString();
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Specialization for QJsonObject.
|
|
*/
|
|
template<>
|
|
struct JsonValue<QJsonObject>
|
|
{
|
|
static bool matchesType(const QJsonValue &value) { return value.isObject(); }
|
|
|
|
static QJsonObject value(const QJsonValue &value) noexcept(false)
|
|
{
|
|
if (!matchesType(value))
|
|
throw JsonTypeError("JSON value not of type Object");
|
|
return value.toObject();
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Specialization for JsonObject.
|
|
*/
|
|
template<>
|
|
struct JsonValue<JsonObject>
|
|
{
|
|
static bool matchesType(const QJsonValue &value) { return value.isObject(); }
|
|
static JsonObject value(const QJsonValue &value) { return JsonObject(JsonValue<QJsonObject>::value(value)); }
|
|
};
|
|
|
|
/**
|
|
* Specialization for Null.
|
|
*/
|
|
template<>
|
|
struct JsonValue<void>
|
|
{
|
|
static bool matchesType(const QJsonValue &value) { return value.isNull(); }
|
|
};
|
|
|
|
/**
|
|
* Specialization for QJsonArray.
|
|
*/
|
|
template<>
|
|
struct JsonValue<QJsonArray>
|
|
{
|
|
static bool matchesType(const QJsonValue &value) { return value.isArray(); }
|
|
|
|
static QJsonArray value(const QJsonValue &value) noexcept(false)
|
|
{
|
|
if (!matchesType(value))
|
|
throw JsonTypeError("JSON value not of type Array");
|
|
return value.toArray();
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Specialization for JsonArray.
|
|
*/
|
|
template<>
|
|
struct JsonValue<JsonArray>
|
|
{
|
|
static bool matchesType(const QJsonValue &value) { return value.isArray(); }
|
|
static JsonArray value(const QJsonValue &value) { return JsonArray(JsonValue<QJsonArray>::value(value)); }
|
|
};
|
|
|
|
/**
|
|
* Partial specialisation for QVector<T>.
|
|
*/
|
|
template<class T>
|
|
struct JsonValue<QVector<T>>
|
|
{
|
|
static bool matchesType(const QJsonValue &value)
|
|
{
|
|
if (!value.isArray())
|
|
return false;
|
|
|
|
const JsonArray array(value.toArray());
|
|
return array.isVector<T>();
|
|
}
|
|
|
|
static QVector<T> value(const QJsonValue &value)
|
|
{
|
|
const JsonArray array(JsonValue<QJsonArray>::value(value));
|
|
return array.toVector<T>();
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Partial specialisation for std::vector<T>.
|
|
*/
|
|
template<class T>
|
|
struct JsonValue<std::vector<T>>
|
|
{
|
|
static bool matchesType(const QJsonValue &value)
|
|
{
|
|
return JsonValue<QVector<T>>::matchesType(value);
|
|
}
|
|
|
|
static std::vector<T> value(const QJsonValue &value)
|
|
{
|
|
const JsonArray array(JsonValue<QJsonArray>::value(value));
|
|
return array.toStdVector<T>();
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Partial specialisation for QMap<QString, T>.
|
|
*/
|
|
template<class T>
|
|
struct JsonValue<QMap<QString, T>>
|
|
{
|
|
static bool matchesType(const QJsonValue &value)
|
|
{
|
|
if (!value.isObject())
|
|
return false;
|
|
|
|
const JsonObject obj(JsonValue<QJsonObject>::value(value));
|
|
return obj.isMap<T>();
|
|
}
|
|
|
|
static QMap<QString, T> value(const QJsonValue &value)
|
|
{
|
|
const JsonObject obj(JsonValue<QJsonObject>::value(value));
|
|
return obj.toMap<T>();
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Partial specialisation for std::map<std::string, T>.
|
|
*/
|
|
template<class T>
|
|
struct JsonValue<std::map<std::string, T>>
|
|
{
|
|
static bool matchesType(const QJsonValue &value)
|
|
{
|
|
return JsonValue<QMap<QString, T>>::matchesType(value);
|
|
}
|
|
|
|
static std::map<std::string, T> value(const QJsonValue &value)
|
|
{
|
|
const JsonObject obj(JsonValue<QJsonObject>::value(value));
|
|
return obj.toStdMap<T>();
|
|
}
|
|
};
|
|
|
|
//==============================================================================
|
|
|
|
template<class T>
|
|
bool JsonObject::contains(const Key &key) const
|
|
{
|
|
if (!m_json.contains(key))
|
|
return false;
|
|
return JsonValue<T>::matchesType(m_json.value(key));
|
|
}
|
|
|
|
template<class T>
|
|
T JsonObject::value(const Key &key) const noexcept(false)
|
|
{
|
|
if (!containsAny(key))
|
|
throw JsonKeyError("no element with key: " + static_cast<const QString &>(key).toStdString());
|
|
try
|
|
{
|
|
return JsonValue<T>::value(m_json.value(key));
|
|
}
|
|
catch(const JsonTypeError &typeError)
|
|
{
|
|
throw JsonTypeError(std::string(typeError.what()) + " - key: " + static_cast<const QString &>(key).toStdString());
|
|
}
|
|
}
|
|
|
|
template<class T>
|
|
T JsonObject::valueOr(const Key &key, const T &defaultValue) const
|
|
{
|
|
try
|
|
{
|
|
return value<T>(key);
|
|
}
|
|
// Only catch JsonKeyError, JsonTypeError shall be propagated.
|
|
catch (const JsonKeyError &)
|
|
{
|
|
return defaultValue;
|
|
}
|
|
}
|
|
|
|
template<class T>
|
|
bool JsonObject::isMap() const
|
|
{
|
|
const QStringList keys = m_json.keys();
|
|
for (const auto &key : keys)
|
|
if (!JsonValue<T>::matchesType(m_json.value(key)))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
template<class T>
|
|
QMap<QString, T> JsonObject::toMap() const
|
|
{
|
|
QMap<QString, T> result;
|
|
for (auto current = m_json.begin(); current != m_json.end(); ++current)
|
|
result.insert(current.key(), JsonValue<T>::value(current.value()));
|
|
return result;
|
|
}
|
|
|
|
template<class T>
|
|
std::map<std::string, T> JsonObject::toStdMap() const
|
|
{
|
|
std::map<std::string, T> result;
|
|
for (auto current = m_json.begin(); current != m_json.end(); ++current)
|
|
result.insert({current.key().toStdString(), JsonValue<T>::value(current.value())});
|
|
return result;
|
|
}
|
|
|
|
//==============================================================================
|
|
|
|
template<class T>
|
|
bool JsonArray::contains(int index) const noexcept(false)
|
|
{
|
|
if (index < 0 || index >= m_json.size())
|
|
throw JsonRangeError("index out of range: " + std::to_string(index));
|
|
return JsonValue<T>::matchesType(m_json.at(index));
|
|
}
|
|
|
|
template<class T>
|
|
T JsonArray::at(int index) const noexcept(false)
|
|
{
|
|
if (index < 0 || index >= m_json.size())
|
|
throw JsonRangeError("index out of range: " + std::to_string(index));
|
|
return JsonValue<T>::value(m_json.at(index));
|
|
}
|
|
|
|
template<class T>
|
|
bool JsonArray::isVector() const
|
|
{
|
|
for (const QJsonValue &value : m_json)
|
|
if (!JsonValue<T>::matchesType(value))
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
template<class T>
|
|
QVector<T> JsonArray::toVector() const
|
|
{
|
|
QVector<T> result;
|
|
result.reserve(m_json.size());
|
|
for (const QJsonValue &value : m_json)
|
|
result.push_back(JsonValue<T>::value(value));
|
|
return result;
|
|
}
|
|
|
|
template<class T>
|
|
std::vector<T> JsonArray::toStdVector() const
|
|
{
|
|
std::vector<T> result;
|
|
result.reserve(m_json.size());
|
|
for (const QJsonValue &value : m_json)
|
|
result.push_back(JsonValue<T>::value(value));
|
|
return result;
|
|
}
|
|
|
|
} // namespace LtsUtils
|