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