Merge pull request #125 from pah/fixes/113
Fix comparison operator ambiguities between Value/Document
This commit is contained in:
commit
ab8416e1e6
@ -1993,7 +1993,9 @@ INCLUDE_FILE_PATTERNS =
|
|||||||
|
|
||||||
PREDEFINED = \
|
PREDEFINED = \
|
||||||
RAPIDJSON_DOXYGEN_RUNNING \
|
RAPIDJSON_DOXYGEN_RUNNING \
|
||||||
RAPIDJSON_DISABLEIF_RETURN(cond,returntype)=returntype
|
RAPIDJSON_REMOVEFPTR_(x)=x \
|
||||||
|
RAPIDJSON_ENABLEIF_RETURN(cond,returntype)="RAPIDJSON_REMOVEFPTR_ returntype" \
|
||||||
|
RAPIDJSON_DISABLEIF_RETURN(cond,returntype)="RAPIDJSON_REMOVEFPTR_ returntype"
|
||||||
|
|
||||||
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
|
# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
|
||||||
# tag can be used to specify a list of macro names that should be expanded. The
|
# tag can be used to specify a list of macro names that should be expanded. The
|
||||||
|
@ -458,7 +458,10 @@ public:
|
|||||||
#else
|
#else
|
||||||
explicit GenericValue(bool b)
|
explicit GenericValue(bool b)
|
||||||
#endif
|
#endif
|
||||||
: data_(), flags_(b ? kTrueFlag : kFalseFlag) {}
|
: data_(), flags_(b ? kTrueFlag : kFalseFlag) {
|
||||||
|
// safe-guard against failing SFINAE
|
||||||
|
RAPIDJSON_STATIC_ASSERT((internal::IsSame<bool,T>::Value));
|
||||||
|
}
|
||||||
|
|
||||||
//! Constructor for int value.
|
//! Constructor for int value.
|
||||||
explicit GenericValue(int i) : data_(), flags_(kNumberIntFlag) {
|
explicit GenericValue(int i) : data_(), flags_(kNumberIntFlag) {
|
||||||
@ -587,7 +590,7 @@ public:
|
|||||||
use \ref SetBool() instead.
|
use \ref SetBool() instead.
|
||||||
*/
|
*/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
RAPIDJSON_DISABLEIF_RETURN(internal::IsPointer<T>,GenericValue&)
|
RAPIDJSON_DISABLEIF_RETURN((internal::IsPointer<T>), (GenericValue&))
|
||||||
operator=(T value) {
|
operator=(T value) {
|
||||||
GenericValue v(value);
|
GenericValue v(value);
|
||||||
return *this = v;
|
return *this = v;
|
||||||
@ -682,22 +685,27 @@ public:
|
|||||||
//! Equal-to operator with primitive types
|
//! Equal-to operator with primitive types
|
||||||
/*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c double, \c true, \c false
|
/*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c double, \c true, \c false
|
||||||
*/
|
*/
|
||||||
template <typename T> RAPIDJSON_DISABLEIF_RETURN(internal::IsPointer<T>, bool) operator==(const T& rhs) const { return *this == GenericValue(rhs); }
|
template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>,internal::IsBaseOf<GenericValue,T> >), (bool)) operator==(const T& rhs) const { return *this == GenericValue(rhs); }
|
||||||
|
|
||||||
|
//! Not-equal-to operator
|
||||||
|
/*! \return !(*this == rhs)
|
||||||
|
*/
|
||||||
|
bool operator!=(const GenericValue& rhs) const { return !(*this == rhs); }
|
||||||
|
|
||||||
//! Not-equal-to operator with arbitrary types
|
//! Not-equal-to operator with arbitrary types
|
||||||
/*! \return !(*this == rhs)
|
/*! \return !(*this == rhs)
|
||||||
*/
|
*/
|
||||||
template <typename T> bool operator!=(const T& rhs) const { return !(*this == rhs); }
|
template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::IsBaseOf<GenericValue,T>), (bool)) operator!=(const T& rhs) const { return !(*this == rhs); }
|
||||||
|
|
||||||
//! Equal-to operator with arbitrary types (symmetric version)
|
//! Equal-to operator with arbitrary types (symmetric version)
|
||||||
/*! \return (rhs == lhs)
|
/*! \return (rhs == lhs)
|
||||||
*/
|
*/
|
||||||
template <typename T> friend bool operator==(const T& lhs, const GenericValue& rhs) { return rhs == lhs; }
|
template <typename T> friend RAPIDJSON_DISABLEIF_RETURN((internal::IsBaseOf<GenericValue,T>), (bool)) operator==(const T& lhs, const GenericValue& rhs) { return rhs == lhs; }
|
||||||
|
|
||||||
//! Not-Equal-to operator with arbitrary types (symmetric version)
|
//! Not-Equal-to operator with arbitrary types (symmetric version)
|
||||||
/*! \return !(rhs == lhs)
|
/*! \return !(rhs == lhs)
|
||||||
*/
|
*/
|
||||||
template <typename T> friend bool operator!=(const T& lhs, const GenericValue& rhs) { return !(rhs == lhs); }
|
template <typename T> friend RAPIDJSON_DISABLEIF_RETURN((internal::IsBaseOf<GenericValue,T>), (bool)) operator!=(const T& lhs, const GenericValue& rhs) { return !(rhs == lhs); }
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
//!@name Type
|
//!@name Type
|
||||||
@ -934,7 +942,7 @@ public:
|
|||||||
\note Amortized Constant time complexity.
|
\note Amortized Constant time complexity.
|
||||||
*/
|
*/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
RAPIDJSON_DISABLEIF_RETURN(internal::IsPointer<T>,GenericValue&)
|
RAPIDJSON_DISABLEIF_RETURN((internal::IsPointer<T>), (GenericValue&))
|
||||||
AddMember(StringRefType name, T value, Allocator& allocator) {
|
AddMember(StringRefType name, T value, Allocator& allocator) {
|
||||||
GenericValue n(name);
|
GenericValue n(name);
|
||||||
GenericValue v(value);
|
GenericValue v(value);
|
||||||
@ -1158,7 +1166,7 @@ int z = a[0u].GetInt(); // This works too.
|
|||||||
\note Amortized constant time complexity.
|
\note Amortized constant time complexity.
|
||||||
*/
|
*/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
RAPIDJSON_DISABLEIF_RETURN(internal::IsPointer<T>,GenericValue&)
|
RAPIDJSON_DISABLEIF_RETURN((internal::IsPointer<T>), (GenericValue&))
|
||||||
PushBack(T value, Allocator& allocator) {
|
PushBack(T value, Allocator& allocator) {
|
||||||
GenericValue v(value);
|
GenericValue v(value);
|
||||||
return PushBack(v, allocator);
|
return PushBack(v, allocator);
|
||||||
|
@ -25,53 +25,119 @@
|
|||||||
RAPIDJSON_DIAG_PUSH
|
RAPIDJSON_DIAG_PUSH
|
||||||
RAPIDJSON_DIAG_OFF(effc++)
|
RAPIDJSON_DIAG_OFF(effc++)
|
||||||
#endif
|
#endif
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
RAPIDJSON_DIAG_PUSH
|
||||||
|
RAPIDJSON_DIAG_OFF(6334)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef RAPIDJSON_HAS_CXX11_TYPETRAITS
|
||||||
|
#include <type_traits>
|
||||||
|
#endif
|
||||||
|
|
||||||
//@cond RAPIDJSON_INTERNAL
|
//@cond RAPIDJSON_INTERNAL
|
||||||
namespace rapidjson {
|
namespace rapidjson {
|
||||||
namespace internal {
|
namespace internal {
|
||||||
|
|
||||||
template <int N> struct IntegralC { enum { Value = N }; };
|
|
||||||
template <bool Cond> struct BoolType : IntegralC<Cond> {};
|
|
||||||
struct TrueType : BoolType<true> {};
|
|
||||||
struct FalseType : BoolType<false> {};
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// BoolType, TrueType, FalseType
|
||||||
|
//
|
||||||
|
template <bool Cond> struct BoolType {
|
||||||
|
static const bool Value = Cond;
|
||||||
|
typedef BoolType Type;
|
||||||
|
};
|
||||||
|
typedef BoolType<true> TrueType;
|
||||||
|
typedef BoolType<false> FalseType;
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// SelectIf, BoolExpr, NotExpr, AndExpr, OrExpr
|
||||||
|
//
|
||||||
|
|
||||||
|
template <bool C> struct SelectIfImpl { template <typename T1, typename T2> struct Apply { typedef T1 Type; }; };
|
||||||
|
template <> struct SelectIfImpl<false> { template <typename T1, typename T2> struct Apply { typedef T2 Type; }; };
|
||||||
|
template <bool C, typename T1, typename T2> struct SelectIfCond : SelectIfImpl<C>::template Apply<T1,T2> {};
|
||||||
|
template <typename C, typename T1, typename T2> struct SelectIf : SelectIfCond<C::Value, T1, T2> {};
|
||||||
|
|
||||||
|
template <bool Cond1, bool Cond2> struct AndExprCond : FalseType {};
|
||||||
|
template <> struct AndExprCond<true, true> : TrueType {};
|
||||||
|
template <bool Cond1, bool Cond2> struct OrExprCond : TrueType {};
|
||||||
|
template <> struct OrExprCond<false, false> : FalseType {};
|
||||||
|
|
||||||
|
template <typename C> struct BoolExpr : SelectIf<C,TrueType,FalseType>::Type {};
|
||||||
|
template <typename C> struct NotExpr : SelectIf<C,FalseType,TrueType>::Type {};
|
||||||
|
template <typename C1, typename C2> struct AndExpr : AndExprCond<C1::Value, C2::Value>::Type {};
|
||||||
|
template <typename C1, typename C2> struct OrExpr : OrExprCond<C1::Value, C2::Value>::Type {};
|
||||||
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// AddConst, MaybeAddConst, RemoveConst
|
||||||
template <typename T> struct AddConst { typedef const T Type; };
|
template <typename T> struct AddConst { typedef const T Type; };
|
||||||
|
template <bool Constify, typename T> struct MaybeAddConst : SelectIfCond<Constify, const T, T> {};
|
||||||
template <typename T> struct RemoveConst { typedef T Type; };
|
template <typename T> struct RemoveConst { typedef T Type; };
|
||||||
template <typename T> struct RemoveConst<const T> { typedef T Type; };
|
template <typename T> struct RemoveConst<const T> { typedef T Type; };
|
||||||
|
|
||||||
template <bool Condition, typename T1, typename T2> struct SelectIfCond;
|
|
||||||
template <typename T1, typename T2> struct SelectIfCond<true,T1,T2> { typedef T1 Type; };
|
|
||||||
template <typename T1, typename T2> struct SelectIfCond<false,T1,T2> { typedef T2 Type; };
|
|
||||||
|
|
||||||
template <typename Condition, typename T1, typename T2>
|
|
||||||
struct SelectIf : SelectIfCond<Condition::Value,T1,T2> {};
|
|
||||||
|
|
||||||
template <bool Constify, typename T>
|
|
||||||
struct MaybeAddConst : SelectIfCond<Constify, const T, T> {};
|
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
// IsSame, IsConst, IsMoreConst, IsPointer
|
||||||
|
//
|
||||||
template <typename T, typename U> struct IsSame : FalseType {};
|
template <typename T, typename U> struct IsSame : FalseType {};
|
||||||
template <typename T> struct IsSame<T, T> : TrueType {};
|
template <typename T> struct IsSame<T, T> : TrueType {};
|
||||||
|
|
||||||
template <typename T> struct IsConst : FalseType {};
|
template <typename T> struct IsConst : FalseType {};
|
||||||
template <typename T> struct IsConst<const T> : TrueType {};
|
template <typename T> struct IsConst<const T> : TrueType {};
|
||||||
|
|
||||||
|
template <typename CT, typename T>
|
||||||
|
struct IsMoreConst
|
||||||
|
: AndExpr<IsSame<typename RemoveConst<CT>::Type, typename RemoveConst<T>::Type>,
|
||||||
|
BoolType<IsConst<CT>::Value >= IsConst<T>::Value> >::Type {};
|
||||||
|
|
||||||
template <typename T> struct IsPointer : FalseType {};
|
template <typename T> struct IsPointer : FalseType {};
|
||||||
template <typename T> struct IsPointer<T*> : TrueType {};
|
template <typename T> struct IsPointer<T*> : TrueType {};
|
||||||
|
|
||||||
template <typename CT, typename T>
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
struct IsMoreConst {
|
// IsBaseOf
|
||||||
enum { Value =
|
//
|
||||||
( IsSame< typename RemoveConst<CT>::Type, typename RemoveConst<T>::Type>::Value
|
#ifdef RAPIDJSON_HAS_CXX11_TYPETRAITS
|
||||||
&& ( IsConst<CT>::Value >= IsConst<T>::Value ) )
|
|
||||||
};
|
template <typename B, typename D> struct IsBaseOf
|
||||||
|
: BoolType< ::std::is_base_of<B,D>::value> {};
|
||||||
|
|
||||||
|
#else // simplified version adopted from Boost
|
||||||
|
|
||||||
|
template<typename B, typename D> struct IsBaseOfImpl {
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(B) != 0);
|
||||||
|
RAPIDJSON_STATIC_ASSERT(sizeof(D) != 0);
|
||||||
|
|
||||||
|
typedef char (&Yes)[1];
|
||||||
|
typedef char (&No) [2];
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static Yes Check(const D*, T);
|
||||||
|
static No Check(const B*, int);
|
||||||
|
|
||||||
|
struct Host {
|
||||||
|
operator const B*() const;
|
||||||
|
operator const D*();
|
||||||
};
|
};
|
||||||
|
|
||||||
template <bool Condition, typename T = void> struct EnableIfCond;
|
enum { Value = (sizeof(Check(Host(), 0)) == sizeof(Yes)) };
|
||||||
template <typename T> struct EnableIfCond<true, T> { typedef T Type; };
|
};
|
||||||
|
|
||||||
|
template <typename B, typename D> struct IsBaseOf
|
||||||
|
: OrExpr<IsSame<B, D>, BoolExpr<IsBaseOfImpl<B, D> > >::Type {};
|
||||||
|
|
||||||
|
#endif // RAPIDJSON_HAS_CXX11_TYPETRAITS
|
||||||
|
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
// EnableIf / DisableIf
|
||||||
|
//
|
||||||
|
template <bool Condition, typename T = void> struct EnableIfCond { typedef T Type; };
|
||||||
template <typename T> struct EnableIfCond<false, T> { /* empty */ };
|
template <typename T> struct EnableIfCond<false, T> { /* empty */ };
|
||||||
|
|
||||||
template <bool Condition, typename T = void>
|
template <bool Condition, typename T = void> struct DisableIfCond { typedef T Type; };
|
||||||
struct DisableIfCond : EnableIfCond<!Condition, T> {};
|
template <typename T> struct DisableIfCond<true, T> { /* empty */ };
|
||||||
|
|
||||||
template <typename Condition, typename T = void>
|
template <typename Condition, typename T = void>
|
||||||
struct EnableIf : EnableIfCond<Condition::Value, T> {};
|
struct EnableIf : EnableIfCond<Condition::Value, T> {};
|
||||||
@ -80,26 +146,37 @@ template <typename Condition, typename T = void>
|
|||||||
struct DisableIf : DisableIfCond<Condition::Value, T> {};
|
struct DisableIf : DisableIfCond<Condition::Value, T> {};
|
||||||
|
|
||||||
// SFINAE helpers
|
// SFINAE helpers
|
||||||
struct SfinaeResultTag {};
|
struct SfinaeTag {};
|
||||||
template <typename T> struct RemoveSfinaeFptr {};
|
template <typename T> struct RemoveSfinaeTag;
|
||||||
template <typename T> struct RemoveSfinaeFptr<SfinaeResultTag&(*)(T)> { typedef T Type; };
|
template <typename T> struct RemoveSfinaeTag<SfinaeTag&(*)(T)> { typedef T Type; };
|
||||||
|
|
||||||
#define RAPIDJSON_REMOVEFPTR_(type) \
|
#define RAPIDJSON_REMOVEFPTR_(type) \
|
||||||
typename ::rapidjson::internal::RemoveSfinaeFptr \
|
typename ::rapidjson::internal::RemoveSfinaeTag \
|
||||||
< ::rapidjson::internal::SfinaeResultTag&(*) type>::Type
|
< ::rapidjson::internal::SfinaeTag&(*) type>::Type
|
||||||
|
|
||||||
#define RAPIDJSON_ENABLEIF(cond) \
|
#define RAPIDJSON_ENABLEIF(cond) \
|
||||||
typename ::rapidjson::internal::EnableIf \
|
typename ::rapidjson::internal::EnableIf \
|
||||||
<RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL
|
<RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL
|
||||||
|
|
||||||
|
#define RAPIDJSON_DISABLEIF(cond) \
|
||||||
|
typename ::rapidjson::internal::DisableIf \
|
||||||
|
<RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL
|
||||||
|
|
||||||
|
#define RAPIDJSON_ENABLEIF_RETURN(cond,returntype) \
|
||||||
|
typename ::rapidjson::internal::EnableIf \
|
||||||
|
<RAPIDJSON_REMOVEFPTR_(cond), \
|
||||||
|
RAPIDJSON_REMOVEFPTR_(returntype)>::Type
|
||||||
|
|
||||||
#define RAPIDJSON_DISABLEIF_RETURN(cond,returntype) \
|
#define RAPIDJSON_DISABLEIF_RETURN(cond,returntype) \
|
||||||
typename ::rapidjson::internal::DisableIf<cond,returntype>::Type
|
typename ::rapidjson::internal::DisableIf \
|
||||||
|
<RAPIDJSON_REMOVEFPTR_(cond), \
|
||||||
|
RAPIDJSON_REMOVEFPTR_(returntype)>::Type
|
||||||
|
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
} // namespace rapidjson
|
} // namespace rapidjson
|
||||||
//@endcond
|
//@endcond
|
||||||
|
|
||||||
#ifdef __GNUC__
|
#if defined(__GNUC__) || defined(_MSC_VER)
|
||||||
RAPIDJSON_DIAG_POP
|
RAPIDJSON_DIAG_POP
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -106,15 +106,35 @@ TEST(Value, equalto_operator) {
|
|||||||
TestEqual(x["pi"], 3.14);
|
TestEqual(x["pi"], 3.14);
|
||||||
|
|
||||||
// Test operator==()
|
// Test operator==()
|
||||||
|
#ifdef RAPIDJSON_COMPARE_DIFFERENT_ALLOCATORS
|
||||||
|
CrtAllocator crtAllocator;
|
||||||
|
GenericValue<UTF8<>, CrtAllocator> y;
|
||||||
|
GenericDocument<UTF8<>, CrtAllocator> z(&crtAllocator);
|
||||||
|
CrtAllocator& yAllocator = crtAllocator;
|
||||||
|
#else
|
||||||
|
Value::AllocatorType& yAllocator = allocator;
|
||||||
Value y;
|
Value y;
|
||||||
y.CopyFrom(x, allocator);
|
Document z;
|
||||||
|
#endif // RAPIDJSON_COMPARE_DIFFERENT_ALLOCATORS
|
||||||
|
y.CopyFrom(x, yAllocator);
|
||||||
|
z.CopyFrom(y, z.GetAllocator());
|
||||||
|
|
||||||
TestEqual(x, y);
|
TestEqual(x, y);
|
||||||
|
TestEqual(y, z);
|
||||||
|
TestEqual(z, x);
|
||||||
|
|
||||||
// Swapping member order should be fine.
|
// Swapping member order should be fine.
|
||||||
y.RemoveMember("t");
|
EXPECT_TRUE(y.RemoveMember("t"));
|
||||||
TestUnequal(x, y);
|
TestUnequal(x, y);
|
||||||
y.AddMember("t", Value(true).Move(), allocator);
|
TestUnequal(z, y);
|
||||||
|
EXPECT_TRUE(z.RemoveMember("t"));
|
||||||
|
TestUnequal(x, z);
|
||||||
|
TestEqual(y, z);
|
||||||
|
y.AddMember("t", true, yAllocator);
|
||||||
|
z.AddMember("t", true, z.GetAllocator());
|
||||||
TestEqual(x, y);
|
TestEqual(x, y);
|
||||||
|
TestEqual(y, z);
|
||||||
|
TestEqual(z, x);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Value>
|
template <typename Value>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user