1 /*
2  * Copyright (C) 2017 Open Source Robotics Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17 
18 
19 #ifndef IGNITION_COMMON_DETAIL_SPECIALIZEDPLUGIN_HH_
20 #define IGNITION_COMMON_DETAIL_SPECIALIZEDPLUGIN_HH_
21 
22 #include "ignition/common/SpecializedPlugin.hh"
23 #include <memory>
24 
25 // This preprocessor token should only be used by the unittest that is
26 // responsible for checking that the specialized routines are being used to
27 // access specialized plugin interfaces.
28 #ifdef IGNITION_UNITTEST_SPECIALIZED_PLUGIN_ACCESS
29 bool usedSpecializedInterfaceAccess;
30 #endif
31 
32 
33 namespace ignition
34 {
35   namespace common
36   {
37     /////////////////////////////////////////////////
38     template <class SpecInterface>
39     // the following is a false positive with cppcheck 1.82 fixed in 1.83
40     // cppcheck-suppress syntaxError
41     template <class Interface>
QueryInterface()42     Interface *SpecializedPlugin<SpecInterface>::QueryInterface()
43     {
44       return this->PrivateQueryInterface(type<Interface>());
45     }
46 
47     /////////////////////////////////////////////////
48     template <class SpecInterface>
49     template <class Interface>
QueryInterface() const50     const Interface *SpecializedPlugin<SpecInterface>::QueryInterface() const
51     {
52       return this->PrivateQueryInterface(type<Interface>());
53     }
54 
55     /////////////////////////////////////////////////
56     template <class SpecInterface>
57     template <class Interface>
58     std::shared_ptr<Interface>
QueryInterfaceSharedPtr()59     SpecializedPlugin<SpecInterface>::QueryInterfaceSharedPtr()
60     {
61       Interface *ptr = this->QueryInterface<Interface>();
62       if (ptr)
63         return std::shared_ptr<Interface>(this->PrivateGetInstancePtr(), ptr);
64 
65       return nullptr;
66     }
67 
68     /////////////////////////////////////////////////
69     template <class SpecInterface>
70     template <class Interface>
71     std::shared_ptr<const Interface>
QueryInterfaceSharedPtr() const72     SpecializedPlugin<SpecInterface>::QueryInterfaceSharedPtr() const
73     {
74       const Interface *ptr = this->QueryInterface<Interface>();
75       if (ptr)
76         return std::shared_ptr<Interface>(this->PrivateGetInstancePtr(), ptr);
77 
78       return nullptr;
79     }
80 
81     /////////////////////////////////////////////////
82     template <class SpecInterface>
83     template <class Interface>
HasInterface() const84     bool SpecializedPlugin<SpecInterface>::HasInterface() const
85     {
86       return this->PrivateHasInterface(type<Interface>());
87     }
88 
89     /////////////////////////////////////////////////
90     template <class SpecInterface>
91     template <class Interface>
PrivateQueryInterface(type<Interface>)92     Interface *SpecializedPlugin<SpecInterface>::PrivateQueryInterface(
93         type<Interface>)
94     {
95       return this->Plugin::QueryInterface<Interface>();
96     }
97 
98     /////////////////////////////////////////////////
99     template <class SpecInterface>
PrivateQueryInterface(type<SpecInterface>)100     SpecInterface *SpecializedPlugin<SpecInterface>::PrivateQueryInterface(
101         type<SpecInterface>)
102     {
103       #ifdef IGNITION_UNITTEST_SPECIALIZED_PLUGIN_ACCESS
104       usedSpecializedInterfaceAccess = true;
105       #endif
106       return static_cast<SpecInterface*>(
107             this->privateSpecializedInterfaceIterator->second);
108     }
109 
110     /////////////////////////////////////////////////
111     template <class SpecInterface>
112     template <class Interface>
113     const Interface *SpecializedPlugin<SpecInterface>::
PrivateQueryInterface(type<Interface>) const114     PrivateQueryInterface(type<Interface>) const
115     {
116       return this->Plugin::QueryInterface<Interface>();
117     }
118 
119     /////////////////////////////////////////////////
120     template <class SpecInterface>
121     const SpecInterface *SpecializedPlugin<SpecInterface>::
PrivateQueryInterface(type<SpecInterface>) const122     PrivateQueryInterface(type<SpecInterface>) const
123     {
124       #ifdef IGNITION_UNITTEST_SPECIALIZED_PLUGIN_ACCESS
125       usedSpecializedInterfaceAccess = true;
126       #endif
127       return static_cast<SpecInterface*>(
128             this->privateSpecializedInterfaceIterator->second);
129     }
130 
131     /////////////////////////////////////////////////
132     template <class SpecInterface>
133     template <class Interface>
PrivateHasInterface(type<Interface>) const134     bool SpecializedPlugin<SpecInterface>::PrivateHasInterface(
135         type<Interface>) const
136     {
137       return this->Plugin::HasInterface<Interface>();
138     }
139 
140     /////////////////////////////////////////////////
141     template <class SpecInterface>
PrivateHasInterface(type<SpecInterface>) const142     bool SpecializedPlugin<SpecInterface>::PrivateHasInterface(
143         type<SpecInterface>) const
144     {
145       #ifdef IGNITION_UNITTEST_SPECIALIZED_PLUGIN_ACCESS
146       usedSpecializedInterfaceAccess = true;
147       #endif
148       return (nullptr != this->privateSpecializedInterfaceIterator->second);
149     }
150 
151     /////////////////////////////////////////////////
152     template <class SpecInterface>
SpecializedPlugin()153     SpecializedPlugin<SpecInterface>::SpecializedPlugin()
154       : privateSpecializedInterfaceIterator(
155           this->PrivateGetOrCreateIterator(
156             SpecInterface::IGNCOMMONInterfaceName))
157     {
158       // Do nothing
159     }
160 
161     namespace detail
162     {
163       /// \brief This template provides an implementation of
164       /// SelectSpecializerIfAvailable by having two template specializations
165       /// to choose between at compile time.
166       ///
167       /// If specialized is true, then this will provide the specializer for
168       /// Interface as `Specializer`.
169       template <typename Interface, bool specialized>
170       struct SelectSpecalizerIfAvailableImpl
171       {
172         using Specializer = SpecializedPlugin<Interface>;
173       };
174 
175       /// \brief This template specialization will be invoked when
176       /// Specialization is not specialized for Interface, and therefore return
177       /// the generic Plugin type.
178       template <typename Interface>
179       struct SelectSpecalizerIfAvailableImpl<Interface, false>
180       {
181         using Specializer = Plugin;
182       };
183 
184       /// \brief If Specialization contains a leaf specializer for Interface,
185       /// i.e. SpecializedPlugin<Interface>, then this will provide that type
186       /// under the name `Specializer`. Otherwise, this will simply provide the
187       /// generic Plugin type.
188       template <typename Interface, typename Specialization>
189       struct SelectSpecalizerIfAvailable
190       {
191         using Specializer = typename SelectSpecalizerIfAvailableImpl<Interface,
192             std::is_base_of<SpecializedPlugin<Interface>, Specialization>::value
193             >::Specializer;
194       };
195 
196       /// \brief ComposePlugin provides a way for a multi-specialized Plugin
197       /// type to find its specializations within itself each time an
198       /// interface-querying function is called. The macro
199       /// DETAIL_IGN_COMMON_COMPOSEPLUGIN_DISPATCH accomplishes this for each
200       /// of the different functions by doing a compile-time check on whether
201       /// Base2 contains the specialization, and then picks Base1 if it does
202       /// not.
203       template <class Base1, class Base2>
204       class ComposePlugin : public virtual Base1, public virtual Base2
205       {
206         /// \brief Default destructor
207         public: virtual ~ComposePlugin() = default;
208 
209         // Inherit function overloads
210         using Plugin::QueryInterface;
211         using Plugin::QueryInterfaceSharedPtr;
212         using Plugin::HasInterface;
213 
214         // Used for template metaprogramming
215         using Specialization = ComposePlugin<Base1, Base2>;
216 
217         /// \brief Implement functions whose only roles are to dispatch their
218         /// functionalities between two base classes, depending on which base is
219         /// specialized for the template type. This must only be called within
220         /// the ComposePlugin class.
221         ///
222         /// The dispatch is performed by casting this object to the type that
223         /// specializes for the requested Interface, if such a type is availabe
224         /// within its inheritance structure. Otherwise, we cast to the generic
225         /// Plugin type.
226         #define DETAIL_IGN_COMMON_COMPOSEPLUGIN_DISPATCH( \
227                       ReturnType, Function, Suffix, CastTo, Args) \
228           public: /* NOLINT(*) */ \
229           template <class T> \
230           ReturnType Function Suffix \
231           { \
232             using Specializer = typename detail::SelectSpecalizerIfAvailable< \
233                     T, Specialization>::Specializer; \
234             return static_cast<CastTo*>(this)->template Function <T> Args; \
235           }
236 
237 
238         DETAIL_IGN_COMMON_COMPOSEPLUGIN_DISPATCH(
239             T*, QueryInterface, (), Specializer, ())
240 
241         DETAIL_IGN_COMMON_COMPOSEPLUGIN_DISPATCH(
242             const T*, QueryInterface, () const, const Specializer, ())
243 
244         DETAIL_IGN_COMMON_COMPOSEPLUGIN_DISPATCH(
245             std::shared_ptr<T>, QueryInterfaceSharedPtr, (), Specializer, ())
246 
247         DETAIL_IGN_COMMON_COMPOSEPLUGIN_DISPATCH(
248             std::shared_ptr<const T>, QueryInterfaceSharedPtr,
249             () const, const Specializer, ())
250 
251         DETAIL_IGN_COMMON_COMPOSEPLUGIN_DISPATCH(
252             bool, HasInterface, () const, const Specializer, ())
253 
254 
255         // Declare friendship
256         template <class...> friend class ignition::common::SpecializedPlugin;
257         template <class, class> friend class ComposePlugin;
258 
259         private: ComposePlugin() = default;
260       };
261     }
262 
263     /// \brief Construct an unbalanced binary tree of specializations by
264     /// convoluting SpecializedPlugin types using ComposePlugin.
265     template <class SpecInterface1, class... OtherSpecInterfaces>
266     class SpecializedPlugin<SpecInterface1, OtherSpecInterfaces...> :
267         public virtual detail::ComposePlugin<
268           SpecializedPlugin<SpecInterface1>,
269           SpecializedPlugin<OtherSpecInterfaces...> >
270     {
271       // Declare friendship
272       template <class...> friend class SpecializedPlugin;
273       template <class, class> friend class detail::ComposePlugin;
274       template <class> friend class TemplatePluginPtr;
275 
276       /// \brief Virtual destructor
277       public: virtual ~SpecializedPlugin() = default;
278 
279       /// \brief Default constructor
280       private: SpecializedPlugin() = default;
281     };
282   }
283 }
284 
285 #endif
286