diff --git a/build/Doxyfile b/build/Doxyfile index 65de7e9..6827b51 100644 --- a/build/Doxyfile +++ b/build/Doxyfile @@ -1993,7 +1993,9 @@ INCLUDE_FILE_PATTERNS = PREDEFINED = \ 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 # tag can be used to specify a list of macro names that should be expanded. The diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h index f5244e8..92c7316 100644 --- a/include/rapidjson/document.h +++ b/include/rapidjson/document.h @@ -458,7 +458,10 @@ public: #else explicit GenericValue(bool b) #endif - : data_(), flags_(b ? kTrueFlag : kFalseFlag) {} + : data_(), flags_(b ? kTrueFlag : kFalseFlag) { + // safe-guard against failing SFINAE + RAPIDJSON_STATIC_ASSERT((internal::IsSame::Value)); + } //! Constructor for int value. explicit GenericValue(int i) : data_(), flags_(kNumberIntFlag) { @@ -587,7 +590,7 @@ public: use \ref SetBool() instead. */ template - RAPIDJSON_DISABLEIF_RETURN(internal::IsPointer,GenericValue&) + RAPIDJSON_DISABLEIF_RETURN((internal::IsPointer), (GenericValue&)) operator=(T value) { GenericValue v(value); return *this = v; @@ -682,22 +685,27 @@ public: //! 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 */ - template RAPIDJSON_DISABLEIF_RETURN(internal::IsPointer, bool) operator==(const T& rhs) const { return *this == GenericValue(rhs); } + template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr,internal::IsBaseOf >), (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 /*! \return !(*this == rhs) */ - template bool operator!=(const T& rhs) const { return !(*this == rhs); } + template RAPIDJSON_DISABLEIF_RETURN((internal::IsBaseOf), (bool)) operator!=(const T& rhs) const { return !(*this == rhs); } //! Equal-to operator with arbitrary types (symmetric version) /*! \return (rhs == lhs) */ - template friend bool operator==(const T& lhs, const GenericValue& rhs) { return rhs == lhs; } + template friend RAPIDJSON_DISABLEIF_RETURN((internal::IsBaseOf), (bool)) operator==(const T& lhs, const GenericValue& rhs) { return rhs == lhs; } //! Not-Equal-to operator with arbitrary types (symmetric version) /*! \return !(rhs == lhs) */ - template friend bool operator!=(const T& lhs, const GenericValue& rhs) { return !(rhs == lhs); } + template friend RAPIDJSON_DISABLEIF_RETURN((internal::IsBaseOf), (bool)) operator!=(const T& lhs, const GenericValue& rhs) { return !(rhs == lhs); } //@} //!@name Type @@ -934,7 +942,7 @@ public: \note Amortized Constant time complexity. */ template - RAPIDJSON_DISABLEIF_RETURN(internal::IsPointer,GenericValue&) + RAPIDJSON_DISABLEIF_RETURN((internal::IsPointer), (GenericValue&)) AddMember(StringRefType name, T value, Allocator& allocator) { GenericValue n(name); GenericValue v(value); @@ -1158,7 +1166,7 @@ int z = a[0u].GetInt(); // This works too. \note Amortized constant time complexity. */ template - RAPIDJSON_DISABLEIF_RETURN(internal::IsPointer,GenericValue&) + RAPIDJSON_DISABLEIF_RETURN((internal::IsPointer), (GenericValue&)) PushBack(T value, Allocator& allocator) { GenericValue v(value); return PushBack(v, allocator); diff --git a/include/rapidjson/internal/meta.h b/include/rapidjson/internal/meta.h index b19a9f4..bcff1a5 100644 --- a/include/rapidjson/internal/meta.h +++ b/include/rapidjson/internal/meta.h @@ -25,53 +25,119 @@ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(effc++) #endif +#if defined(_MSC_VER) +RAPIDJSON_DIAG_PUSH +RAPIDJSON_DIAG_OFF(6334) +#endif + +#ifdef RAPIDJSON_HAS_CXX11_TYPETRAITS +#include +#endif //@cond RAPIDJSON_INTERNAL namespace rapidjson { namespace internal { -template struct IntegralC { enum { Value = N }; }; -template struct BoolType : IntegralC {}; -struct TrueType : BoolType {}; -struct FalseType : BoolType {}; +/////////////////////////////////////////////////////////////////////////////// +// BoolType, TrueType, FalseType +// +template struct BoolType { + static const bool Value = Cond; + typedef BoolType Type; +}; +typedef BoolType TrueType; +typedef BoolType FalseType; + + +/////////////////////////////////////////////////////////////////////////////// +// SelectIf, BoolExpr, NotExpr, AndExpr, OrExpr +// + +template struct SelectIfImpl { template struct Apply { typedef T1 Type; }; }; +template <> struct SelectIfImpl { template struct Apply { typedef T2 Type; }; }; +template struct SelectIfCond : SelectIfImpl::template Apply {}; +template struct SelectIf : SelectIfCond {}; + +template struct AndExprCond : FalseType {}; +template <> struct AndExprCond : TrueType {}; +template struct OrExprCond : TrueType {}; +template <> struct OrExprCond : FalseType {}; + +template struct BoolExpr : SelectIf::Type {}; +template struct NotExpr : SelectIf::Type {}; +template struct AndExpr : AndExprCond::Type {}; +template struct OrExpr : OrExprCond::Type {}; + + +/////////////////////////////////////////////////////////////////////////////// +// AddConst, MaybeAddConst, RemoveConst template struct AddConst { typedef const T Type; }; +template struct MaybeAddConst : SelectIfCond {}; template struct RemoveConst { typedef T Type; }; template struct RemoveConst { typedef T Type; }; -template struct SelectIfCond; -template struct SelectIfCond { typedef T1 Type; }; -template struct SelectIfCond { typedef T2 Type; }; -template -struct SelectIf : SelectIfCond {}; - -template -struct MaybeAddConst : SelectIfCond {}; - -template struct IsSame : FalseType {}; -template struct IsSame : TrueType {}; +/////////////////////////////////////////////////////////////////////////////// +// IsSame, IsConst, IsMoreConst, IsPointer +// +template struct IsSame : FalseType {}; +template struct IsSame : TrueType {}; template struct IsConst : FalseType {}; template struct IsConst : TrueType {}; +template +struct IsMoreConst + : AndExpr::Type, typename RemoveConst::Type>, + BoolType::Value >= IsConst::Value> >::Type {}; + template struct IsPointer : FalseType {}; template struct IsPointer : TrueType {}; -template -struct IsMoreConst { - enum { Value = - ( IsSame< typename RemoveConst::Type, typename RemoveConst::Type>::Value - && ( IsConst::Value >= IsConst::Value ) ) +/////////////////////////////////////////////////////////////////////////////// +// IsBaseOf +// +#ifdef RAPIDJSON_HAS_CXX11_TYPETRAITS + +template struct IsBaseOf + : BoolType< ::std::is_base_of::value> {}; + +#else // simplified version adopted from Boost + +template struct IsBaseOfImpl { + RAPIDJSON_STATIC_ASSERT(sizeof(B) != 0); + RAPIDJSON_STATIC_ASSERT(sizeof(D) != 0); + + typedef char (&Yes)[1]; + typedef char (&No) [2]; + + template + 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 struct EnableIfCond; -template struct EnableIfCond { typedef T Type; }; +template struct IsBaseOf + : OrExpr, BoolExpr > >::Type {}; + +#endif // RAPIDJSON_HAS_CXX11_TYPETRAITS + + +////////////////////////////////////////////////////////////////////////// +// EnableIf / DisableIf +// +template struct EnableIfCond { typedef T Type; }; template struct EnableIfCond { /* empty */ }; -template -struct DisableIfCond : EnableIfCond {}; +template struct DisableIfCond { typedef T Type; }; +template struct DisableIfCond { /* empty */ }; template struct EnableIf : EnableIfCond {}; @@ -80,26 +146,37 @@ template struct DisableIf : DisableIfCond {}; // SFINAE helpers -struct SfinaeResultTag {}; -template struct RemoveSfinaeFptr {}; -template struct RemoveSfinaeFptr { typedef T Type; }; +struct SfinaeTag {}; +template struct RemoveSfinaeTag; +template struct RemoveSfinaeTag { typedef T Type; }; #define RAPIDJSON_REMOVEFPTR_(type) \ - typename ::rapidjson::internal::RemoveSfinaeFptr \ - < ::rapidjson::internal::SfinaeResultTag&(*) type>::Type + typename ::rapidjson::internal::RemoveSfinaeTag \ + < ::rapidjson::internal::SfinaeTag&(*) type>::Type #define RAPIDJSON_ENABLEIF(cond) \ typename ::rapidjson::internal::EnableIf \ ::Type * = NULL +#define RAPIDJSON_DISABLEIF(cond) \ + typename ::rapidjson::internal::DisableIf \ + ::Type * = NULL + +#define RAPIDJSON_ENABLEIF_RETURN(cond,returntype) \ + typename ::rapidjson::internal::EnableIf \ + ::Type + #define RAPIDJSON_DISABLEIF_RETURN(cond,returntype) \ - typename ::rapidjson::internal::DisableIf::Type + typename ::rapidjson::internal::DisableIf \ + ::Type } // namespace internal } // namespace rapidjson //@endcond -#ifdef __GNUC__ +#if defined(__GNUC__) || defined(_MSC_VER) RAPIDJSON_DIAG_POP #endif diff --git a/test/unittest/valuetest.cpp b/test/unittest/valuetest.cpp index a234e1f..9324813 100644 --- a/test/unittest/valuetest.cpp +++ b/test/unittest/valuetest.cpp @@ -106,15 +106,35 @@ TEST(Value, equalto_operator) { TestEqual(x["pi"], 3.14); // Test operator==() +#ifdef RAPIDJSON_COMPARE_DIFFERENT_ALLOCATORS + CrtAllocator crtAllocator; + GenericValue, CrtAllocator> y; + GenericDocument, CrtAllocator> z(&crtAllocator); + CrtAllocator& yAllocator = crtAllocator; +#else + Value::AllocatorType& yAllocator = allocator; 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(y, z); + TestEqual(z, x); // Swapping member order should be fine. - y.RemoveMember("t"); + EXPECT_TRUE(y.RemoveMember("t")); 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(y, z); + TestEqual(z, x); } template