Newer
Older
Import / projects / Gameloft / core / Utils / Json.h
#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_