foundationdb/fdbclient/json_spirit/json_spirit_value.h

513 lines
13 KiB
C++

#ifndef JSON_SPIRIT_VALUE
#define JSON_SPIRIT_VALUE
// Copyright John W. Wilkinson 2007 - 2014
// Distributed under the MIT License, see accompanying file LICENSE-OSS
// json spirit version 4.08
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
#pragma once
#endif
#include <vector>
#include <map>
#include <string>
#include <cassert>
#include <sstream>
#include <stdexcept>
#include <boost/config.hpp>
#include <boost/cstdint.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/variant.hpp>
// comment out the value types you don't need to reduce build times and intermediate file sizes
#define JSON_SPIRIT_VALUE_ENABLED
#define JSON_SPIRIT_WVALUE_ENABLED
#define JSON_SPIRIT_MVALUE_ENABLED
#define JSON_SPIRIT_WMVALUE_ENABLED
namespace json_spirit {
enum Value_type { obj_type, array_type, str_type, bool_type, int_type, real_type, null_type };
static std::string value_type_to_string(Value_type vtype);
struct Null {};
template <class Config> // Config determines whether the value uses std::string or std::wstring and
// whether JSON Objects are represented as vectors or maps
class Value_impl {
public:
typedef Config Config_type;
typedef typename Config::String_type String_type;
typedef typename Config::Object_type Object;
typedef typename Config::Array_type Array;
typedef typename String_type::const_pointer Const_str_ptr; // eg const char*
Value_impl(); // creates null value
Value_impl(Const_str_ptr value);
Value_impl(const String_type& value);
Value_impl(const Object& value);
Value_impl(const Array& value);
Value_impl(bool value);
Value_impl(int value);
Value_impl(int64_t value);
Value_impl(uint64_t value);
Value_impl(double value);
template <class Iter>
Value_impl(Iter first, Iter last); // constructor from containers, e.g. std::vector or std::list
template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
Value_impl(const boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>& variant); // constructor for compatible variant types
Value_impl(const Value_impl& other);
bool operator==(const Value_impl& lhs) const;
Value_impl& operator=(const Value_impl& lhs);
Value_type type() const;
bool is_uint64() const;
bool is_null() const;
const String_type& get_str() const;
const Object& get_obj() const;
const Array& get_array() const;
bool get_bool() const;
int get_int() const;
int64_t get_int64() const;
uint64_t get_uint64() const;
double get_real() const;
Object& get_obj();
Array& get_array();
template <typename T>
T get_value() const; // example usage: int i = value.get_value< int >();
// or double d = value.get_value< double >();
static const Value_impl null;
private:
void check_type(const Value_type vtype) const;
typedef boost::variant<boost::recursive_wrapper<Object>,
boost::recursive_wrapper<Array>,
String_type,
bool,
int64_t,
double,
Null,
uint64_t>
Variant;
Variant v_;
class Variant_converter_visitor : public boost::static_visitor<Variant> {
public:
template <typename T, typename A, template <typename, typename> class Cont>
Variant operator()(const Cont<T, A>& cont) const {
return Array(cont.begin(), cont.end());
}
Variant operator()(int i) const { return static_cast<int64_t>(i); }
template <class T>
Variant operator()(const T& t) const {
return t;
}
};
};
// vector objects
template <class Config>
struct Pair_impl {
typedef typename Config::String_type String_type;
typedef typename Config::Value_type Value_type;
Pair_impl() {}
Pair_impl(const String_type& name, const Value_type& value);
bool operator==(const Pair_impl& lhs) const;
String_type name_;
Value_type value_;
};
#if defined(JSON_SPIRIT_VALUE_ENABLED) || defined(JSON_SPIRIT_WVALUE_ENABLED)
template <class String>
struct Config_vector {
typedef String String_type;
typedef Value_impl<Config_vector> Value_type;
typedef Pair_impl<Config_vector> Pair_type;
typedef std::vector<Value_type> Array_type;
typedef std::vector<Pair_type> Object_type;
static Value_type& add(Object_type& obj, const String_type& name, const Value_type& value) {
obj.push_back(Pair_type(name, value));
return obj.back().value_;
}
static const String_type& get_name(const Pair_type& pair) { return pair.name_; }
static const Value_type& get_value(const Pair_type& pair) { return pair.value_; }
};
#endif
// typedefs for ASCII
#ifdef JSON_SPIRIT_VALUE_ENABLED
typedef Config_vector<std::string> Config;
typedef Config::Value_type Value;
typedef Config::Pair_type Pair;
typedef Config::Object_type Object;
typedef Config::Array_type Array;
#endif
// typedefs for Unicode
#if defined(JSON_SPIRIT_WVALUE_ENABLED) && !defined(BOOST_NO_STD_WSTRING)
typedef Config_vector<std::wstring> wConfig;
typedef wConfig::Value_type wValue;
typedef wConfig::Pair_type wPair;
typedef wConfig::Object_type wObject;
typedef wConfig::Array_type wArray;
#endif
// map objects
#if defined(JSON_SPIRIT_MVALUE_ENABLED) || defined(JSON_SPIRIT_WMVALUE_ENABLED)
template <class String>
struct Config_map {
typedef String String_type;
typedef Value_impl<Config_map> Value_type;
typedef std::vector<Value_type> Array_type;
typedef std::map<String_type, Value_type> Object_type;
typedef std::pair<const String_type, Value_type> Pair_type;
static Value_type& add(Object_type& obj, const String_type& name, const Value_type& value) {
return obj[name] = value;
}
static const String_type& get_name(const Pair_type& pair) { return pair.first; }
static const Value_type& get_value(const Pair_type& pair) { return pair.second; }
};
#endif
// typedefs for ASCII
#ifdef JSON_SPIRIT_MVALUE_ENABLED
typedef Config_map<std::string> mConfig;
typedef mConfig::Value_type mValue;
typedef mConfig::Object_type mObject;
typedef mConfig::Array_type mArray;
#endif
// typedefs for Unicode
#if defined(JSON_SPIRIT_WMVALUE_ENABLED) && !defined(BOOST_NO_STD_WSTRING)
typedef Config_map<std::wstring> wmConfig;
typedef wmConfig::Value_type wmValue;
typedef wmConfig::Object_type wmObject;
typedef wmConfig::Array_type wmArray;
#endif
///////////////////////////////////////////////////////////////////////////////////////////////
//
// implementation
inline bool operator==(const Null&, const Null&) {
return true;
}
template <class Config>
const Value_impl<Config> Value_impl<Config>::null;
template <class Config>
Value_impl<Config>::Value_impl() : v_(Null()) {}
template <class Config>
Value_impl<Config>::Value_impl(const Const_str_ptr value) : v_(String_type(value)) {}
template <class Config>
Value_impl<Config>::Value_impl(const String_type& value) : v_(value) {}
template <class Config>
Value_impl<Config>::Value_impl(const Object& value) : v_(value) {}
template <class Config>
Value_impl<Config>::Value_impl(const Array& value) : v_(value) {}
template <class Config>
Value_impl<Config>::Value_impl(bool value) : v_(value) {}
template <class Config>
Value_impl<Config>::Value_impl(int value) : v_(static_cast<int64_t>(value)) {}
template <class Config>
Value_impl<Config>::Value_impl(int64_t value) : v_(value) {}
template <class Config>
Value_impl<Config>::Value_impl(uint64_t value) : v_(value) {}
template <class Config>
Value_impl<Config>::Value_impl(double value) : v_(value) {}
template <class Config>
Value_impl<Config>::Value_impl(const Value_impl<Config>& other) : v_(other.v_) {}
template <class Config>
template <class Iter>
Value_impl<Config>::Value_impl(Iter first, Iter last) : v_(Array(first, last)) {}
template <class Config>
template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
Value_impl<Config>::Value_impl(const boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>& variant)
: v_(boost::apply_visitor(Variant_converter_visitor(), variant)) {}
template <class Config>
Value_impl<Config>& Value_impl<Config>::operator=(const Value_impl& lhs) {
Value_impl tmp(lhs);
std::swap(v_, tmp.v_);
return *this;
}
template <class Config>
bool Value_impl<Config>::operator==(const Value_impl& lhs) const {
if (this == &lhs)
return true;
if (type() != lhs.type())
return false;
return v_ == lhs.v_;
}
template <class Config>
Value_type Value_impl<Config>::type() const {
if (is_uint64()) {
return int_type;
}
return static_cast<Value_type>(v_.which());
}
template <class Config>
bool Value_impl<Config>::is_uint64() const {
return v_.which() == null_type + 1;
}
template <class Config>
bool Value_impl<Config>::is_null() const {
return type() == null_type;
}
template <class Config>
void Value_impl<Config>::check_type(const Value_type vtype) const {
if (type() != vtype) {
std::ostringstream os;
os << "get_value< " << value_type_to_string(vtype) << " > called on " << value_type_to_string(type())
<< " Value";
throw std::runtime_error(os.str());
}
}
template <class Config>
const typename Config::String_type& Value_impl<Config>::get_str() const {
check_type(str_type);
return *boost::get<String_type>(&v_);
}
template <class Config>
const typename Value_impl<Config>::Object& Value_impl<Config>::get_obj() const {
check_type(obj_type);
return *boost::get<Object>(&v_);
}
template <class Config>
const typename Value_impl<Config>::Array& Value_impl<Config>::get_array() const {
check_type(array_type);
return *boost::get<Array>(&v_);
}
template <class Config>
bool Value_impl<Config>::get_bool() const {
check_type(bool_type);
return boost::get<bool>(v_);
}
template <class Config>
int Value_impl<Config>::get_int() const {
check_type(int_type);
return static_cast<int>(get_int64());
}
template <class Config>
int64_t Value_impl<Config>::get_int64() const {
check_type(int_type);
if (is_uint64()) {
return static_cast<int64_t>(get_uint64());
}
return boost::get<int64_t>(v_);
}
template <class Config>
uint64_t Value_impl<Config>::get_uint64() const {
check_type(int_type);
if (!is_uint64()) {
return static_cast<uint64_t>(get_int64());
}
return boost::get<uint64_t>(v_);
}
template <class Config>
double Value_impl<Config>::get_real() const {
if (type() == int_type) {
return is_uint64() ? static_cast<double>(get_uint64()) : static_cast<double>(get_int64());
}
check_type(real_type);
return boost::get<double>(v_);
}
template <class Config>
typename Value_impl<Config>::Object& Value_impl<Config>::get_obj() {
check_type(obj_type);
return *boost::get<Object>(&v_);
}
template <class Config>
typename Value_impl<Config>::Array& Value_impl<Config>::get_array() {
check_type(array_type);
return *boost::get<Array>(&v_);
}
template <class Config>
Pair_impl<Config>::Pair_impl(const String_type& name, const Value_type& value) : name_(name), value_(value) {}
template <class Config>
bool Pair_impl<Config>::operator==(const Pair_impl<Config>& lhs) const {
if (this == &lhs)
return true;
return (name_ == lhs.name_) && (value_ == lhs.value_);
}
// converts a C string, ie. 8 bit char array, to a string object
//
template <class String_type>
String_type to_str(const char* c_str) {
String_type result;
for (const char* p = c_str; *p != 0; ++p) {
result += *p;
}
return result;
}
//
namespace internal_ {
template <typename T>
struct Type_to_type {};
template <class Value>
int get_value(const Value& value, Type_to_type<int>) {
return value.get_int();
}
template <class Value>
int64_t get_value(const Value& value, Type_to_type<int64_t>) {
return value.get_int64();
}
template <class Value>
uint64_t get_value(const Value& value, Type_to_type<uint64_t>) {
return value.get_uint64();
}
template <class Value>
double get_value(const Value& value, Type_to_type<double>) {
return value.get_real();
}
template <class Value>
typename Value::String_type get_value(const Value& value, Type_to_type<typename Value::String_type>) {
return value.get_str();
}
template <class Value>
typename Value::Array get_value(const Value& value, Type_to_type<typename Value::Array>) {
return value.get_array();
}
template <class Value>
typename Value::Object get_value(const Value& value, Type_to_type<typename Value::Object>) {
return value.get_obj();
}
template <class Value>
bool get_value(const Value& value, Type_to_type<bool>) {
return value.get_bool();
}
} // namespace internal_
template <class Config>
template <typename T>
T Value_impl<Config>::get_value() const {
return internal_::get_value(*this, internal_::Type_to_type<T>());
}
static std::string value_type_to_string(const Value_type vtype) {
switch (vtype) {
case obj_type:
return "Object";
case array_type:
return "Array";
case str_type:
return "string";
case bool_type:
return "boolean";
case int_type:
return "integer";
case real_type:
return "real";
case null_type:
return "null";
}
assert(false);
return "unknown type";
}
} // namespace json_spirit
#endif