Commit 4029ddb1 authored by Milo Yip's avatar Milo Yip

Merge pull request #542 from miloyip/issue316_templatedaccessors

Templated accessors and range-based for
parents cdc2330c 9f6736c2
......@@ -393,6 +393,127 @@ template <typename T> struct IsGenericValue : IsGenericValueImpl<T>::Type {};
} // namespace internal
///////////////////////////////////////////////////////////////////////////////
// TypeHelper
namespace internal {
template <typename ValueType, typename T>
struct TypeHelper {};
template<typename ValueType>
struct TypeHelper<ValueType, bool> {
static bool Is(const ValueType& v) { return v.IsBool(); }
static bool Get(const ValueType& v) { return v.GetBool(); }
static ValueType& Set(ValueType& v, bool data) { return v.SetBool(data); }
static ValueType& Set(ValueType& v, bool data, typename ValueType::AllocatorType&) { return v.SetBool(data); }
};
template<typename ValueType>
struct TypeHelper<ValueType, int> {
static bool Is(const ValueType& v) { return v.IsInt(); }
static int Get(const ValueType& v) { return v.GetInt(); }
static ValueType& Set(ValueType& v, int data) { return v.SetInt(data); }
static ValueType& Set(ValueType& v, int data, typename ValueType::AllocatorType&) { return v.SetInt(data); }
};
template<typename ValueType>
struct TypeHelper<ValueType, unsigned> {
static bool Is(const ValueType& v) { return v.IsUint(); }
static unsigned Get(const ValueType& v) { return v.GetUint(); }
static ValueType& Set(ValueType& v, unsigned data) { return v.SetUint(data); }
static ValueType& Set(ValueType& v, unsigned data, typename ValueType::AllocatorType&) { return v.SetUint(data); }
};
template<typename ValueType>
struct TypeHelper<ValueType, int64_t> {
static bool Is(const ValueType& v) { return v.IsInt64(); }
static int64_t Get(const ValueType& v) { return v.GetInt64(); }
static ValueType& Set(ValueType& v, int64_t data) { return v.SetInt64(data); }
static ValueType& Set(ValueType& v, int64_t data, typename ValueType::AllocatorType&) { return v.SetInt64(data); }
};
template<typename ValueType>
struct TypeHelper<ValueType, uint64_t> {
static bool Is(const ValueType& v) { return v.IsUint64(); }
static uint64_t Get(const ValueType& v) { return v.GetUint64(); }
static ValueType& Set(ValueType& v, uint64_t data) { return v.SetUint64(data); }
static ValueType& Set(ValueType& v, uint64_t data, typename ValueType::AllocatorType&) { return v.SetUint64(data); }
};
template<typename ValueType>
struct TypeHelper<ValueType, double> {
static bool Is(const ValueType& v) { return v.IsDouble(); }
static double Get(const ValueType& v) { return v.GetDouble(); }
static ValueType& Set(ValueType& v, double data) { return v.SetDouble(data); }
static ValueType& Set(ValueType& v, double data, typename ValueType::AllocatorType&) { return v.SetDouble(data); }
};
template<typename ValueType>
struct TypeHelper<ValueType, float> {
static bool Is(const ValueType& v) { return v.IsFloat(); }
static float Get(const ValueType& v) { return v.GetFloat(); }
static ValueType& Set(ValueType& v, float data) { return v.SetFloat(data); }
static ValueType& Set(ValueType& v, float data, typename ValueType::AllocatorType&) { return v.SetFloat(data); }
};
template<typename ValueType>
struct TypeHelper<ValueType, const typename ValueType::Ch*> {
typedef const typename ValueType::Ch* StringType;
static bool Is(const ValueType& v) { return v.IsString(); }
static StringType Get(const ValueType& v) { return v.GetString(); }
static ValueType& Set(ValueType& v, const StringType data) { return v.SetString(typename ValueType::StringRefType(data)); }
static ValueType& Set(ValueType& v, const StringType data, typename ValueType::AllocatorType& a) { return v.SetString(data, a); }
};
#if RAPIDJSON_HAS_STDSTRING
template<typename ValueType>
struct TypeHelper<ValueType, std::basic_string<typename ValueType::Ch> > {
typedef std::basic_string<typename ValueType::Ch> StringType;
static bool Is(const ValueType& v) { return v.IsString(); }
static StringType Get(const ValueType& v) { return v.GetString(); }
static ValueType& Set(ValueType& v, const StringType& data, typename ValueType::AllocatorType& a) { return v.SetString(data, a); }
};
#endif
template<typename ValueType>
struct TypeHelper<ValueType, typename ValueType::Array> {
typedef typename ValueType::Array ArrayType;
static bool Is(const ValueType& v) { return v.IsArray(); }
static ArrayType Get(ValueType& v) { return v.GetArray(); }
static ValueType& Set(ValueType& v, ArrayType data) { return v = data; }
static ValueType& Set(ValueType& v, ArrayType data, typename ValueType::AllocatorType&) { return v = data; }
};
template<typename ValueType>
struct TypeHelper<ValueType, typename ValueType::ConstArray> {
typedef typename ValueType::ConstArray ArrayType;
static bool Is(const ValueType& v) { return v.IsArray(); }
static ArrayType Get(const ValueType& v) { return v.GetArray(); }
};
template<typename ValueType>
struct TypeHelper<ValueType, typename ValueType::Object> {
typedef typename ValueType::Object ObjectType;
static bool Is(const ValueType& v) { return v.IsObject(); }
static ObjectType Get(ValueType& v) { return v.GetObject(); }
static ValueType& Set(ValueType& v, ObjectType data) { return v = data; }
static ValueType& Set(ValueType& v, ObjectType data, typename ValueType::AllocatorType&) { v = data; }
};
template<typename ValueType>
struct TypeHelper<ValueType, typename ValueType::ConstObject> {
typedef typename ValueType::ConstObject ObjectType;
static bool Is(const ValueType& v) { return v.IsObject(); }
static ObjectType Get(const ValueType& v) { return v.GetObject(); }
};
} // namespace internal
// Forward declarations
template <bool, typename> class GenericArray;
template <bool, typename> class GenericObject;
///////////////////////////////////////////////////////////////////////////////
// GenericValue
......@@ -420,6 +541,10 @@ public:
typedef GenericValue* ValueIterator; //!< Value iterator for iterating in array.
typedef const GenericValue* ConstValueIterator; //!< Constant value iterator for iterating in array.
typedef GenericValue<Encoding, Allocator> ValueType; //!< Value type of itself.
typedef GenericArray<false, ValueType> Array;
typedef GenericArray<true, ValueType> ConstArray;
typedef GenericObject<false, ValueType> Object;
typedef GenericObject<true, ValueType> ConstObject;
//!@name Constructors and destructor.
//@{
......@@ -556,6 +681,28 @@ public:
GenericValue(const std::basic_string<Ch>& s, Allocator& allocator) : data_(), flags_() { SetStringRaw(StringRef(s), allocator); }
#endif
//! Constructor for Array.
/*!
\param a An array obtained by \c GetArray().
\note \c Array is always pass-by-value.
\note the source array is moved into this value and the sourec array becomes empty.
*/
GenericValue(Array a) RAPIDJSON_NOEXCEPT : data_(a.value_.data_), flags_(a.value_.flags_) {
a.value_.data_ = Data();
a.value_.flags_ = kArrayFlag;
}
//! Constructor for Object.
/*!
\param o An object obtained by \c GetObject().
\note \c Object is always pass-by-value.
\note the source object is moved into this value and the sourec object becomes empty.
*/
GenericValue(Object o) RAPIDJSON_NOEXCEPT : data_(o.value_.data_), flags_(o.value_.flags_) {
o.value_.data_ = Data();
o.value_.flags_ = kObjectFlag;
}
//! Destructor.
/*! Need to destruct elements of array, members of object, or copy-string.
*/
......@@ -1020,7 +1167,7 @@ public:
RAPIDJSON_ASSERT(IsObject());
RAPIDJSON_ASSERT(name.IsString());
Object& o = data_.o;
ObjectData& o = data_.o;
if (o.size >= o.capacity) {
if (o.capacity == 0) {
o.capacity = kDefaultObjectCapacity;
......@@ -1291,6 +1438,9 @@ public:
return false;
}
Object GetObject() { RAPIDJSON_ASSERT(IsObject()); return Object(*this); }
ConstObject GetObject() const { RAPIDJSON_ASSERT(IsObject()); return ConstObject(*this); }
//@}
//!@name Array
......@@ -1466,6 +1616,9 @@ public:
return pos;
}
Array GetArray() { RAPIDJSON_ASSERT(IsArray()); return Array(*this); }
ConstArray GetArray() const { RAPIDJSON_ASSERT(IsArray()); return ConstArray(*this); }
//@}
//!@name Number
......@@ -1563,6 +1716,30 @@ public:
//@}
//!@name Array
//@{
//! Templated version for checking whether this value is type T.
/*!
\tparam T Either \c bool, \c int, \c unsigned, \c int64_t, \c uint64_t, \c double, \c float, \c const \c char*, \c std::basic_string<Ch>
*/
template <typename T>
bool Is() const { return internal::TypeHelper<ValueType, T>::Is(*this); }
template <typename T>
T Get() const { return internal::TypeHelper<ValueType, T>::Get(*this); }
template <typename T>
T Get() { return internal::TypeHelper<ValueType, T>::Get(*this); }
template<typename T>
ValueType& Set(const T& data) { return internal::TypeHelper<ValueType, T>::Set(*this, data); }
template<typename T>
ValueType& Set(const T& data, AllocatorType& allocator) { return internal::TypeHelper<ValueType, T>::Set(*this, data, allocator); }
//@}
//! Generate events of this value to a Handler.
/*! This function adopts the GoF visitor pattern.
Typical usage is to output this JSON value as JSON text via Writer, which is a Handler.
......@@ -1697,13 +1874,13 @@ private:
double d;
}; // 8 bytes
struct Object {
struct ObjectData {
Member* members;
SizeType size;
SizeType capacity;
}; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
struct Array {
struct ArrayData {
GenericValue* elements;
SizeType size;
SizeType capacity;
......@@ -1713,8 +1890,8 @@ private:
String s;
ShortString ss;
Number n;
Object o;
Array a;
ObjectData o;
ArrayData a;
}; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
// Initialize this value as array with initial data, without calling destructor.
......@@ -2172,6 +2349,145 @@ GenericValue<Encoding,Allocator>::GenericValue(const GenericValue<Encoding,Sourc
}
}
//! Helper class for accessing Value of array type.
/*!
Instance of this helper class is obtained by \c GenericValue::GetArray().
In addition to all APIs for array type, it provides range-based for loop if \c RAPIDJSON_HAS_CXX11_RANGE_FOR=1.
*/
template <bool Const, typename ValueT>
class GenericArray {
public:
typedef GenericArray<true, ValueT> ConstArray;
typedef GenericArray<false, ValueT> Array;
typedef ValueT PlainType;
typedef typename internal::MaybeAddConst<Const,PlainType>::Type ValueType;
typedef ValueType* ValueIterator; // This may be const or non-const iterator
typedef const ValueT* ConstValueIterator;
typedef typename ValueType::AllocatorType AllocatorType;
typedef typename ValueType::StringRefType StringRefType;
template <typename, typename>
friend class GenericValue;
GenericArray(const GenericArray& rhs) : value_(rhs.value_) {}
GenericArray& operator=(const GenericArray& rhs) { value_ = rhs.value_; return *this; }
~GenericArray() {}
SizeType Size() const { return value_.Size(); }
SizeType Capacity() const { return value_.Capacity(); }
bool Empty() const { return value_.Empty(); }
void Clear() const { value_.Clear(); }
ValueType& operator[](SizeType index) const { return value_[index]; }
ValueIterator Begin() const { return value_.Begin(); }
ValueIterator End() const { return value_.End(); }
GenericArray Reserve(SizeType newCapacity, AllocatorType &allocator) const { value_.Reserve(newCapacity, allocator); return *this; }
GenericArray PushBack(ValueType& value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; }
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
GenericArray PushBack(ValueType&& value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; }
#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
GenericArray PushBack(StringRefType value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; }
template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (const GenericArray&)) PushBack(T value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; }
GenericArray PopBack() const { value_.PopBack(); return *this; }
ValueIterator Erase(ConstValueIterator pos) const { return value_.Erase(pos); }
ValueIterator Erase(ConstValueIterator first, ConstValueIterator last) const { return value_.Erase(first, last); }
#if RAPIDJSON_HAS_CXX11_RANGE_FOR
ValueIterator begin() const { return value_.Begin(); }
ValueIterator end() const { return value_.End(); }
#endif
private:
GenericArray();
GenericArray(ValueType& value) : value_(value) {}
ValueType& value_;
};
//! Helper class for accessing Value of array type.
/*!
Instance of this helper class is obtained by \c GenericValue::GetArray().
In addition to all APIs for array type, it provides range-based for loop if \c RAPIDJSON_HAS_CXX11_RANGE_FOR=1.
*/
template <bool Const, typename ValueT>
class GenericObject {
public:
typedef GenericObject<true, ValueT> ConstObject;
typedef GenericObject<false, ValueT> Object;
typedef ValueT PlainType;
typedef typename internal::MaybeAddConst<Const,PlainType>::Type ValueType;
typedef GenericMemberIterator<Const, typename ValueT::EncodingType, typename ValueT::AllocatorType> MemberIterator; // This may be const or non-const iterator
typedef GenericMemberIterator<true, typename ValueT::EncodingType, typename ValueT::AllocatorType> ConstMemberIterator;
typedef typename ValueType::AllocatorType AllocatorType;
typedef typename ValueType::StringRefType StringRefType;
typedef typename ValueType::EncodingType EncodingType;
typedef typename ValueType::Ch Ch;
template <typename, typename>
friend class GenericValue;
GenericObject(const GenericObject& rhs) : value_(rhs.value_) {}
GenericObject& operator=(const GenericObject& rhs) { value_ = rhs.value_; return *this; }
~GenericObject() {}
SizeType MemberCount() const { return value_.MemberCount(); }
bool ObjectEmpty() const { return value_.ObjectEmpty(); }
template <typename T> ValueType& operator[](T* name) const { return value_[name]; }
template <typename SourceAllocator> ValueType& operator[](const GenericValue<EncodingType, SourceAllocator>& name) const { return value_[name]; }
#if RAPIDJSON_HAS_STDSTRING
ValueType& operator[](const std::basic_string<Ch>& name) const { return value_[name]; }
#endif
MemberIterator MemberBegin() const { return value_.MemberBegin(); }
MemberIterator MemberEnd() const { return value_.MemberEnd(); }
bool HasMember(const Ch* name) const { return value_.HasMember(name); }
#if RAPIDJSON_HAS_STDSTRING
bool HasMember(const std::basic_string<Ch>& name) const { return value_.HasMember(name); }
#endif
template <typename SourceAllocator> bool HasMember(const GenericValue<EncodingType, SourceAllocator>& name) const { return value_.HasMember(name); }
MemberIterator FindMember(const Ch* name) const { value_.FindMember(name); }
template <typename SourceAllocator> MemberIterator FindMember(const GenericValue<EncodingType, SourceAllocator>& name) const { value_.FindMember(name); }
#if RAPIDJSON_HAS_STDSTRING
MemberIterator FindMember(const std::basic_string<Ch>& name) const { return value_.FindMember(name); }
#endif
GenericObject AddMember(ValueType& name, ValueType& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
GenericObject AddMember(ValueType& name, StringRefType value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
#if RAPIDJSON_HAS_STDSTRING
GenericObject AddMember(ValueType& name, std::basic_string<Ch>& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
#endif
template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&)) AddMember(ValueType& name, T value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
GenericObject AddMember(ValueType&& name, ValueType&& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
GenericObject AddMember(ValueType&& name, ValueType& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
GenericObject AddMember(ValueType& name, ValueType&& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
GenericObject AddMember(StringRefType name, ValueType&& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
GenericObject AddMember(StringRefType name, ValueType& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
GenericObject AddMember(StringRefType name, StringRefType value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (GenericObject)) AddMember(StringRefType name, T value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
void RemoveAllMembers() { return value_.RemoveAllMembers(); }
bool RemoveMember(const Ch* name) const { return value_.RemoveMember(name); }
#if RAPIDJSON_HAS_STDSTRING
bool RemoveMember(const std::basic_string<Ch>& name) const { return value_.RemoveMember(name); }
#endif
template <typename SourceAllocator> bool RemoveMember(const GenericValue<EncodingType, SourceAllocator>& name) const { return value_.RemoveMember(name); }
MemberIterator RemoveMember(MemberIterator m) const { return value_.RemoveMember(m); }
MemberIterator EraseMember(ConstMemberIterator pos) const { return value_.EraseMember(pos); }
MemberIterator EraseMember(ConstMemberIterator first, ConstMemberIterator last) const { return value_.EraseMember(first, last); }
bool EraseMember(const Ch* name) const { return value_.EraseMember(name); }
#if RAPIDJSON_HAS_STDSTRING
bool EraseMember(const std::basic_string<Ch>& name) const { return EraseMember(ValueType(StringRef(name))); }
#endif
template <typename SourceAllocator> bool EraseMember(const GenericValue<EncodingType, SourceAllocator>& name) const { return value_.EraseMember(name); }
#if RAPIDJSON_HAS_CXX11_RANGE_FOR
MemberIterator begin() const { return value_.MemberBegin(); }
MemberIterator end() const { return value_.MemberEnd(); }
#endif
private:
GenericObject();
GenericObject(ValueType& value) : value_(value) {}
ValueType& value_;
};
RAPIDJSON_NAMESPACE_END
#ifdef _MSC_VER
......
......@@ -530,6 +530,17 @@ RAPIDJSON_NAMESPACE_END
#define RAPIDJSON_HAS_CXX11_TYPETRAITS 0
#endif
#ifndef RAPIDJSON_HAS_CXX11_RANGE_FOR
#if defined(__clang__)
#define RAPIDJSON_HAS_CXX11_RANGE_FOR __has_feature(cxx_range_for)
#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,3,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \
(defined(_MSC_VER) && _MSC_VER >= 1600)
#define RAPIDJSON_HAS_CXX11_RANGE_FOR 1
#else
#define RAPIDJSON_HAS_CXX11_RANGE_FOR 0
#endif
#endif // RAPIDJSON_HAS_CXX11_RANGE_FOR
//!@endcond
///////////////////////////////////////////////////////////////////////////////
......
......@@ -335,6 +335,12 @@ TEST(Value, True) {
Value z;
z.SetBool(true);
EXPECT_TRUE(z.IsTrue());
// Templated functions
EXPECT_TRUE(z.Is<bool>());
EXPECT_TRUE(z.Get<bool>());
EXPECT_FALSE(z.Set<bool>(false).Get<bool>());
EXPECT_TRUE(z.Set(true).Get<bool>());
}
TEST(Value, False) {
......@@ -414,6 +420,12 @@ TEST(Value, Int) {
// operator=(int)
z = 5678;
EXPECT_EQ(5678, z.GetInt());
// Templated functions
EXPECT_TRUE(z.Is<int>());
EXPECT_EQ(5678, z.Get<int>());
EXPECT_EQ(5679, z.Set(5679).Get<int>());
EXPECT_EQ(5680, z.Set<int>(5680).Get<int>());
}
TEST(Value, Uint) {
......@@ -453,6 +465,12 @@ TEST(Value, Uint) {
EXPECT_EQ(2147483648u, z.GetUint());
EXPECT_FALSE(z.IsInt());
EXPECT_TRUE(z.IsInt64()); // Issue 41: Incorrect parsing of unsigned int number types
// Templated functions
EXPECT_TRUE(z.Is<unsigned>());
EXPECT_EQ(2147483648u, z.Get<unsigned>());
EXPECT_EQ(2147483649u, z.Set(2147483649u).Get<unsigned>());
EXPECT_EQ(2147483650u, z.Set<unsigned>(2147483650u).Get<unsigned>());
}
TEST(Value, Int64) {
......@@ -505,8 +523,15 @@ TEST(Value, Int64) {
EXPECT_FALSE(z.IsInt());
EXPECT_NEAR(-2147483649.0, z.GetDouble(), 0.0);
z.SetInt64(static_cast<int64_t>(RAPIDJSON_UINT64_C2(0x80000000, 00000000)));
int64_t i = static_cast<int64_t>(RAPIDJSON_UINT64_C2(0x80000000, 00000000));
z.SetInt64(i);
EXPECT_DOUBLE_EQ(-9223372036854775808.0, z.GetDouble());
// Templated functions
EXPECT_TRUE(z.Is<int64_t>());
EXPECT_EQ(i, z.Get<int64_t>());
EXPECT_EQ(i - 1, z.Set(i - 1).Get<int64_t>());
EXPECT_EQ(i - 2, z.Set<int64_t>(i - 2).Get<int64_t>());
}
TEST(Value, Uint64) {
......@@ -547,10 +572,17 @@ TEST(Value, Uint64) {
EXPECT_FALSE(z.IsUint());
EXPECT_TRUE(z.IsInt64());
z.SetUint64(RAPIDJSON_UINT64_C2(0x80000000, 0x00000000)); // 2^63 cannot cast as int64
uint64_t u = RAPIDJSON_UINT64_C2(0x80000000, 0x00000000);
z.SetUint64(u); // 2^63 cannot cast as int64
EXPECT_FALSE(z.IsInt64());
EXPECT_EQ(RAPIDJSON_UINT64_C2(0x80000000, 0x00000000), z.GetUint64()); // Issue 48
EXPECT_EQ(u, z.GetUint64()); // Issue 48
EXPECT_DOUBLE_EQ(9223372036854775808.0, z.GetDouble());
// Templated functions
EXPECT_TRUE(z.Is<uint64_t>());
EXPECT_EQ(u, z.Get<uint64_t>());
EXPECT_EQ(u + 1, z.Set(u + 1).Get<uint64_t>());
EXPECT_EQ(u + 2, z.Set<uint64_t>(u + 2).Get<uint64_t>());
}
TEST(Value, Double) {
......@@ -577,6 +609,12 @@ TEST(Value, Double) {
z = 56.78;
EXPECT_NEAR(56.78, z.GetDouble(), 0.0);
// Templated functions
EXPECT_TRUE(z.Is<double>());
EXPECT_EQ(56.78, z.Get<double>());
EXPECT_EQ(57.78, z.Set(57.78).Get<double>());
EXPECT_EQ(58.78, z.Set<double>(58.78).Get<double>());
}
TEST(Value, Float) {
......@@ -604,6 +642,12 @@ TEST(Value, Float) {
z = 56.78f;
EXPECT_NEAR(56.78f, z.GetFloat(), 0.0f);
// Templated functions
EXPECT_TRUE(z.Is<float>());
EXPECT_EQ(56.78f, z.Get<float>());
EXPECT_EQ(57.78f, z.Set(57.78f).Get<float>());
EXPECT_EQ(58.78f, z.Set<float>(58.78f).Get<float>());
}
TEST(Value, IsLosslessDouble) {
......@@ -724,6 +768,11 @@ TEST(Value, String) {
EXPECT_STREQ("World", w.GetString());
EXPECT_EQ(5u, w.GetStringLength());
// templated functions
EXPECT_TRUE(z.Is<const char*>());
EXPECT_STREQ(cstr, z.Get<const char*>());
EXPECT_STREQ("Apple", z.Set<const char*>("Apple").Get<const char*>());
#if RAPIDJSON_HAS_STDSTRING
{
std::string str = "Hello World";
......@@ -759,6 +808,14 @@ TEST(Value, String) {
vs1 = StringRef(str);
TestEqual(str, vs1);
TestEqual(vs0, vs1);
// Templated function.
EXPECT_TRUE(vs0.Is<std::string>());
EXPECT_EQ(str, vs0.Get<std::string>());
vs0.Set<std::string>(std::string("Apple"), allocator);
EXPECT_EQ(std::string("Apple"), vs0.Get<std::string>());
vs0.Set(std::string("Orange"), allocator);
EXPECT_EQ(std::string("Orange"), vs0.Get<std::string>());
}
#endif // RAPIDJSON_HAS_STDSTRING
}
......@@ -769,25 +826,9 @@ TEST(Value, SetStringNullException) {
EXPECT_THROW(v.SetString(0, 0), AssertException);
}
TEST(Value, Array) {
Value x(kArrayType);
const Value& y = x;
Value::AllocatorType allocator;
EXPECT_EQ(kArrayType, x.GetType());
EXPECT_TRUE(x.IsArray());
EXPECT_TRUE(x.Empty());
EXPECT_EQ(0u, x.Size());
EXPECT_TRUE(y.IsArray());
EXPECT_TRUE(y.Empty());
EXPECT_EQ(0u, y.Size());
EXPECT_FALSE(x.IsNull());
EXPECT_FALSE(x.IsBool());
EXPECT_FALSE(x.IsFalse());
EXPECT_FALSE(x.IsTrue());
EXPECT_FALSE(x.IsString());
EXPECT_FALSE(x.IsObject());
template <typename T, typename Allocator>
static void TestArray(T& x, Allocator& allocator) {
const T& y = x;
// PushBack()
Value v;
......@@ -834,7 +875,7 @@ TEST(Value, Array) {
#endif
// iterator
Value::ValueIterator itr = x.Begin();
typename T::ValueIterator itr = x.Begin();
EXPECT_TRUE(itr != x.End());
EXPECT_TRUE(itr->IsNull());
++itr;
......@@ -853,7 +894,7 @@ TEST(Value, Array) {
EXPECT_STREQ("foo", itr->GetString());
// const iterator
Value::ConstValueIterator citr = y.Begin();
typename T::ConstValueIterator citr = y.Begin();
EXPECT_TRUE(citr != y.End());
EXPECT_TRUE(citr->IsNull());
++citr;
......@@ -939,6 +980,29 @@ TEST(Value, Array) {
EXPECT_EQ(i + removeCount, x[static_cast<SizeType>(i)][0].GetUint());
}
}
}
TEST(Value, Array) {
Value x(kArrayType);
const Value& y = x;
Value::AllocatorType allocator;
EXPECT_EQ(kArrayType, x.GetType());
EXPECT_TRUE(x.IsArray());
EXPECT_TRUE(x.Empty());
EXPECT_EQ(0u, x.Size());
EXPECT_TRUE(y.IsArray());
EXPECT_TRUE(y.Empty());
EXPECT_EQ(0u, y.Size());
EXPECT_FALSE(x.IsNull());
EXPECT_FALSE(x.IsBool());
EXPECT_FALSE(x.IsFalse());
EXPECT_FALSE(x.IsTrue());
EXPECT_FALSE(x.IsString());
EXPECT_FALSE(x.IsObject());
TestArray(x, allocator);
// Working in gcc without C++11, but VS2013 cannot compile. To be diagnosed.
// http://en.wikipedia.org/wiki/Erase-remove_idiom
......@@ -962,19 +1026,96 @@ TEST(Value, Array) {
EXPECT_TRUE(z.Empty());
}
TEST(Value, Object) {
Value x(kObjectType);
const Value& y = x; // const version
TEST(Value, ArrayHelper) {
Value::AllocatorType allocator;
{
Value x(kArrayType);
Value::Array a = x.GetArray();
TestArray(a, allocator);
}
EXPECT_EQ(kObjectType, x.GetType());
EXPECT_TRUE(x.IsObject());
EXPECT_TRUE(x.ObjectEmpty());
EXPECT_EQ(0u, x.MemberCount());
EXPECT_EQ(kObjectType, y.GetType());
EXPECT_TRUE(y.IsObject());
EXPECT_TRUE(y.ObjectEmpty());
EXPECT_EQ(0u, y.MemberCount());
{
Value x(kArrayType);
Value::Array a = x.GetArray();
a.PushBack(1, allocator);
Value::Array a2(a); // copy constructor
EXPECT_EQ(1, a2.Size());
Value::Array a3 = a;
EXPECT_EQ(1, a3.Size());
Value::ConstArray y = static_cast<const Value&>(x).GetArray();
(void)y;
// y.PushBack(1, allocator); // should not compile
// Templated functions
x.Clear();
EXPECT_TRUE(x.Is<Value::Array>());
EXPECT_TRUE(x.Is<Value::ConstArray>());
a.PushBack(1, allocator);
EXPECT_EQ(1, x.Get<Value::Array>()[0].GetInt());
EXPECT_EQ(1, x.Get<Value::ConstArray>()[0].GetInt());
Value x2;
x2.Set<Value::Array>(a);
EXPECT_TRUE(x.IsArray()); // IsArray() is invariant after moving.
EXPECT_EQ(1, x2.Get<Value::Array>()[0].GetInt());
}
{
Value y(kArrayType);
y.PushBack(123, allocator);
Value x(y.GetArray()); // Construct value form array.
EXPECT_TRUE(x.IsArray());
EXPECT_EQ(123, x[0].GetInt());
EXPECT_TRUE(y.IsArray()); // Invariant
EXPECT_TRUE(y.Empty());
}
{
Value x(kArrayType);
Value y(kArrayType);
y.PushBack(123, allocator);
x.PushBack(y.GetArray(), allocator); // Implicit constructor to convert Array to GenericValue
EXPECT_EQ(1, x.Size());
EXPECT_EQ(123, x[0][0].GetInt());
EXPECT_TRUE(y.IsArray());
EXPECT_TRUE(y.Empty());
}
}
#if RAPIDJSON_HAS_CXX11_RANGE_FOR
TEST(Value, ArrayHelperRangeFor) {
Value::AllocatorType allocator;
Value x(kArrayType);
for (int i = 0; i < 10; i++)
x.PushBack(i, allocator);
{
int i = 0;
for (auto& v : x.GetArray())
EXPECT_EQ(i++, v.GetInt());
EXPECT_EQ(i, 10);
}
{
int i = 0;
for (const auto& v : const_cast<const Value&>(x).GetArray())
EXPECT_EQ(i++, v.GetInt());
EXPECT_EQ(i, 10);
}
// Array a = x.GetArray();
// Array ca = const_cast<const Value&>(x).GetArray();
}
#endif
template <typename T, typename Allocator>
static void TestObject(T& x, Allocator& allocator) {
const T& y = x; // const version
// AddMember()
x.AddMember("A", "Apple", allocator);
......@@ -1215,7 +1356,7 @@ TEST(Value, Object) {
const unsigned n = 10;
for (unsigned first = 0; first < n; first++) {
for (unsigned last = first; last <= n; last++) {
Value(kObjectType).Swap(x);
x.RemoveAllMembers();
for (unsigned i = 0; i < n; i++)
x.AddMember(keys[i], Value(kArrayType).PushBack(i, allocator), allocator);
......@@ -1238,6 +1379,23 @@ TEST(Value, Object) {
x.RemoveAllMembers();
EXPECT_TRUE(x.ObjectEmpty());
EXPECT_EQ(0u, x.MemberCount());
}
TEST(Value, Object) {
Value x(kObjectType);
const Value& y = x; // const version
Value::AllocatorType allocator;
EXPECT_EQ(kObjectType, x.GetType());
EXPECT_TRUE(x.IsObject());
EXPECT_TRUE(x.ObjectEmpty());
EXPECT_EQ(0u, x.MemberCount());
EXPECT_EQ(kObjectType, y.GetType());
EXPECT_TRUE(y.IsObject());
EXPECT_TRUE(y.ObjectEmpty());
EXPECT_EQ(0u, y.MemberCount());
TestObject(x, allocator);
// SetObject()
Value z;
......@@ -1245,6 +1403,100 @@ TEST(Value, Object) {
EXPECT_TRUE(z.IsObject());
}
TEST(Value, ObjectHelper) {
Value::AllocatorType allocator;
{
Value x(kObjectType);
Value::Object o = x.GetObject();
TestObject(o, allocator);
}
{
Value x(kObjectType);
Value::Object o = x.GetObject();
o.AddMember("1", 1, allocator);
Value::Object o2(o); // copy constructor
EXPECT_EQ(1, o2.MemberCount());
Value::Object o3 = o;
EXPECT_EQ(1, o3.MemberCount());
Value::ConstObject y = static_cast<const Value&>(x).GetObject();
(void)y;
// y.AddMember("1", 1, allocator); // should not compile
// Templated functions
x.RemoveAllMembers();
EXPECT_TRUE(x.Is<Value::Object>());
EXPECT_TRUE(x.Is<Value::ConstObject>());
o.AddMember("1", 1, allocator);
EXPECT_EQ(1, x.Get<Value::Object>()["1"].GetInt());
EXPECT_EQ(1, x.Get<Value::ConstObject>()["1"].GetInt());
Value x2;
x2.Set<Value::Object>(o);
EXPECT_TRUE(x.IsObject()); // IsObject() is invariant after moving
EXPECT_EQ(1, x2.Get<Value::Object>()["1"].GetInt());
}
{
Value x(kObjectType);
x.AddMember("a", "apple", allocator);
Value y(x.GetObject());
EXPECT_STREQ("apple", y["a"].GetString());
EXPECT_TRUE(x.IsObject()); // Invariant
}
{
Value x(kObjectType);
x.AddMember("a", "apple", allocator);
Value y(kObjectType);
y.AddMember("fruits", x.GetObject(), allocator);
EXPECT_STREQ("apple", y["fruits"]["a"].GetString());
EXPECT_TRUE(x.IsObject()); // Invariant
}
}
#if RAPIDJSON_HAS_CXX11_RANGE_FOR
TEST(Value, ObjectHelperRangeFor) {
Value::AllocatorType allocator;
Value x(kObjectType);
for (int i = 0; i < 10; i++) {
char name[10];
Value n(name, static_cast<SizeType>(sprintf(name, "%d", i)), allocator);
x.AddMember(n, i, allocator);
}
{
int i = 0;
for (auto& m : x.GetObject()) {
char name[10];
sprintf(name, "%d", i);
EXPECT_STREQ(name, m.name.GetString());
EXPECT_EQ(i, m.value.GetInt());
i++;
}
EXPECT_EQ(i, 10);
}
{
int i = 0;
for (const auto& m : const_cast<const Value&>(x).GetObject()) {
char name[10];
sprintf(name, "%d", i);
EXPECT_STREQ(name, m.name.GetString());
EXPECT_EQ(i, m.value.GetInt());
i++;
}
EXPECT_EQ(i, 10);
}
// Object a = x.GetObject();
// Object ca = const_cast<const Value&>(x).GetObject();
}
#endif
TEST(Value, EraseMember_String) {
Value::AllocatorType allocator;
Value x(kObjectType);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment