Add GenericArray helper class with range-based for
This commit is contained in:
parent
c6946fd2c1
commit
59309b5dd2
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user