Imported Upstream version 1.1.0
[platform/upstream/iotivity.git] / service / resource-encapsulation / src / common / primitiveResource / include / AssertUtils.h
1 //******************************************************************
2 //
3 // Copyright 2015 Samsung Electronics All Rights Reserved.
4 //
5 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
6 //
7 // Licensed under the Apache License, Version 2.0 (the "License");
8 // you may not use this file except in compliance with the License.
9 // You may obtain a copy of the License at
10 //
11 //      http://www.apache.org/licenses/LICENSE-2.0
12 //
13 // Unless required by applicable law or agreed to in writing, software
14 // distributed under the License is distributed on an "AS IS" BASIS,
15 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 // See the License for the specific language governing permissions and
17 // limitations under the License.
18 //
19 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
20
21 #ifndef COMMON_INTERNAL_ASSERTUTILS_H
22 #define COMMON_INTERNAL_ASSERTUTILS_H
23
24 #include <cstdint>
25 #include <cstdlib>
26
27 #include <memory>
28
29 #include "octypes.h"
30 #include "OCException.h"
31
32 #include "RCSException.h"
33
34 namespace OIC
35 {
36     namespace Service
37     {
38         namespace Detail
39         {
40
41             // This is a helper class to avoid calling the base layer during terminating the process.
42             // The reason why you should not call the base layer in this situation is that
43             // OC apis are singletons or internally implemented as singleton.
44             // Singleton implemented with a static variable is initialized
45             // in the first call to the function.
46             // It means you can not guarantee the order of initialization of the singletons,
47             // which is the reverse order of destruction.
48             // Some of RE classes are also implemented as singletons.
49             // Now we have a problem if RE tries to call one of OC apis
50             // after OC classes are destroyed first.
51             // To solve this issue, it registers exit handler to catch the termination event.
52             // Keep this information with a bool flag dynamically allocated to
53             // make sure it is not destroyed during the destruction of the static objects.
54             class TerminationChecker
55             {
56             private:
57                 static bool& getExited()
58                 {
59                     static bool* flag = new bool{ false };
60                     return *flag;
61                 }
62
63                 static void atExitHandler()
64                 {
65                     getExited() = true;
66                 }
67
68                 TerminationChecker()
69                 {
70                     std::atexit(atExitHandler);
71                 }
72
73             public:
74                 static bool isInTermination()
75                 {
76                     static TerminationChecker once;
77                     return getExited();
78                 }
79             };
80
81             struct NotOCStackResult;
82
83             template <typename FUNC, typename ...PARAMS>
84             struct ResultType
85             {
86                 typedef decltype(std::declval<FUNC>()(std::declval<PARAMS>()...)) type;
87             };
88
89             template< typename A, typename B, typename ENABLER = void >
90             struct EnableIfTypeIs;
91
92             template< typename A >
93             struct EnableIfTypeIs< A, OCStackResult,
94                     typename std::enable_if< std::is_same< A, OCStackResult >::value >::type >
95             {
96                 typedef void type;
97             };
98
99             template< typename A >
100             struct EnableIfTypeIs< A, NotOCStackResult,
101                     typename std::enable_if< !std::is_same< A, OCStackResult >::value >::type >
102             {
103                 typedef A type;
104             };
105
106             template< typename T, typename = typename std::enable_if<
107                     std::is_class<T>::value && std::is_pointer<T>::value>::type >
108             struct EnableIfClassPointer
109             {
110                 typedef void type;
111             };
112
113             template< typename T, typename = typename std::enable_if< std::is_class< T >::value > >
114             struct EnableIfClass
115             {
116                 typedef void type;
117             };
118         }
119
120         inline void expectOCStackResult(OCStackResult actual,
121                 std::initializer_list<OCStackResult> allowed)
122         {
123             for (auto r : allowed)
124             {
125                 if (actual == r) return;
126             }
127
128             throw RCSPlatformException(actual);
129         }
130
131         inline void expectOCStackResult(OCStackResult actual, OCStackResult expected)
132         {
133             if (actual != expected)
134             {
135                 throw RCSPlatformException(actual);
136             }
137         }
138
139         inline void expectOCStackResultOK(OCStackResult actual)
140         {
141             expectOCStackResult(actual, OC_STACK_OK);
142         }
143
144         template< typename FUNC, typename ...PARAMS >
145         typename Detail::EnableIfTypeIs< typename Detail::ResultType< FUNC, PARAMS... >::type,
146                 OCStackResult >::type
147         invokeOCFuncWithResultExpect(std::initializer_list<OCStackResult> allowed,
148                 FUNC&& fn, PARAMS&& ...params)
149         {
150             if (Detail::TerminationChecker::isInTermination()) return;
151
152             try
153             {
154                 expectOCStackResult(fn(std::forward< PARAMS >(params)...), std::move(allowed));
155             }
156             catch (const OC::OCException& e)
157             {
158                 throw RCSPlatformException(e.code());
159             }
160         }
161
162
163         template< typename FUNC, typename ...PARAMS >
164         typename Detail::EnableIfTypeIs< typename Detail::ResultType< FUNC, PARAMS... >::type,
165                 OCStackResult >::type
166         invokeOCFunc(FUNC&& fn, PARAMS&& ...params)
167         {
168             if (Detail::TerminationChecker::isInTermination()) return;
169
170             try
171             {
172                 expectOCStackResultOK(fn(std::forward< PARAMS >(params)...));
173             }
174             catch (const OC::OCException& e)
175             {
176                 throw RCSPlatformException(e.code());
177             }
178         }
179
180         template< typename FUNC, typename ...PARAMS >
181         typename Detail::EnableIfTypeIs< typename Detail::ResultType< FUNC, PARAMS... >::type,
182                         Detail::NotOCStackResult >::type
183         invokeOCFunc(FUNC* fn, PARAMS&& ...params)
184         {
185             if (Detail::TerminationChecker::isInTermination()) return;
186
187             try
188             {
189                 return fn(std::forward< PARAMS >(params)...);
190             }
191             catch (const OC::OCException& e)
192             {
193                 throw RCSPlatformException(e.code());
194             }
195         }
196
197         template< typename OBJ, typename = typename Detail::EnableIfClassPointer<OBJ>::type,
198                 typename FUNC, typename ...PARAMS >
199         inline auto invokeOC(OBJ&& obj, FUNC&& fn, PARAMS&& ...params) ->
200             typename Detail::EnableIfTypeIs<
201                 decltype((obj->*fn)(std::forward< PARAMS >(params)...)), OCStackResult>::
202                 type
203         {
204             if (Detail::TerminationChecker::isInTermination()) return;
205
206             try
207             {
208                 expectOCStackResultOK(obj->*fn(std::forward< PARAMS >(params)...));
209             }
210             catch (const OC::OCException& e)
211             {
212                 throw RCSPlatformException(e.code());
213             }
214         }
215
216         template< typename OBJ, typename = typename Detail::EnableIfClassPointer<OBJ>::type,
217                 typename FUNC, typename ...PARAMS >
218         inline auto invokeOC(OBJ&& obj, FUNC&& fn, PARAMS&& ...params) ->
219                 typename Detail::EnableIfTypeIs<
220                     decltype((obj->*fn)(std::forward< PARAMS >(params)...)),
221                     Detail::NotOCStackResult>::
222                     type
223         {
224             if (Detail::TerminationChecker::isInTermination()) return;
225
226             try
227             {
228                 obj->*fn(std::forward< PARAMS >(params)...);
229             }
230             catch (const OC::OCException& e)
231             {
232                 throw RCSPlatformException(e.code());
233             }
234         }
235
236         template< typename OBJ, typename = typename Detail::EnableIfClass<OBJ>::type,
237                 typename FUNC, typename ...PARAMS >
238         inline auto invokeOC(const std::shared_ptr< OBJ >& obj, FUNC&& fn, PARAMS&& ...params) ->
239                 typename Detail::EnableIfTypeIs<
240                     decltype((obj.get()->*fn)(std::forward< PARAMS >(params)...)), OCStackResult>::
241                     type
242         {
243             if (Detail::TerminationChecker::isInTermination()) return;
244
245             try
246             {
247                 expectOCStackResultOK((obj.get()->*fn)(std::forward< PARAMS >(params)...));
248             }
249             catch (const OC::OCException& e)
250             {
251                 throw RCSPlatformException(e.code());
252             }
253         }
254
255         template< typename OBJ, typename = typename Detail::EnableIfClass< OBJ >::type,
256                 typename FUNC, typename ...PARAMS >
257         inline auto invokeOC(const std::shared_ptr<OBJ>& obj, FUNC&& fn, PARAMS&& ...params) ->
258             typename Detail::EnableIfTypeIs<
259                    decltype((obj.get()->*fn)(std::forward< PARAMS >(params)...)),
260                    Detail::NotOCStackResult>::
261                    type
262         {
263             if (Detail::TerminationChecker::isInTermination()) return { };
264
265             try
266             {
267                 return (obj.get()->*fn)(std::forward< PARAMS >(params)...);
268             }
269             catch (const OC::OCException& e)
270             {
271                 throw RCSPlatformException(e.code());
272             }
273         }
274
275     }
276 }
277
278 #endif // COMMON_INTERNAL_ASSERTUTILS_H