#ifndef _BNE_JSON_H_
#define _BNE_JSON_H_
#define CFG_JSON_NO_RESIZE
#include <array>
#include <vector>
#include <map>
#include <unordered_map>
#include <memory>
#include <type_traits>
#include <json/json.h>
#include <RKTypes.h>
#include <RKVector.h>
#include <RKList.h>
#include <RKString.h>
//#include "Fix16.h"
#include "Time/ServerTime.h"
#include <RKJson.h>
namespace deprecated
{
/// \brief Convert a JSON value to a concrete C++ value.
/// \details This behaves somewhat like dynamic_cast<> in that it will return the appropriate value or some reasonable default.
/// Unlike dynamic_cast<>, this default is not nullptr but rather some sensible value.
/// The reason for this secondary behaviour is for safety in the event that non-essential values come through with
/// incorrect types from CRM data.
/// This is provided as a convenience because often there are values you wish as default so that each object in
/// the JSON file needn't be fully specified (because many of them are created by hand).
/// It does represent something of a perversion of the '*_cast<>' idiom, and for that reason we may wish to avoid calling it a 'cast'.
///
/// \param value The value to convert.
/// \param defaultValue The default value.
/// \return The C++ equivalent.
template <typename T> T json_cast(bne::JsonValueConstRef value);
template <typename T> T json_cast(bne::JsonValueConstRef value, const T& defaultValue);
/// \brief Convertion of a JSON value to a CPP type.
/// \details This will assert if the type is anything other than a boolean and then attempt to convert the value sensibly;
/// \brief Most general template implementation; this is left deliberately uncompilable so that unsupported types are shown as
/// compile errors.
template <typename T>
struct json_caster
{
static T to_value(bne::JsonValueConstRef value, const T& valueOnError, bool* error = nullptr) {
// The general implementation is deliberately left blank; you cannot cast this type.
// return T::no_valid_json_cast_provided_for_type;
if (error == nullptr) {
RKASSERT(value.isObject(), "Bad json_cast; expected map, got '%s'", value.toStyledString().c_str());
}
if (value.isObject()) {
T ret;
ret.Read(value);
return ret;
}
if (error != nullptr) {
*error = true;
}
return valueOnError;
}
};
/// \brief Convert a value to a boolean.
/// \details A null become false, an empty string becomes false,
/// a non-empty object becomes true.
template <>
struct json_caster < bool >
{
static bool to_value(bne::JsonValueConstRef value, bool valueOnError, bool* error = nullptr) {
if (error == nullptr) {
RKASSERT(value.isNumeric(), "Bad json_cast; expected bool, got '%s'", value.toStyledString().c_str());
}
if (value.isNumeric()) {
return value.asBool();
}
if (error != nullptr) {
*error = true;
}
return valueOnError;
}
};
/// \brief Convert a value to a signed integer.
/// \details A null or any non-numeric value becomes a 0,
/// unsigned integersv and real values are converted where they will fit within the range of an integer.
template <>
struct json_caster < int >
{
static int to_value(bne::JsonValueConstRef value, int valueOnError, bool* error = nullptr) {
if (error == nullptr) {
RKASSERT(value.isNumeric(), "Bad json_cast; expected integer, got '%s'", value.toStyledString().c_str());
}
if (value.isNumeric()) {
return value.asInt();
}
if (error != nullptr) {
*error = true;
}
return valueOnError;
}
};
/// \brief Convert a value to an unsigned integer.
/// \details A null or any non-numeric value becomes a 0,
/// unsigned integersv and real values are converted where they will fit within the range of an unsigned integer.
template <>
struct json_caster < uint32 >
{
static uint32 to_value(bne::JsonValueConstRef value, uint32 valueOnError, bool* error = nullptr) {
if (error == nullptr) {
RKASSERT(value.isNumeric(), "Bad json_cast; expected unsigned integer, got '%s'", value.toStyledString().c_str());
RKASSERT(!(value.isInt() && value.asInt() < 0), "Bad json_cast; expected unsigned integer, got signed integer '%d'", value.asInt());
}
if (value.isNumeric()) {
return value.asUInt();
}
if (error != nullptr) {
*error = true;
}
return valueOnError;
}
};
/// \brief Convert a value to an unsigned integer.
/// \details A null or any non-numeric value becomes a 0,
/// unsigned integersv and real values are converted where they will fit within the range of an unsigned integer.
template <>
struct json_caster < uint8 >
{
static uint8 to_value(bne::JsonValueConstRef value, uint8 valueOnError, bool* error = nullptr) {
if (error == nullptr) {
RKASSERT(value.isNumeric(), "Bad json_cast; expected unsigned integer, got '%s'", value.toStyledString().c_str());
RKASSERT(value.asUInt() < 256, "Bad json_cast; value larger than 255 '%d'", value.asInt());
}
if (value.isNumeric()) {
return value.asUInt();
}
if (error != nullptr) {
*error = true;
}
return valueOnError;
}
};
/// \brief Convert a value to a time value.
/// \details A null or any non-numeric value becomes a 0, real values are converted where they will fit within the range of an unsigned integer.
/// \todo Serialising timestamps as uint32 will potentially break in 2037 or so. Should consider using either a double or a string to serialise timestamps.
template <>
struct json_caster < time_t >
{
static time_t to_value(bne::JsonValueConstRef value, const time_t& valueOnError, bool* error = nullptr) {
if (error == nullptr) {
RKASSERT(value.isNumeric(), "Bad json_cast; expected time_t, got '%s'", value.toStyledString().c_str());
}
if (value.isNumeric()) {
return value.asUInt();
}
if (error != nullptr) {
*error = true;
}
return valueOnError;
}
};
/// \brief Convert a value to a float value.
/// \details A null or any non-numeric value becomes a 0.
/// \todo If the double is out of range then the resulting float will be truncated.
template <>
struct json_caster < float >
{
static float to_value(bne::JsonValueConstRef value, float valueOnError, bool* error = nullptr) {
if (error == nullptr) {
RKASSERT(value.isNumeric(), "Bad json_cast; expected float, got '%s'", value.toStyledString().c_str());
RKASSERT(value.asDouble() <= std::numeric_limits<float>::max(),
"Bad json_cast; real value is out of range for a float, value may not be larger than '%f'", std::numeric_limits<float>::max());
}
if (value.isNumeric() && value.asDouble() <= std::numeric_limits<float>::max()) {
return static_cast<float>(value.asDouble());
}
if (error != nullptr) {
*error = true;
}
return valueOnError;
}
};
/// \brief Convert a value to a string.
/// \details An empty string if the object cannot be converted, 'true' or 'false' if the value is a boolean.
template <>
struct json_caster < const char* >
{
static const char* to_value(bne::JsonValueConstRef value, const char* valueOnError, bool* error = nullptr) {
if (error == nullptr) {
RKASSERT(value.isString(), "Bad json_cast; expected string, got '%s'", value.toStyledString().c_str());
}
const char* string = value.asCString();
if (string != nullptr) {
return string;
}
if (error != nullptr) {
*error = true;
}
return valueOnError;
}
};
template<>
struct json_caster < RKString >
{
static RKString to_value(bne::JsonValueConstRef value, const RKString& valueOnError, bool* error = nullptr) {
if (error == nullptr) {
RKASSERT(value.isString(), "Bad json_cast; expected string, got '%s'", value.toStyledString().c_str());
}
const char* string = value.asCString();
if (string != nullptr) {
return RKString(string);
}
if (error != nullptr) {
*error = true;
}
return valueOnError;
}
};
template<>
struct json_caster < std::string >
{
static std::string to_value(bne::JsonValueConstRef value, const std::string& valueOnError, bool* error = nullptr) {
if (error == nullptr) {
RKASSERT(value.isString(), "Bad json_cast; expected string, got '%s'", value.toStyledString().c_str());
}
const char* string = value.asCString();
if (string != nullptr) {
return std::string(string);
}
if (error != nullptr) {
*error = true;
}
return valueOnError;
}
};
/// \brief Convert a value to a RKVector2.
/// \details This assumes an array of numeric values of size 2. Any other object will assert and then return the zero vector.
template <>
struct json_caster < RKVector2 >
{
static RKVector2 to_value(bne::JsonValueConstRef value, const RKVector2& valueOnError, bool* error = nullptr) {
if (error == nullptr) {
RKASSERT(value.isArray(), "Bad json_cast; expected array, got '%s'", value.toStyledString().c_str());
}
if (value.isArray()) {
float x = (value.size() >= 1) ? json_caster<float>::to_value(value[0u], 0, error) : 0;
float y = (value.size() >= 2) ? json_caster<float>::to_value(value[1], 0, error) : 0;
if (error == nullptr || *error == false) {
return RKVector2(x, y);
}
}
if (error != nullptr) {
*error = true;
}
return valueOnError;
}
};
/// \brief Convert a value to a RKVec2i.
/// \details This assumes an array of numeric values of size 2. Any other object will assert and then return the zero vector.
template <>
struct json_caster < RKVec2i >
{
static RKVec2i to_value(bne::JsonValueConstRef value, const RKVec2i& valueOnError, bool* error = nullptr) {
if (error == nullptr) {
RKASSERT(value.isArray(), "Bad json_cast; expected array, got '%s'", value.toStyledString().c_str());
}
if (value.isArray()) {
int x = (value.size() >= 1) ? json_caster<int>::to_value(value[0u], 0, error) : 0;
int y = (value.size() >= 2) ? json_caster<int>::to_value(value[1], 0, error) : 0;
if (error == nullptr || *error == false) {
return RKVec2i(x, y);
}
}
if (error != nullptr) {
*error = true;
}
return valueOnError;
}
};
/// \brief Convert a value to a RKVector.
/// \details This assumes an array of numeric values of size 4. Any other object assert and then return the zero vector.
template <>
struct json_caster < RKVector >
{
static RKVector to_value(bne::JsonValueConstRef value, const RKVector& valueOnError, bool* error = nullptr) {
if (error == nullptr) {
RKASSERT(value.isArray(), "Bad json_cast; expected array, got '%s'", value.toStyledString().c_str());
}
if (value.isArray()) {
float x = (value.size() >= 1) ? json_caster<float>::to_value(value[0u], 0, error) : 0;
float y = (value.size() >= 2) ? json_caster<float>::to_value(value[1], 0, error) : 0;
float z = (value.size() >= 3) ? json_caster<float>::to_value(value[2], 0, error) : 0;
float w = (value.size() == 4) ? json_caster<float>::to_value(value[3], 1, error) : 1;
if (error == nullptr || *error == false) {
return RKVector(x, y, z, w);
}
}
if (error != nullptr) {
*error = true;
}
return valueOnError;
}
};
/// \brief Convert a JSON value to a concrete C++ value.
/// \details This behaves somewhat like dynamic_cast<> in that it will return the appropriate value or some reasonable default.
/// Unlike dynamic_cast<>, this default is not nullptr but rather some sensible value.
/// The reason for this secondary behaviour is for safety in the event that non-essential values come through with
/// incorrect types from CRM data.
/// This is provided as a convenience because often there are values you wish as default so that each object in
/// the JSON file needn't be fully specified (because many of them are created by hand).
/// It does represent something of a perversion of the '*_cast<>' idiom, and for that reason we may wish to avoid calling it a 'cast'.
///
/// \param value The value to convert.
/// \param defaultValue The default value.
/// \return The C++ equivalent.
template <typename T>
T json_cast(bne::JsonValueConstRef value, const T& defaultValue, bool* error) {
if (value.isNull()) {
return defaultValue;
}
else {
return json_caster<T>::to_value(value, defaultValue, error);
}
}
template <typename T>
T json_cast(bne::JsonValueConstRef value, const T& defaultValue) {
return json_cast(value, defaultValue, nullptr);
}
template <typename T>
T json_cast(bne::JsonValueConstRef value, bool* error) {
return json_cast(value, T(), error);
}
template <typename T>
T json_cast(bne::JsonValueConstRef value) {
return json_cast(value, T(), nullptr);
}
/// \brief Convert a value to a dynamically allocated array.
/// \details This asserts and returns an empty array if the json value is not an array.
/// For each value in the array a json_cast for that specific value is invoked which may raise an assert (but then return a sensible default)
/// if any type within the array is incorrect.
/// \todo Because this returns a copy it's not really the best way to implement a conversion from json to a list.
/// Consider passing a reference to an existing RKList<> that is first cleared before being filled.
template <typename T>
struct json_caster < RKList<T> >
{
static RKList<T> to_value(bne::JsonValueConstRef value, const RKList<T>& valueOnError, bool* error = nullptr) {
if (error == nullptr) {
RKASSERT(value.isArray(), "Bad json_cast: expected array, got '%s'", value.toStyledString().c_str());
}
if (value.isArray()) {
RKList<T> array; array.Reserve(value.size());
for (uint32 i = 0; i < value.size(); ++i) {
array.Append(json_cast<T>(value[i], T(), error));
}
if (error == nullptr || *error == false) {
return array;
}
}
if (error != nullptr) {
*error = true;
}
return valueOnError;
}
};
template <typename T>
struct json_caster < std::vector<T> >
{
static std::vector<T> to_value(bne::JsonValueConstRef value, const std::vector<T>& valueOnError, bool* error = nullptr) {
if (error == nullptr) {
RKASSERT(value.isArray(), "Bad json_cast: expected array, got '%s'", value.toStyledString().c_str());
}
if (value.isArray()) {
std::vector<T> array; array.reserve(value.size());
for (uint32 i = 0; i < value.size(); ++i) {
array.push_back(json_cast<T>(value[i], T(), error));
}
if (error == nullptr || *error == false) {
return array;
}
}
if (error != nullptr) {
*error = true;
}
return valueOnError;
}
};
/// \brief Convert a value to a statically allocated array.
/// \details This asserts and returns an default assigned array if the json value is not an array, or is an array of an inappropriate size.
/// For each value in the array a json_cast for that specific value is invoked which may raise an assert (but then return a sensible default)
/// if any type within the array is incorrect.
template <typename T, uint32 SIZE>
struct json_caster < RKArray<T, SIZE> >
{
static RKArray<T, SIZE> to_value(bne::JsonValueConstRef value, const RKArray<T, SIZE>& valueOnError, bool* error = nullptr) {
if (error == nullptr) {
RKASSERT(value.isArray(), "Bad json_cast; expected array of size %d, got '%s'", SIZE, value.toStyledString().c_str());
RKASSERT(value.size() >= SIZE, "Bad json_cast; expected array of size %d, got array of size %d", SIZE, value.size());
}
if (value.isArray() && value.size() >= SIZE) {
RKArray<T, SIZE> array;
for (uint32 i = 0; i < SIZE; ++i) {
array[i] = json_cast<T>(value[i], error);
}
if (error == nullptr || *error == false) {
return array;
}
}
if (error != nullptr) {
*error = true;
}
return valueOnError;
}
};
/// \brief Convert a value to a Fix16.
/// \details A null or any non-numeric value becomes a 0,
/// unsigned integersv and real values are converted where they will fit within the range of an unsigned integer.
//template <>
//struct json_caster < Fix16 >
//{
// static Fix16 to_value(bne::JsonValueConstRef value, Fix16 valueOnError, bool* error = nullptr) {
// if (error == nullptr) {
// RKASSERT(value.isUInt() || value.isInt(), "Bad json_cast; expected integer, got '%s'", value.toStyledString().c_str());
// }
// if (value.isUInt() || value.isInt()) {
// Fix16 retVal;
// retVal.SetRawValue(value.asInt());
// return retVal;
// }
// if (error != nullptr) {
// *error = true;
// }
// return valueOnError;
// }
//};
/// \brief Convert a value to a vec2x_t.
/// \details A null or any non-numeric value becomes a 0,
/// unsigned integersv and real values are converted where they will fit within the range of an unsigned integer.
//template <>
//struct json_caster < vec2x_t >
//{
// static vec2x_t to_value(bne::JsonValueConstRef value, vec2x_t valueOnError, bool* error = nullptr) {
// if (error == nullptr) {
// RKASSERT(value.isArray(), "Bad json_cast: expected array, got '%s'", value.toStyledString().c_str());
// RKASSERT(value.size() == 2, "Bad json_cast: expected 2 elements in array, actual size '%d'", value.size());
// }
// if (value.isArray()) {
// vec2x_t vec;
// vec.m_x = json_cast<Fix16>(value[(uint32_t) 0], error);
// vec.m_y = json_cast<Fix16>(value[(uint32_t) 1], error);
// return vec;
// }
// if (error != nullptr) {
// *error = true;
// }
// return valueOnError;
// }
//};
template <typename T, size_t SIZE>
struct json_caster < std::array<T, SIZE> >
{
static std::array<T, SIZE> to_value(bne::JsonValueConstRef value, const std::array<T, SIZE>& valueOnError, bool* error = nullptr) {
if (error == nullptr) {
RKASSERT(value.isArray(), "Bad json_cast; expected array of size %d, got '%s'", SIZE, value.toStyledString().c_str());
RKASSERT(value.size() >= SIZE, "Bad json_cast; expected array of size %d, got array of size %d", SIZE, value.size());
}
if (value.isArray() && value.size() >= SIZE) {
std::array<T, SIZE> array;
for (uint32 i = 0; i < SIZE; ++i) {
array[i] = json_cast<T>(value[i], error);
}
if (error == nullptr || *error == false) {
return array;
}
}
if (error != nullptr) {
*error = true;
}
return valueOnError;
}
};
/// \brief Convert a value to a map.
/// \details This asserts and returns an default assigned map if the json value is not a map.
template <typename K, typename T>
struct json_caster < std::map<K, T> >
{
static std::map<K, T> to_value(bne::JsonValueConstRef value, const std::map<K, T>& valueOnError, bool* error = nullptr) {
if (error == nullptr) {
RKASSERT(value.isObject(), "Bad json_cast; expected map, got '%s'", value.toStyledString().c_str());
}
if (value.isObject()) {
std::map<K, T> amap;
for (const auto& it : value.getMemberNames()) { // NOLINT(c++11/auto)
amap[it] = json_cast<T>(value[it], error);
}
if (error == nullptr || *error == false) {
return amap;
}
}
if (error != nullptr) {
*error = true;
}
return valueOnError;
}
};
/// \brief Convert a value to an unsigned integer.
/// \details A null or any non-numeric value becomes a 0,
/// unsigned integersv and real values are converted where they will fit within the range of an unsigned integer.
template <>
struct json_caster < Timestamp >
{
static Timestamp to_value(bne::JsonValueConstRef value, Timestamp valueOnError, bool* error = nullptr) {
if (error == nullptr) {
RKASSERT(value.isNumeric(), "Bad json_cast; expected unsigned integer, got '%s'", value.toStyledString().c_str());
RKASSERT(!(value.isInt() && value.asInt() < 0), "Bad json_cast; expected unsigned integer, got signed integer '%d'", value.asInt());
}
if (value.isNumeric()) {
return Timestamp(value.asUInt());
}
if (error != nullptr) {
*error = true;
}
return valueOnError;
}
};
/// \brief Convert a value to a duration.
/// \details A null or any non-numeric value becomes a 0,
/// unsigned integersv and real values are converted where they will fit within the range of an unsigned integer.
template <>
struct json_caster < bne::Duration >
{
static bne::Duration to_value(bne::JsonValueConstRef value, bne::Duration valueOnError, bool* error = nullptr) {
if (error == nullptr) {
RKASSERT(value.isArray(), "Bad json_cast: expected array, got '%s'", value.toStyledString().c_str());
RKASSERT(value.size() == 2, "Bad json_cast: expected 2 elements in array, actual size '%d'", value.size());
}
if (value.isArray()) {
bne::Duration dur;
dur.SetStartTime(json_cast<Timestamp>(value[(uint32_t)0], error));
dur.SetEndTime(json_cast<Timestamp>(value[(uint32_t)1], error));
return dur;
}
if (error != nullptr) {
*error = true;
}
return valueOnError;
}
};
} // namespace bne
inline std::ostream& operator<<(std::ostream& out, bne::JsonValueConstRef value)
{
out << value.toStyledString();
return out;
}
/// \brief Output basic types
inline bne::JsonValueRef operator<<(bne::JsonValueRef out, bool value) {
out.setBool(value);
return out;
}
inline bne::JsonValueRef operator<<(bne::JsonValueRef out, int value) {
out.setInt(value);
return out;
}
inline bne::JsonValueRef operator<<(bne::JsonValueRef out, uint32 value) {
out.setUInt(value);
return out;
}
inline bne::JsonValueRef operator<<(bne::JsonValueRef out, uint8 value) {
out.setUInt(value);
return out;
}
inline bne::JsonValueRef operator<<(bne::JsonValueRef out, time_t value) {
out.setUInt(static_cast<uint32>(value)); // FIXME: casting 64b timestamp to 32b!
return out;
}
inline bne::JsonValueRef operator<<(bne::JsonValueRef out, float value) {
out.setDouble(value);
return out;
}
inline bne::JsonValueRef operator<<(bne::JsonValueRef out, const char* value) {
out.setString(value);
return out;
}
inline bne::JsonValueRef operator<<(bne::JsonValueRef out, const std::string& value) {
out.setString(value.c_str());
return out;
}
inline bne::JsonValueRef operator<<(bne::JsonValueRef out, const RKString& value) {
out.setString(value.GetString());
return out;
}
inline bne::JsonValueRef operator<<(bne::JsonValueRef out, const RKVector2& value) {
#ifdef CFG_JSON_NO_RESIZE
out.resize(0);
out.append(value.x);
out.append(value.y);
#else
out.resize(2);
out[(uint32_t) 0] = value.x;
out[(uint32_t) 1] = value.y;
#endif
return out;
}
inline bne::JsonValueRef operator<<(bne::JsonValueRef out, const RKVector& value) {
#ifdef CFG_JSON_NO_RESIZE
out.resize(0);
out.append(value.x);
out.append(value.y);
out.append(value.z);
out.append(value.w);
#else
out.resize(4);
out[(uint32_t) 0] = value.x;
out[(uint32_t) 1] = value.y;
out[(uint32_t) 2] = value.z;
out[(uint32_t) 3] = value.w;
#endif
return out;
}
//inline bne::JsonValueRef operator<<(bne::JsonValueRef out, const vec2x_t& value) {
//#ifdef CFG_JSON_NO_RESIZE
// out.resize(0);
// out.append(value.m_x.GetRawValue());
// out.append(value.m_y.GetRawValue());
//#else
// out.resize(2);
// out[(uint32_t)0] = value.m_x.GetRawValue();
// out[(uint32_t)1] = value.m_y.GetRawValue();
//#endif
// return out;
//}
//inline bne::JsonValueRef operator<<(bne::JsonValueRef out, const fix16_t& value) {
// out.setInt(value.GetRawValue());
// return out;
//}
inline bne::JsonValueRef operator<<(bne::JsonValueRef out, const Timestamp& value) {
out.setInt(value);
return out;
}
inline bne::JsonValueRef operator<<(bne::JsonValueRef out, const bne::Duration& value) {
out.append(value.GetStartTime());
out.append(value.GetEndTime());
return out;
}
template <typename T>
inline bne::JsonValueRef operator<<(bne::JsonValueRef out, const T& value) {
value.Write(out);
return out;
}
/// \brief Output a dynamic array to a json value.
template <typename T>
bne::JsonValueRef operator<<(bne::JsonValueRef out, const std::vector<T>& value) {
#ifdef CFG_JSON_NO_RESIZE
out.resize(0);
for (size_t i = 0; i < value.size(); ++i)
{
out.appendEmpty() << value[i];
}
#else
out.resize(value.size());
for (size_t i = 0; i < value.size(); ++i) {
bne::JsonValue val;
val << value[i];
out[i] = val;
}
#endif
return out;
}
template <typename T>
bne::JsonValueRef operator<<(bne::JsonValueRef out, const RKList<T>& value) {
#ifdef CFG_JSON_NO_RESIZE
out.resize(0);
for (size_t i = 0; i < value.Size(); ++i)
{
out.appendEmpty() << value[i];
}
#else
out.resize(value.Size());
for (size_t i = 0; i < value.Size(); ++i) {
bne::JsonValue val;
val << value[i];
out[i] = val;
}
#endif
return out;
}
/// \brief Output a static array to a json value.
template <typename T, size_t SIZE>
bne::JsonValueRef operator<<(bne::JsonValueRef out, const std::array<T, SIZE>& value) {
#ifdef CFG_JSON_NO_RESIZE
out.resize(0);
for (size_t i = 0; i < SIZE; ++i) {
bne::JsonValue val;
val << value[i];
out.append(val);
}
#else
out.resize(SIZE);
for (size_t i = 0; i < SIZE; ++i) {
bne::JsonValue val;
val << value[i];
out[i] = val;
}
#endif
return out;
}
template <typename T, uint32 SIZE>
bne::JsonValueRef operator<<(bne::JsonValueRef out, const RKArray<T, SIZE>& value) {
#ifdef CFG_JSON_NO_RESIZE
out.resize(0);
for (size_t i = 0; i < SIZE; ++i)
{
out.appendEmpty() << value[i];
}
#else
out.resize(SIZE);
for (size_t i = 0; i < SIZE; ++i) {
bne::JsonValue val;
val << value[i];
out[i] = val;
}
#endif
return out;
}
/// \brief Output a map to a json value.
template <typename K, typename T>
bne::JsonValueRef operator<<(bne::JsonValueRef out, const std::map<K, T>& value) {
for (const auto& it : value) { // NOLINT(c++11/auto)
out[it.first] = it.second;
}
return out;
}
#endif // _BNE_JSON_H_