Commit ab8416e1 authored by Milo Yip's avatar Milo Yip

Merge pull request #125 from pah/fixes/113

Fix comparison operator ambiguities between Value/Document
parents 1fafc38e 804b7fcb
...@@ -1993,7 +1993,9 @@ INCLUDE_FILE_PATTERNS = ...@@ -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: ...@@ -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: ...@@ -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: ...@@ -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: ...@@ -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. ...@@ -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 @@ ...@@ -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*();
}; };
enum { Value = (sizeof(Check(Host(), 0)) == sizeof(Yes)) };
}; };
template <bool Condition, typename T = void> struct EnableIfCond; template <typename B, typename D> struct IsBaseOf
template <typename T> struct EnableIfCond<true, T> { typedef T Type; }; : 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> ...@@ -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) { ...@@ -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>
......
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