Commit 59309b5d authored by Milo Yip's avatar Milo Yip

Add GenericArray helper class with range-based for

parent c6946fd2
......@@ -483,6 +483,9 @@ struct TypeHelper<ValueType, std::basic_string<typename ValueType::Ch> > {
} // namespace internal
template <typename ValueType>
class GenericArray;
///////////////////////////////////////////////////////////////////////////////
// GenericValue
......@@ -510,6 +513,7 @@ 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<ValueType> ArrayType;
//!@name Constructors and destructor.
//@{
......@@ -1556,6 +1560,9 @@ public:
return pos;
}
ArrayType GetArray() { RAPIDJSON_ASSERT(IsArray()); return ArrayType(*this); }
const ArrayType GetArray() const { RAPIDJSON_ASSERT(IsArray()); return ArrayType(*this); }
//@}
//!@name Number
......@@ -1653,9 +1660,12 @@ 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 std::basic_string<Ch>
\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); }
......@@ -1669,6 +1679,8 @@ public:
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.
......@@ -2278,6 +2290,65 @@ 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 <typename ValueType>
class GenericArray {
public:
typedef typename ValueType::ValueIterator ValueIterator;
typedef typename ValueType::ConstValueIterator ConstValueIterator;
typedef typename ValueType::AllocatorType AllocatorType;
typedef typename ValueType::StringRefType StringRefType;
template <typename, typename>
friend class GenericValue;
GenericArray() : ptr_() {}
GenericArray(const GenericArray& rhs) : ptr_(rhs.ptr_) {}
GenericArray& operator=(GenericArray& rhs) { ptr_ = rhs.ptr_; return *this; }
~GenericArray() {}
SizeType Size() const { return ptr_->Size(); }
SizeType Capacity() const { return ptr_->Capacity(); }
bool Empty() const { return ptr_->Empty(); }
void Clear() { ptr_->Clear(); }
ValueType& operator[](SizeType index) { return (*ptr_)[index]; }
const ValueType& operator[](SizeType index) const { return (*ptr_)[index]; }
ValueIterator Begin() { return ptr_->Begin(); }
ValueIterator End() { return ptr_->End(); }
ConstValueIterator Begin() const { return ptr_->Begin(); }
ConstValueIterator End() const { return ptr_->End(); }
GenericArray& Reserve(SizeType newCapacity, AllocatorType &allocator) { ptr_->Reserve(newCapacity, allocator); return *this; }
GenericArray& PushBack(ValueType& value, AllocatorType& allocator) { ptr_->PushBack(value, allocator); return *this; }
#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
GenericArray& PushBack(ValueType&& value, AllocatorType& allocator) { ptr_->PushBack(value, allocator); return *this; }
#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
GenericArray& PushBack(StringRefType value, AllocatorType& allocator) { ptr_->PushBack(value, allocator); return *this; }
template <typename T>
RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (GenericArray&))
PushBack(T value, AllocatorType& allocator) { ptr_->PushBack(value, allocator); return *this; }
GenericArray& PopBack() { ptr_->PopBack(); return *this; }
ValueIterator Erase(ConstValueIterator pos) { return ptr_->Erase(pos); }
ValueIterator Erase(ConstValueIterator first, ConstValueIterator last) { return ptr_->Erase(first, last); }
#if RAPIDJSON_HAS_CXX11_RANGE_FOR
ValueIterator begin() { return ptr_->Begin(); }
ValueIterator end() { return ptr_->End(); }
ConstValueIterator begin() const { return ptr_->Begin(); }
ConstValueIterator end() const { return ptr_->End(); }
#endif
private:
GenericArray(ValueType& value) : ptr_(&value) {}
GenericArray(const ValueType& value) : ptr_(const_cast<ValueType*>(&value)) {}
ValueType* ptr_;
};
typedef GenericArray<Value> Array;
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
///////////////////////////////////////////////////////////////////////////////
......
......@@ -824,25 +824,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>
void TestArray(T& x, Allocator& allocator) {
const T& y = x;
// PushBack()
Value v;
......@@ -889,7 +873,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;
......@@ -908,7 +892,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;
......@@ -994,6 +978,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
......@@ -1017,6 +1024,52 @@ TEST(Value, Array) {
EXPECT_TRUE(z.Empty());
}
TEST(Value, ArrayHelper) {
Value::AllocatorType allocator;
{
Value x(kArrayType);
Array a = x.GetArray();
TestArray(a, allocator);
}
Value x(kArrayType);
Array a = x.GetArray();
a.PushBack(1, allocator);
Array a2(a); // copy constructor
EXPECT_EQ(1, a2.Size());
Array a3; // default constructor
a3 = a; // assignment operator
EXPECT_EQ(1, a3.Size());
}
#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 (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
TEST(Value, Object) {
Value x(kObjectType);
const Value& y = x; // const version
......
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