1 // Tencent is pleased to support the open source community by making RapidJSON available.
2 //
3 // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
4 //
5 // Licensed under the MIT License (the "License"); you may not use this file except
6 // in compliance with the License. You may obtain a copy of the License at
7 //
8 // http://opensource.org/licenses/MIT
9 //
10 // Unless required by applicable law or agreed to in writing, software distributed
11 // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
12 // CONDITIONS OF ANY KIND, either express or implied. See the License for the
13 // specific language governing permissions and limitations under the License.
14 
15 #ifndef RAPIDJSON_INTERNAL_META_H_
16 #define RAPIDJSON_INTERNAL_META_H_
17 
18 #include "../rapidjson.h"
19 
20 #ifdef __GNUC__
21 RAPIDJSON_DIAG_PUSH
22 RAPIDJSON_DIAG_OFF(effc++)
23 #endif
24 #if defined(_MSC_VER)
25 RAPIDJSON_DIAG_PUSH
26 RAPIDJSON_DIAG_OFF(6334)
27 #endif
28 
29 #if RAPIDJSON_HAS_CXX11_TYPETRAITS
30 #include <type_traits>
31 #endif
32 
33 //@cond RAPIDJSON_INTERNAL
34 RAPIDJSON_NAMESPACE_BEGIN
35 namespace internal {
36 
37 // Helper to wrap/convert arbitrary types to void, useful for arbitrary type matching
38 template <typename T> struct Void { typedef void Type; };
39 
40 ///////////////////////////////////////////////////////////////////////////////
41 // BoolType, TrueType, FalseType
42 //
43 template <bool Cond> struct BoolType {
44     static const bool Value = Cond;
45     typedef BoolType Type;
46 };
47 typedef BoolType<true> TrueType;
48 typedef BoolType<false> FalseType;
49 
50 
51 ///////////////////////////////////////////////////////////////////////////////
52 // SelectIf, BoolExpr, NotExpr, AndExpr, OrExpr
53 //
54 
55 template <bool C> struct SelectIfImpl { template <typename T1, typename T2> struct Apply { typedef T1 Type; }; };
56 template <> struct SelectIfImpl<false> { template <typename T1, typename T2> struct Apply { typedef T2 Type; }; };
57 template <bool C, typename T1, typename T2> struct SelectIfCond : SelectIfImpl<C>::template Apply<T1,T2> {};
58 template <typename C, typename T1, typename T2> struct SelectIf : SelectIfCond<C::Value, T1, T2> {};
59 
60 template <bool Cond1, bool Cond2> struct AndExprCond : FalseType {};
61 template <> struct AndExprCond<true, true> : TrueType {};
62 template <bool Cond1, bool Cond2> struct OrExprCond : TrueType {};
63 template <> struct OrExprCond<false, false> : FalseType {};
64 
65 template <typename C> struct BoolExpr : SelectIf<C,TrueType,FalseType>::Type {};
66 template <typename C> struct NotExpr  : SelectIf<C,FalseType,TrueType>::Type {};
67 template <typename C1, typename C2> struct AndExpr : AndExprCond<C1::Value, C2::Value>::Type {};
68 template <typename C1, typename C2> struct OrExpr  : OrExprCond<C1::Value, C2::Value>::Type {};
69 
70 
71 ///////////////////////////////////////////////////////////////////////////////
72 // AddConst, MaybeAddConst, RemoveConst
73 template <typename T> struct AddConst { typedef const T Type; };
74 template <bool Constify, typename T> struct MaybeAddConst : SelectIfCond<Constify, const T, T> {};
75 template <typename T> struct RemoveConst { typedef T Type; };
76 template <typename T> struct RemoveConst<const T> { typedef T Type; };
77 
78 
79 ///////////////////////////////////////////////////////////////////////////////
80 // IsSame, IsConst, IsMoreConst, IsPointer
81 //
82 template <typename T, typename U> struct IsSame : FalseType {};
83 template <typename T> struct IsSame<T, T> : TrueType {};
84 
85 template <typename T> struct IsConst : FalseType {};
86 template <typename T> struct IsConst<const T> : TrueType {};
87 
88 template <typename CT, typename T>
89 struct IsMoreConst
90     : AndExpr<IsSame<typename RemoveConst<CT>::Type, typename RemoveConst<T>::Type>,
91               BoolType<IsConst<CT>::Value >= IsConst<T>::Value> >::Type {};
92 
93 template <typename T> struct IsPointer : FalseType {};
94 template <typename T> struct IsPointer<T*> : TrueType {};
95 
96 ///////////////////////////////////////////////////////////////////////////////
97 // IsBaseOf
98 //
99 #if RAPIDJSON_HAS_CXX11_TYPETRAITS
100 
101 template <typename B, typename D> struct IsBaseOf
102     : BoolType< ::std::is_base_of<B,D>::value> {};
103 
104 #else // simplified version adopted from Boost
105 
106 template<typename B, typename D> struct IsBaseOfImpl {
107     RAPIDJSON_STATIC_ASSERT(sizeof(B) != 0);
108     RAPIDJSON_STATIC_ASSERT(sizeof(D) != 0);
109 
110     typedef char (&Yes)[1];
111     typedef char (&No) [2];
112 
113     template <typename T>
114     static Yes Check(const D*, T);
115     static No  Check(const B*, int);
116 
117     struct Host {
118         operator const B*() const;
119         operator const D*();
120     };
121 
122     enum { Value = (sizeof(Check(Host(), 0)) == sizeof(Yes)) };
123 };
124 
125 template <typename B, typename D> struct IsBaseOf
126     : OrExpr<IsSame<B, D>, BoolExpr<IsBaseOfImpl<B, D> > >::Type {};
127 
128 #endif // RAPIDJSON_HAS_CXX11_TYPETRAITS
129 
130 
131 //////////////////////////////////////////////////////////////////////////
132 // EnableIf / DisableIf
133 //
134 template <bool Condition, typename T = void> struct EnableIfCond  { typedef T Type; };
135 template <typename T> struct EnableIfCond<false, T> { /* empty */ };
136 
137 template <bool Condition, typename T = void> struct DisableIfCond { typedef T Type; };
138 template <typename T> struct DisableIfCond<true, T> { /* empty */ };
139 
140 template <typename Condition, typename T = void>
141 struct EnableIf : EnableIfCond<Condition::Value, T> {};
142 
143 template <typename Condition, typename T = void>
144 struct DisableIf : DisableIfCond<Condition::Value, T> {};
145 
146 // SFINAE helpers
147 struct SfinaeTag {};
148 template <typename T> struct RemoveSfinaeTag;
149 template <typename T> struct RemoveSfinaeTag<SfinaeTag&(*)(T)> { typedef T Type; };
150 
151 // NOLINT: Do not add parentheses around 'type'.
152 #define RAPIDJSON_REMOVEFPTR_(type) \
153     typename ::RAPIDJSON_NAMESPACE::internal::RemoveSfinaeTag \
154         < ::RAPIDJSON_NAMESPACE::internal::SfinaeTag&(*) type>::Type  // NOLINT
155 
156 // NOLINT: Do not add parentheses around a statement.
157 #define RAPIDJSON_ENABLEIF(cond) \
158     typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \
159         <RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL  // NOLINT
160 
161 // NOLINT: Do not add parentheses around a statement.
162 #define RAPIDJSON_DISABLEIF(cond) \
163     typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \
164         <RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL  // NOLINT
165 
166 #define RAPIDJSON_ENABLEIF_RETURN(cond,returntype) \
167     typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \
168         <RAPIDJSON_REMOVEFPTR_(cond), \
169          RAPIDJSON_REMOVEFPTR_(returntype)>::Type
170 
171 #define RAPIDJSON_DISABLEIF_RETURN(cond,returntype) \
172     typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \
173         <RAPIDJSON_REMOVEFPTR_(cond), \
174          RAPIDJSON_REMOVEFPTR_(returntype)>::Type
175 
176 } // namespace internal
177 RAPIDJSON_NAMESPACE_END
178 //@endcond
179 
180 #if defined(__GNUC__) || defined(_MSC_VER)
181 RAPIDJSON_DIAG_POP
182 #endif
183 
184 #endif // RAPIDJSON_INTERNAL_META_H_
185