Changeset 11071 for code/trunk/src/libraries/core/command/Functor.h
- Timestamp:
- Jan 17, 2016, 10:29:21 PM (9 years ago)
- Location:
- code/trunk
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
code/trunk
- Property svn:mergeinfo changed
-
code/trunk/src/libraries/core/command/Functor.h
r9667 r11071 40 40 41 41 To create a Functor, the helper function createFunctor() is used. It returns an instance 42 of orxonox::FunctorPtr which is simply a typedef of @ref orxonox::SharedPtr "SharedPtr<Functor>".43 Thismeans you don't have to delete the Functor after using it, because it is managed44 by the SharedPtr.42 of orxonox::FunctorPtr which is simply a typedef of "std::shared_ptr<Functor>". This 43 means you don't have to delete the Functor after using it, because it is managed 44 by the std::shared_ptr. 45 45 46 46 Example: … … 176 176 { 177 177 public: 178 struct Type 179 { 180 /// Defines the type of a function (static or member) 181 enum Enum 182 { 183 Static, 184 Member 185 }; 178 /// Defines the type of a function (static or member) 179 enum class Type 180 { 181 Static, 182 Member 186 183 }; 187 184 188 185 public: 189 virtual ~Functor() {}186 virtual ~Functor() = default; 190 187 191 188 /// Calls the function-pointer with up to five arguments. In case of a member-function, the assigned object-pointer is used to call the function. @return Returns the return-value of the function (if any; MultiType::Null otherwise) … … 196 193 197 194 /// Returns the type of the function: static or member. 198 virtual Type ::EnumgetType() const = 0;195 virtual Type getType() const = 0; 199 196 /// Returns the number of parameters of the function. 200 197 virtual unsigned int getParamCount() const = 0; … … 215 212 virtual void* getRawObjectPointer() const = 0; 216 213 217 /// Enables or disables the safe mode which causes the functor to change the object pointer to NULLif the object is deleted (only member functors).214 /// Enables or disables the safe mode which causes the functor to change the object pointer to nullptr if the object is deleted (only member functors). 218 215 virtual void setSafeMode(bool bSafeMode) = 0; 219 216 … … 242 239 public: 243 240 /// Constructor: Stores the object-pointer. 244 FunctorMember(O* object = 0) : object_(object), bSafeMode_(false) {}241 FunctorMember(O* object = nullptr) : object_(object), bSafeMode_(false) {} 245 242 virtual ~FunctorMember() { if (this->bSafeMode_) { this->unregisterObject(this->object_); } } 246 243 247 /// Calls the function-pointer with up to five arguments and an object. In case of a static-function, the object can be NULL. @return Returns the return-value of the function (if any; MultiType::Null otherwise)244 /// Calls the function-pointer with up to five arguments and an object. In case of a static-function, the object can be nullptr. @return Returns the return-value of the function (if any; MultiType::Null otherwise) 248 245 virtual MultiType operator()(O* object, const MultiType& param1 = MultiType::Null, const MultiType& param2 = MultiType::Null, const MultiType& param3 = MultiType::Null, const MultiType& param4 = MultiType::Null, const MultiType& param5 = MultiType::Null) = 0; 249 246 250 247 // see Functor::operator()() 251 MultiType operator()(const MultiType& param1 = MultiType::Null, const MultiType& param2 = MultiType::Null, const MultiType& param3 = MultiType::Null, const MultiType& param4 = MultiType::Null, const MultiType& param5 = MultiType::Null)248 virtual MultiType operator()(const MultiType& param1 = MultiType::Null, const MultiType& param2 = MultiType::Null, const MultiType& param3 = MultiType::Null, const MultiType& param4 = MultiType::Null, const MultiType& param5 = MultiType::Null) override 252 249 { 253 250 // call the function if an object was assigned … … 262 259 263 260 // see Functor::getType() 264 inline Functor::Type::Enum getType() const261 virtual inline Functor::Type getType() const override 265 262 { return Functor::Type::Member; } 266 263 … … 280 277 281 278 // see Functor::setRawObjectPointer() 282 inline void setRawObjectPointer(void* object)279 virtual inline void setRawObjectPointer(void* object) override 283 280 { this->setObject((O*)object); } 284 281 // see Functor::getRawObjectPointer() 285 inline void* getRawObjectPointer() const282 virtual inline void* getRawObjectPointer() const override 286 283 { return this->object_; } 287 284 288 285 // see Functor::setSafeMode() 289 inline void setSafeMode(bool bSafeMode)286 virtual inline void setSafeMode(bool bSafeMode) override 290 287 { 291 288 if (bSafeMode == this->bSafeMode_) … … 301 298 302 299 protected: 303 /// Casts the object and registers as destruction listener. 304 inline void registerObject(O* object) 305 { Destroyable* base = dynamic_cast<Destroyable*>(object); if (base) { this->registerAsDestructionListener(base); } } 306 /// Casts the object and unregisters as destruction listener. 307 inline void unregisterObject(O* object) 308 { Destroyable* base = dynamic_cast<Destroyable*>(object); if (base) { this->unregisterAsDestructionListener(base); } } 309 310 /// Will be called by Destroyable::~Destroyable() if the stored object is deleted and the Functor is in safe mode. 311 inline void objectDeleted() 312 { this->object_ = 0; } 313 314 O* object_; ///< The stored object-pointer, used to execute a member-function (or NULL for static functions) 315 bool bSafeMode_; ///< If true, the functor is in safe mode and registers itself as listener at the object and changes the pointer to NULL if the object is deleted 300 /// Casts the object and registers as destruction listener if the object is a Destroyable. 301 inline void registerObject(Destroyable* object) 302 { this->registerAsDestructionListener(object); } 303 304 inline void registerObject(void* object) {} 305 306 /// Casts the object and unregisters as destruction listener if the object is a Destroyable. 307 inline void unregisterObject(Destroyable* object) 308 { this->unregisterAsDestructionListener(object); } 309 310 inline void unregisterObject(void* object) {} 311 312 /// Will be called by Destroyable::~Destroyable() if the stored object is a Destroyable and deleted and the Functor is in safe mode. 313 virtual inline void objectDeleted() override 314 { this->object_ = nullptr; } 315 316 O* object_; ///< The stored object-pointer, used to execute a member-function (or nullptr for static functions) 317 bool bSafeMode_; ///< If true, the functor is in safe mode and registers itself as listener at the object and changes the pointer to nullptr if the object is deleted 316 318 }; 317 319 … … 322 324 public: 323 325 /// Constructor: Stores the object-pointer. 324 FunctorMember(void* object = 0) {}325 326 /// Calls the function-pointer with up to five arguments and an object. In case of a static-function, the object can be NULL. @return Returns the return-value of the function (if any; MultiType::Null otherwise)326 FunctorMember(void* object = nullptr) {} 327 328 /// Calls the function-pointer with up to five arguments and an object. In case of a static-function, the object can be nullptr. @return Returns the return-value of the function (if any; MultiType::Null otherwise) 327 329 virtual MultiType operator()(void* object, const MultiType& param1 = MultiType::Null, const MultiType& param2 = MultiType::Null, const MultiType& param3 = MultiType::Null, const MultiType& param4 = MultiType::Null, const MultiType& param5 = MultiType::Null) = 0; 328 330 329 331 // see Functor::operator()() 330 MultiType operator()(const MultiType& param1 = MultiType::Null, const MultiType& param2 = MultiType::Null, const MultiType& param3 = MultiType::Null, const MultiType& param4 = MultiType::Null, const MultiType& param5 = MultiType::Null)331 { 332 return (*this)((void*) 0, param1, param2, param3, param4, param5);332 virtual MultiType operator()(const MultiType& param1 = MultiType::Null, const MultiType& param2 = MultiType::Null, const MultiType& param3 = MultiType::Null, const MultiType& param4 = MultiType::Null, const MultiType& param5 = MultiType::Null) override 333 { 334 return (*this)((void*)nullptr, param1, param2, param3, param4, param5); 333 335 } 334 336 335 337 // see Functor::getType() 336 inline Functor::Type::Enum getType() const338 virtual inline Functor::Type getType() const override 337 339 { return Functor::Type::Static; } 338 340 339 341 // see Functor::setRawObjectPointer() 340 inline void setRawObjectPointer(void*)342 virtual inline void setRawObjectPointer(void*) override 341 343 { orxout(internal_warning) << "Can't assign an object pointer to a static functor" << endl; } 342 344 // see Functor::getRawObjectPointer() 343 inline void* getRawObjectPointer() const344 { return 0; }345 virtual inline void* getRawObjectPointer() const override 346 { return nullptr; } 345 347 346 348 // see Functor::setSafeMode() 347 inline void setSafeMode(bool){}349 virtual inline void setSafeMode(bool) override {} 348 350 }; 349 351 … … 352 354 353 355 /** 354 @brief FunctorPointer is a child class of FunctorMember and ex pands it with a function-pointer.355 @param F The type of the function-pointer 356 @param O The type of the function's class (or void if it's a static function )356 @brief FunctorPointer is a child class of FunctorMember and extends it with a function-pointer (or a function-object). 357 @param F The type of the function-pointer (or the function-object) 358 @param O The type of the function's class (or void if it's a static function or a function-object) 357 359 358 360 The template FunctorPointer has an additional template parameter that defines the type 359 of the function-pointer . This can be handy if you want to get or set the function-pointer.360 You can then use a static_cast to cast a Functor to FunctorPointer if you know the type361 of the function-pointer.361 of the function-pointer (or the function-object). This can be handy if you want to get 362 or set the function-pointer (or the function-object). You can then use a static_cast 363 to cast a Functor to FunctorPointer if you know the type of the function. 362 364 363 365 However FunctorPointer is not aware of the types of the different parameters or the … … 369 371 public: 370 372 /// Constructor: Initializes the base class and stores the function-pointer. 371 FunctorPointer(F functionPointer, O* object = 0) : FunctorMember<O>(object), functionPointer_(functionPointer) {}373 FunctorPointer(F functionPointer, O* object = nullptr) : FunctorMember<O>(object), functionPointer_(functionPointer) {} 372 374 373 375 /// Changes the function-pointer. … … 378 380 { return this->functionPointer_; } 379 381 380 // see Functor::getFullIdentifier()381 const std::type_info& getFullIdentifier() const382 { return typeid(F); }383 384 382 protected: 385 383 F functionPointer_; ///< The stored function-pointer … … 388 386 namespace detail 389 387 { 390 // Helper class to get the type of the function pointer with the given class, parameters, return-value, and constness 391 template <class R, class O, bool isconst, class P1, class P2, class P3, class P4, class P5> struct FunctionPointer { typedef R (O::*Type)(P1, P2, P3, P4, P5); }; 392 template <class R, class O, class P1, class P2, class P3, class P4, class P5> struct FunctionPointer<R, O, false, P1, P2, P3, P4, P5> { typedef R (O::*Type)(P1, P2, P3, P4, P5); }; 393 template <class R, class O, class P1, class P2, class P3, class P4> struct FunctionPointer<R, O, false, P1, P2, P3, P4, void> { typedef R (O::*Type)(P1, P2, P3, P4); }; 394 template <class R, class O, class P1, class P2, class P3> struct FunctionPointer<R, O, false, P1, P2, P3, void, void> { typedef R (O::*Type)(P1, P2, P3); }; 395 template <class R, class O, class P1, class P2> struct FunctionPointer<R, O, false, P1, P2, void, void, void> { typedef R (O::*Type)(P1, P2); }; 396 template <class R, class O, class P1> struct FunctionPointer<R, O, false, P1, void, void, void, void> { typedef R (O::*Type)(P1); }; 397 template <class R, class O> struct FunctionPointer<R, O, false, void, void, void, void, void> { typedef R (O::*Type)(); }; 398 template <class R, class O, class P1, class P2, class P3, class P4, class P5> struct FunctionPointer<R, O, true, P1, P2, P3, P4, P5> { typedef R (O::*Type)(P1, P2, P3, P4, P5) const; }; 399 template <class R, class O, class P1, class P2, class P3, class P4> struct FunctionPointer<R, O, true, P1, P2, P3, P4, void> { typedef R (O::*Type)(P1, P2, P3, P4) const; }; 400 template <class R, class O, class P1, class P2, class P3> struct FunctionPointer<R, O, true, P1, P2, P3, void, void> { typedef R (O::*Type)(P1, P2, P3) const; }; 401 template <class R, class O, class P1, class P2> struct FunctionPointer<R, O, true, P1, P2, void, void, void> { typedef R (O::*Type)(P1, P2) const; }; 402 template <class R, class O, class P1> struct FunctionPointer<R, O, true, P1, void, void, void, void> { typedef R (O::*Type)(P1) const; }; 403 template <class R, class O> struct FunctionPointer<R, O, true, void, void, void, void, void> { typedef R (O::*Type)() const; }; 404 template <class R, class P1, class P2, class P3, class P4, class P5> struct FunctionPointer<R, void, false, P1, P2, P3, P4, P5> { typedef R (*Type)(P1, P2, P3, P4, P5); }; 405 template <class R, class P1, class P2, class P3, class P4> struct FunctionPointer<R, void, false, P1, P2, P3, P4, void> { typedef R (*Type)(P1, P2, P3, P4); }; 406 template <class R, class P1, class P2, class P3> struct FunctionPointer<R, void, false, P1, P2, P3, void, void> { typedef R (*Type)(P1, P2, P3); }; 407 template <class R, class P1, class P2> struct FunctionPointer<R, void, false, P1, P2, void, void, void> { typedef R (*Type)(P1, P2); }; 408 template <class R, class P1> struct FunctionPointer<R, void, false, P1, void, void, void, void> { typedef R (*Type)(P1); }; 409 template <class R> struct FunctionPointer<R, void, false, void, void, void, void, void> { typedef R (*Type)(); }; 410 411 // Helper class, used to call a function-pointer with a given object and parameters and to return its return-value (if available) 412 template <class R, class O, bool isconst, class P1, class P2, class P3, class P4, class P5> struct FunctorCaller { static inline MultiType call(typename detail::FunctionPointer<R, O, isconst, P1, P2, P3, P4, P5>::Type functionPointer, O* object, const MultiType& param1, const MultiType& param2, const MultiType& param3, const MultiType& param4, const MultiType& param5) { return (object->*functionPointer)(param1, param2, param3, param4, param5); } }; 413 template <class R, class O, bool isconst, class P1, class P2, class P3, class P4> struct FunctorCaller<R, O, isconst, P1, P2, P3, P4, void> { static inline MultiType call(typename detail::FunctionPointer<R, O, isconst, P1, P2, P3, P4, void>::Type functionPointer, O* object, const MultiType& param1, const MultiType& param2, const MultiType& param3, const MultiType& param4, const MultiType&) { return (object->*functionPointer)(param1, param2, param3, param4); } }; 414 template <class R, class O, bool isconst, class P1, class P2, class P3> struct FunctorCaller<R, O, isconst, P1, P2, P3, void, void> { static inline MultiType call(typename detail::FunctionPointer<R, O, isconst, P1, P2, P3, void, void>::Type functionPointer, O* object, const MultiType& param1, const MultiType& param2, const MultiType& param3, const MultiType&, const MultiType&) { return (object->*functionPointer)(param1, param2, param3); } }; 415 template <class R, class O, bool isconst, class P1, class P2> struct FunctorCaller<R, O, isconst, P1, P2, void, void, void> { static inline MultiType call(typename detail::FunctionPointer<R, O, isconst, P1, P2, void, void, void>::Type functionPointer, O* object, const MultiType& param1, const MultiType& param2, const MultiType&, const MultiType&, const MultiType&) { return (object->*functionPointer)(param1, param2); } }; 416 template <class R, class O, bool isconst, class P1> struct FunctorCaller<R, O, isconst, P1, void, void, void, void> { static inline MultiType call(typename detail::FunctionPointer<R, O, isconst, P1, void, void, void, void>::Type functionPointer, O* object, const MultiType& param1, const MultiType&, const MultiType&, const MultiType&, const MultiType&) { return (object->*functionPointer)(param1); } }; 417 template <class R, class O, bool isconst> struct FunctorCaller<R, O, isconst, void, void, void, void, void> { static inline MultiType call(typename detail::FunctionPointer<R, O, isconst, void, void, void, void, void>::Type functionPointer, O* object, const MultiType&, const MultiType&, const MultiType&, const MultiType&, const MultiType&) { return (object->*functionPointer)(); } }; 418 template <class O, bool isconst, class P1, class P2, class P3, class P4, class P5> struct FunctorCaller<void, O, isconst, P1, P2, P3, P4, P5> { static inline MultiType call(typename detail::FunctionPointer<void, O, isconst, P1, P2, P3, P4, P5>::Type functionPointer, O* object, const MultiType& param1, const MultiType& param2, const MultiType& param3, const MultiType& param4, const MultiType& param5) { (object->*functionPointer)(param1, param2, param3, param4, param5); return MultiType::Null; } }; 419 template <class O, bool isconst, class P1, class P2, class P3, class P4> struct FunctorCaller<void, O, isconst, P1, P2, P3, P4, void> { static inline MultiType call(typename detail::FunctionPointer<void, O, isconst, P1, P2, P3, P4, void>::Type functionPointer, O* object, const MultiType& param1, const MultiType& param2, const MultiType& param3, const MultiType& param4, const MultiType&) { (object->*functionPointer)(param1, param2, param3, param4); return MultiType::Null; } }; 420 template <class O, bool isconst, class P1, class P2, class P3> struct FunctorCaller<void, O, isconst, P1, P2, P3, void, void> { static inline MultiType call(typename detail::FunctionPointer<void, O, isconst, P1, P2, P3, void, void>::Type functionPointer, O* object, const MultiType& param1, const MultiType& param2, const MultiType& param3, const MultiType&, const MultiType&) { (object->*functionPointer)(param1, param2, param3); return MultiType::Null; } }; 421 template <class O, bool isconst, class P1, class P2> struct FunctorCaller<void, O, isconst, P1, P2, void, void, void> { static inline MultiType call(typename detail::FunctionPointer<void, O, isconst, P1, P2, void, void, void>::Type functionPointer, O* object, const MultiType& param1, const MultiType& param2, const MultiType&, const MultiType&, const MultiType&) { (object->*functionPointer)(param1, param2); return MultiType::Null; } }; 422 template <class O, bool isconst, class P1> struct FunctorCaller<void, O, isconst, P1, void, void, void, void> { static inline MultiType call(typename detail::FunctionPointer<void, O, isconst, P1, void, void, void, void>::Type functionPointer, O* object, const MultiType& param1, const MultiType&, const MultiType&, const MultiType&, const MultiType&) { (object->*functionPointer)(param1); return MultiType::Null; } }; 423 template <class O, bool isconst> struct FunctorCaller<void, O, isconst, void, void, void, void, void> { static inline MultiType call(typename detail::FunctionPointer<void, O, isconst, void, void, void, void, void>::Type functionPointer, O* object, const MultiType&, const MultiType&, const MultiType&, const MultiType&, const MultiType&) { (object->*functionPointer)(); return MultiType::Null; } }; 424 template <class R, bool isconst, class P1, class P2, class P3, class P4, class P5> struct FunctorCaller<R, void, isconst, P1, P2, P3, P4, P5> { static inline MultiType call(typename detail::FunctionPointer<R, void, isconst, P1, P2, P3, P4, P5>::Type functionPointer, void*, const MultiType& param1, const MultiType& param2, const MultiType& param3, const MultiType& param4, const MultiType& param5) { return (*functionPointer)(param1, param2, param3, param4, param5); } }; 425 template <class R, bool isconst, class P1, class P2, class P3, class P4> struct FunctorCaller<R, void, isconst, P1, P2, P3, P4, void> { static inline MultiType call(typename detail::FunctionPointer<R, void, isconst, P1, P2, P3, P4, void>::Type functionPointer, void*, const MultiType& param1, const MultiType& param2, const MultiType& param3, const MultiType& param4, const MultiType&) { return (*functionPointer)(param1, param2, param3, param4); } }; 426 template <class R, bool isconst, class P1, class P2, class P3> struct FunctorCaller<R, void, isconst, P1, P2, P3, void, void> { static inline MultiType call(typename detail::FunctionPointer<R, void, isconst, P1, P2, P3, void, void>::Type functionPointer, void*, const MultiType& param1, const MultiType& param2, const MultiType& param3, const MultiType&, const MultiType&) { return (*functionPointer)(param1, param2, param3); } }; 427 template <class R, bool isconst, class P1, class P2> struct FunctorCaller<R, void, isconst, P1, P2, void, void, void> { static inline MultiType call(typename detail::FunctionPointer<R, void, isconst, P1, P2, void, void, void>::Type functionPointer, void*, const MultiType& param1, const MultiType& param2, const MultiType&, const MultiType&, const MultiType&) { return (*functionPointer)(param1, param2); } }; 428 template <class R, bool isconst, class P1> struct FunctorCaller<R, void, isconst, P1, void, void, void, void> { static inline MultiType call(typename detail::FunctionPointer<R, void, isconst, P1, void, void, void, void>::Type functionPointer, void*, const MultiType& param1, const MultiType&, const MultiType&, const MultiType&, const MultiType&) { return (*functionPointer)(param1); } }; 429 template <class R, bool isconst> struct FunctorCaller<R, void, isconst, void, void, void, void, void> { static inline MultiType call(typename detail::FunctionPointer<R, void, isconst, void, void, void, void, void>::Type functionPointer, void*, const MultiType&, const MultiType&, const MultiType&, const MultiType&, const MultiType&) { return (*functionPointer)(); } }; 430 template <bool isconst, class P1, class P2, class P3, class P4, class P5> struct FunctorCaller<void, void, isconst, P1, P2, P3, P4, P5> { static inline MultiType call(typename detail::FunctionPointer<void, void, isconst, P1, P2, P3, P4, P5>::Type functionPointer, void*, const MultiType& param1, const MultiType& param2, const MultiType& param3, const MultiType& param4, const MultiType& param5) { (*functionPointer)(param1, param2, param3, param4, param5); return MultiType::Null; } }; 431 template <bool isconst, class P1, class P2, class P3, class P4> struct FunctorCaller<void, void, isconst, P1, P2, P3, P4, void> { static inline MultiType call(typename detail::FunctionPointer<void, void, isconst, P1, P2, P3, P4, void>::Type functionPointer, void*, const MultiType& param1, const MultiType& param2, const MultiType& param3, const MultiType& param4, const MultiType&) { (*functionPointer)(param1, param2, param3, param4); return MultiType::Null; } }; 432 template <bool isconst, class P1, class P2, class P3> struct FunctorCaller<void, void, isconst, P1, P2, P3, void, void> { static inline MultiType call(typename detail::FunctionPointer<void, void, isconst, P1, P2, P3, void, void>::Type functionPointer, void*, const MultiType& param1, const MultiType& param2, const MultiType& param3, const MultiType&, const MultiType&) { (*functionPointer)(param1, param2, param3); return MultiType::Null; } }; 433 template <bool isconst, class P1, class P2> struct FunctorCaller<void, void, isconst, P1, P2, void, void, void> { static inline MultiType call(typename detail::FunctionPointer<void, void, isconst, P1, P2, void, void, void>::Type functionPointer, void*, const MultiType& param1, const MultiType& param2, const MultiType&, const MultiType&, const MultiType&) { (*functionPointer)(param1, param2); return MultiType::Null; } }; 434 template <bool isconst, class P1> struct FunctorCaller<void, void, isconst, P1, void, void, void, void> { static inline MultiType call(typename detail::FunctionPointer<void, void, isconst, P1, void, void, void, void>::Type functionPointer, void*, const MultiType& param1, const MultiType&, const MultiType&, const MultiType&, const MultiType&) { (*functionPointer)(param1); return MultiType::Null; } }; 435 template <bool isconst> struct FunctorCaller<void, void, isconst, void, void, void, void, void> { static inline MultiType call(typename detail::FunctionPointer<void, void, isconst, void, void, void, void, void>::Type functionPointer, void*, const MultiType&, const MultiType&, const MultiType&, const MultiType&, const MultiType&) { (*functionPointer)(); return MultiType::Null; } }; 436 437 // Helper class, used to identify the header of a function-pointer (independent of its class) 438 template <class R, class P1, class P2, class P3, class P4, class P5> 439 struct FunctorHeaderIdentifier 440 {}; 388 // Helper class to get the type of the function-pointer (or the function-object) with the given class, parameters, return-value, and constness 389 template <class F, class R, class O, bool isconst, class... Params> struct FunctionType /* generic type is undefined */; 390 template < class R, class O, class... Params> struct FunctionType<void, R, O, false, Params...> { typedef R (O::*Type)(Params...); }; // spezialization: non-const member function 391 template < class R, class O, class... Params> struct FunctionType<void, R, O, true, Params...> { typedef R (O::*Type)(Params...) const; }; // spezialization: const member function 392 template < class R, class... Params> struct FunctionType<void, R, void, false, Params...> { typedef R (*Type)(Params...); }; // spezialization: static function 393 template <class F, class R, class... Params> struct FunctionType<F, R, void, false, Params...> { typedef F Type; }; // spezialization: function object 394 395 // Helper class, used to call a function with a given object and parameters and to return its return-value (if available) 396 template <class F, class R, class O, bool isconst, class... Params> struct FunctorCaller /* generic type is undefined */; 397 template < class R, class O, bool isconst, class... Params> struct FunctorCaller<void, R, O, isconst, Params...> { template <class... UnusedParams> static inline MultiType call(typename detail::FunctionType<void, R, O, isconst, Params...>::Type functionPointer, O* object, const Params&... parameters, const UnusedParams&...) { return (object->*functionPointer)(parameters...); } }; // spezialization: member function with return value 398 template < class O, bool isconst, class... Params> struct FunctorCaller<void, void, O, isconst, Params...> { template <class... UnusedParams> static inline MultiType call(typename detail::FunctionType<void, void, O, isconst, Params...>::Type functionPointer, O* object, const Params&... parameters, const UnusedParams&...) { (object->*functionPointer)(parameters...); return MultiType::Null; } }; // spezialization: member function without return value 399 template < class R, class... Params> struct FunctorCaller<void, R, void, false, Params...> { template <class... UnusedParams> static inline MultiType call(typename detail::FunctionType<void, R, void, false, Params...>::Type functionPointer, void*, const Params&... parameters, const UnusedParams&...) { return (*functionPointer)(parameters...); } }; // spezialization: static function with return value 400 template < class... Params> struct FunctorCaller<void, void, void, false, Params...> { template <class... UnusedParams> static inline MultiType call(typename detail::FunctionType<void, void, void, false, Params...>::Type functionPointer, void*, const Params&... parameters, const UnusedParams&...) { (*functionPointer)(parameters...); return MultiType::Null; } }; // spezialization: static function without return value 401 template <class F, class R, class... Params> struct FunctorCaller<F, R, void, false, Params...> { template <class... UnusedParams> static inline MultiType call(typename detail::FunctionType<F, R, void, false, Params...>::Type functor, void*, const Params&... parameters, const UnusedParams&...) { return functor(parameters...); } }; // spezialization: function object with return value 402 template <class F, class... Params> struct FunctorCaller<F, void, void, false, Params...> { template <class... UnusedParams> static inline MultiType call(typename detail::FunctionType<F, void, void, false, Params...>::Type functor, void*, const Params&... parameters, const UnusedParams&...) { functor(parameters...); return MultiType::Null; } }; // spezialization: function object without return value 441 403 442 404 // Helper class to determine if a function has a returnvalue … … 448 410 { enum { result = false }; }; 449 411 450 // Helper class to count the number of parameters 451 template <class P1, class P2, class P3, class P4, class P5> 452 struct FunctorParamCount 453 { enum { result = 5 }; }; 454 template <class P1, class P2, class P3, class P4> 455 struct FunctorParamCount<P1, P2, P3, P4, void> 456 { enum { result = 4 }; }; 457 template <class P1, class P2, class P3> 458 struct FunctorParamCount<P1, P2, P3, void, void> 459 { enum { result = 3 }; }; 460 template <class P1, class P2> 461 struct FunctorParamCount<P1, P2, void, void, void> 462 { enum { result = 2 }; }; 463 template <class P1> 464 struct FunctorParamCount<P1, void, void, void, void> 465 { enum { result = 1 }; }; 412 // Helper class to determine the N-th parameter of a variadic template (with 0 being the index of the first parameter) 413 template <int n, typename T = void, typename... Other> 414 struct GetNthParamType 415 { typedef typename GetNthParamType<n - 1, Other...>::Type Type; }; 416 template <typename T, typename... Other> 417 struct GetNthParamType<0, T, Other...> 418 { typedef T Type; }; 419 420 // Helper structs to deduce the first N types of a parameter pack 421 template<class... Types> struct type_list {}; 422 423 template <class T1, class... AllTypes> 424 struct make_type_list_helper 425 { 426 template <std::size_t N, class... Types> 427 struct make_type_list_impl : make_type_list_helper<AllTypes...>::template make_type_list_impl<N - 1, Types..., T1> {}; 428 429 template <class... Types> 430 struct make_type_list_impl<1u, Types...> : type_list<Types..., T1> {}; 431 }; 432 433 template <class T1> 434 struct make_type_list_helper<T1> 435 { 436 template <std::size_t N, class... Types> 437 struct make_type_list_impl : type_list<Types..., T1> {}; 438 }; 439 440 template <std::size_t N, class... Types> 441 struct make_type_list : make_type_list_helper<Types...>::template make_type_list_impl<N> {}; 442 443 template <class... Types> 444 struct make_type_list<0u, Types...> : type_list<> {}; 445 446 template <std::size_t N> 447 struct make_type_list<N> : type_list<> {}; 448 466 449 template <> 467 struct FunctorParamCount<void, void, void, void, void> 468 { enum { result = 0 }; }; 450 struct make_type_list<0u> : type_list<> {}; 469 451 } 470 452 … … 473 455 that need to know the exact types of the parameters, return-value, and class. 474 456 457 @param F the type of the function-object (or void if a function-pointer is used). 475 458 @param R The type of the return-value of the function 476 459 @param O The class of the function 477 460 @param isconst True if the function is a const member-function 478 @param P1 The type of the first parameter 479 @param P2 The type of the second parameter 480 @param P3 The type of the third parameter 481 @param P4 The type of the fourth parameter 482 @param P5 The type of the fifth parameter 461 @param Params The types of the parameters 483 462 484 463 This template has many parameters and is usually not used directly. It is created by … … 489 468 All template arguments can be void. 490 469 */ 491 template <class R, class O, bool isconst, class P1, class P2, class P3, class P4, class P5> 492 class FunctorTemplate : public FunctorPointer<typename detail::FunctionPointer<R, O, isconst, P1, P2, P3, P4, P5>::Type, O> 493 { 470 template <class F, class R, class O, bool isconst, class... Params> 471 class FunctorTemplate : public FunctorPointer<typename detail::FunctionType<F, R, O, isconst, Params...>::Type, O> 472 { 473 static_assert(sizeof...(Params) <= 5, "Only up to 5 parameters are supported"); 474 494 475 public: 495 476 /// Constructor: Initializes the base class. 496 FunctorTemplate(typename detail::Function Pointer<R, O, isconst, P1, P2, P3, P4, P5>::Type functionPointer, O* object = 0) : FunctorPointer<typename detail::FunctionPointer<R, O, isconst, P1, P2, P3, P4, P5>::Type, O>(functionPointer, object) {}477 FunctorTemplate(typename detail::FunctionType<F, R, O, isconst, Params...>::Type functionPointer, O* object = nullptr) : FunctorPointer<typename detail::FunctionType<F, R, O, isconst, Params...>::Type, O>(functionPointer, object) {} 497 478 498 479 // see FunctorMember::operator()() 499 MultiType operator()(O* object, const MultiType& param1 = MultiType::Null, const MultiType& param2 = MultiType::Null, const MultiType& param3 = MultiType::Null, const MultiType& param4 = MultiType::Null, const MultiType& param5 = MultiType::Null)500 { 501 return detail::FunctorCaller< R, O, isconst, P1, P2, P3, P4, P5>::call(this->functionPointer_, object, param1, param2, param3, param4, param5);480 virtual MultiType operator()(O* object, const MultiType& param1 = MultiType::Null, const MultiType& param2 = MultiType::Null, const MultiType& param3 = MultiType::Null, const MultiType& param4 = MultiType::Null, const MultiType& param5 = MultiType::Null) override 481 { 482 return detail::FunctorCaller<F, R, O, isconst, Params...>::call(this->functionPointer_, object, param1, param2, param3, param4, param5); 502 483 } 503 484 504 485 // see Functor::clone() 505 FunctorPtr clone()506 { 507 return new FunctorTemplate(*this);486 virtual FunctorPtr clone() override 487 { 488 return std::make_shared<FunctorTemplate>(*this); 508 489 } 509 490 510 491 // see Functor::evaluateArgument() 511 v oid evaluateArgument(unsigned int index, MultiType& argument) const492 virtual void evaluateArgument(unsigned int index, MultiType& argument) const override 512 493 { 513 494 switch (index) 514 495 { 515 case 0: argument.convert< P1>(); break;516 case 1: argument.convert< P2>(); break;517 case 2: argument.convert< P3>(); break;518 case 3: argument.convert< P4>(); break;519 case 4: argument.convert< P5>(); break;496 case 0: argument.convert<typename detail::GetNthParamType<0, Params...>::Type>(); break; 497 case 1: argument.convert<typename detail::GetNthParamType<1, Params...>::Type>(); break; 498 case 2: argument.convert<typename detail::GetNthParamType<2, Params...>::Type>(); break; 499 case 3: argument.convert<typename detail::GetNthParamType<3, Params...>::Type>(); break; 500 case 4: argument.convert<typename detail::GetNthParamType<4, Params...>::Type>(); break; 520 501 } 521 502 } 522 503 523 504 // see Functor::getParamCount() 524 unsigned int getParamCount() const525 { 526 return detail::FunctorParamCount<P1, P2, P3, P4, P5>::result;505 virtual unsigned int getParamCount() const override 506 { 507 return sizeof...(Params); 527 508 } 528 509 529 510 // see Functor::hasReturnvalue() 530 bool hasReturnvalue() const511 virtual bool hasReturnvalue() const override 531 512 { 532 513 return detail::FunctorHasReturnvalue<R>::result; … … 534 515 535 516 // see Functor::getTypenameParam() 536 std::string getTypenameParam(unsigned int index) const517 virtual std::string getTypenameParam(unsigned int index) const override 537 518 { 538 519 switch (index) 539 520 { 540 case 0: return typeToString< P1>();541 case 1: return typeToString< P2>();542 case 2: return typeToString< P3>();543 case 3: return typeToString< P4>();544 case 4: return typeToString< P5>();521 case 0: return typeToString<typename detail::GetNthParamType<0, Params...>::Type>(); 522 case 1: return typeToString<typename detail::GetNthParamType<1, Params...>::Type>(); 523 case 2: return typeToString<typename detail::GetNthParamType<2, Params...>::Type>(); 524 case 3: return typeToString<typename detail::GetNthParamType<3, Params...>::Type>(); 525 case 4: return typeToString<typename detail::GetNthParamType<4, Params...>::Type>(); 545 526 default: return ""; 546 527 } … … 548 529 549 530 // see Functor::getTypenameReturnvalue() 550 std::string getTypenameReturnvalue() const531 virtual std::string getTypenameReturnvalue() const override 551 532 { 552 533 return typeToString<R>(); 553 534 } 554 535 536 // see Functor::getFullIdentifier() 537 virtual const std::type_info& getFullIdentifier() const override 538 { 539 return typeid(typename detail::FunctionType<void, R, O, isconst, Params...>::Type); 540 } 541 555 542 // see Functor::getHeaderIdentifier() 556 const std::type_info& getHeaderIdentifier() const557 { 558 return typeid( detail::FunctorHeaderIdentifier<R, P1, P2, P3, P4, P5>);543 virtual const std::type_info& getHeaderIdentifier() const override 544 { 545 return typeid(typename detail::FunctionType<void, R, void, false, Params...>::Type); 559 546 } 560 547 561 548 // see Functor::getHeaderIdentifier(unsigned int) 562 const std::type_info& getHeaderIdentifier(unsigned int params) const549 virtual const std::type_info& getHeaderIdentifier(unsigned int params) const override 563 550 { 564 551 switch (params) 565 552 { 566 case 0: return t ypeid(detail::FunctorHeaderIdentifier<R, void, void, void, void, void>);567 case 1: return t ypeid(detail::FunctorHeaderIdentifier<R, P1, void, void, void, void>);568 case 2: return t ypeid(detail::FunctorHeaderIdentifier<R, P1, P2, void, void, void>);569 case 3: return t ypeid(detail::FunctorHeaderIdentifier<R, P1, P2, P3, void, void>);570 case 4: return t ypeid(detail::FunctorHeaderIdentifier<R, P1, P2, P3, P4, void>);571 default: return t ypeid(detail::FunctorHeaderIdentifier<R, P1, P2, P3, P4, P5>);553 case 0: return this->getTypelistIdentifier(detail::make_type_list<0, Params...>{}); 554 case 1: return this->getTypelistIdentifier(detail::make_type_list<1, Params...>{}); 555 case 2: return this->getTypelistIdentifier(detail::make_type_list<2, Params...>{}); 556 case 3: return this->getTypelistIdentifier(detail::make_type_list<3, Params...>{}); 557 case 4: return this->getTypelistIdentifier(detail::make_type_list<4, Params...>{}); 558 default: return this->getTypelistIdentifier(detail::make_type_list<5, Params...>{}); 572 559 } 573 560 } 561 562 private: 563 /// Helper function that deduces a parameter pack of types and returns the corresponding identifier 564 template<class... Types> 565 const std::type_info& getTypelistIdentifier(detail::type_list<Types...>) const 566 { 567 return typeid(typename detail::FunctionType<void, R, void, false, Types...>::Type); 568 } 574 569 }; 575 570 576 template <class R, class O, class OO, class P1, class P2, class P3, class P4, class P5> inline FunctorMemberPtr<O> createFunctor(R (O::*functionPointer)(P1, P2, P3, P4, P5), OO* object) { return new FunctorTemplate<R, O, false, P1, P2, P3, P4, P5>(functionPointer, object); } ///< Creates a new FunctorMember with the given function-pointer and an assigned object 577 template <class R, class O, class OO, class P1, class P2, class P3, class P4> inline FunctorMemberPtr<O> createFunctor(R (O::*functionPointer)(P1, P2, P3, P4), OO* object) { return new FunctorTemplate<R, O, false, P1, P2, P3, P4, void>(functionPointer, object); } ///< Creates a new FunctorMember with the given function-pointer and an assigned object 578 template <class R, class O, class OO, class P1, class P2, class P3> inline FunctorMemberPtr<O> createFunctor(R (O::*functionPointer)(P1, P2, P3), OO* object) { return new FunctorTemplate<R, O, false, P1, P2, P3, void, void>(functionPointer, object); } ///< Creates a new FunctorMember with the given function-pointer and an assigned object 579 template <class R, class O, class OO, class P1, class P2> inline FunctorMemberPtr<O> createFunctor(R (O::*functionPointer)(P1, P2), OO* object) { return new FunctorTemplate<R, O, false, P1, P2, void, void, void>(functionPointer, object); } ///< Creates a new FunctorMember with the given function-pointer and an assigned object 580 template <class R, class O, class OO, class P1> inline FunctorMemberPtr<O> createFunctor(R (O::*functionPointer)(P1), OO* object) { return new FunctorTemplate<R, O, false, P1, void, void, void, void>(functionPointer, object); } ///< Creates a new FunctorMember with the given function-pointer and an assigned object 581 template <class R, class O, class OO> inline FunctorMemberPtr<O> createFunctor(R (O::*functionPointer)(), OO* object) { return new FunctorTemplate<R, O, false, void, void, void, void, void>(functionPointer, object); } ///< Creates a new FunctorMember with the given function-pointer and an assigned object 582 template <class R, class O, class OO, class P1, class P2, class P3, class P4, class P5> inline FunctorMemberPtr<O> createFunctor(R (O::*functionPointer)(P1, P2, P3, P4, P5) const, OO* object) { return new FunctorTemplate<R, O, true, P1, P2, P3, P4, P5>(functionPointer, object); } ///< Creates a new FunctorMember with the given function-pointer and an assigned object 583 template <class R, class O, class OO, class P1, class P2, class P3, class P4> inline FunctorMemberPtr<O> createFunctor(R (O::*functionPointer)(P1, P2, P3, P4) const, OO* object) { return new FunctorTemplate<R, O, true, P1, P2, P3, P4, void>(functionPointer, object); } ///< Creates a new FunctorMember with the given function-pointer and an assigned object 584 template <class R, class O, class OO, class P1, class P2, class P3> inline FunctorMemberPtr<O> createFunctor(R (O::*functionPointer)(P1, P2, P3) const, OO* object) { return new FunctorTemplate<R, O, true, P1, P2, P3, void, void>(functionPointer, object); } ///< Creates a new FunctorMember with the given function-pointer and an assigned object 585 template <class R, class O, class OO, class P1, class P2> inline FunctorMemberPtr<O> createFunctor(R (O::*functionPointer)(P1, P2) const, OO* object) { return new FunctorTemplate<R, O, true, P1, P2, void, void, void>(functionPointer, object); } ///< Creates a new FunctorMember with the given function-pointer and an assigned object 586 template <class R, class O, class OO, class P1> inline FunctorMemberPtr<O> createFunctor(R (O::*functionPointer)(P1) const, OO* object) { return new FunctorTemplate<R, O, true, P1, void, void, void, void>(functionPointer, object); } ///< Creates a new FunctorMember with the given function-pointer and an assigned object 587 template <class R, class O, class OO> inline FunctorMemberPtr<O> createFunctor(R (O::*functionPointer)() const, OO* object) { return new FunctorTemplate<R, O, true, void, void, void, void, void>(functionPointer, object); } ///< Creates a new FunctorMember with the given function-pointer and an assigned object 588 589 template <class R, class O, class P1, class P2, class P3, class P4, class P5> inline FunctorMemberPtr<O> createFunctor(R (O::*functionPointer)(P1, P2, P3, P4, P5)) { return new FunctorTemplate<R, O, false, P1, P2, P3, P4, P5>(functionPointer); } ///< Creates a new FunctorMember with the given function-pointer 590 template <class R, class O, class P1, class P2, class P3, class P4> inline FunctorMemberPtr<O> createFunctor(R (O::*functionPointer)(P1, P2, P3, P4)) { return new FunctorTemplate<R, O, false, P1, P2, P3, P4, void>(functionPointer); } ///< Creates a new FunctorMember with the given function-pointer 591 template <class R, class O, class P1, class P2, class P3> inline FunctorMemberPtr<O> createFunctor(R (O::*functionPointer)(P1, P2, P3)) { return new FunctorTemplate<R, O, false, P1, P2, P3, void, void>(functionPointer); } ///< Creates a new FunctorMember with the given function-pointer 592 template <class R, class O, class P1, class P2> inline FunctorMemberPtr<O> createFunctor(R (O::*functionPointer)(P1, P2)) { return new FunctorTemplate<R, O, false, P1, P2, void, void, void>(functionPointer); } ///< Creates a new FunctorMember with the given function-pointer 593 template <class R, class O, class P1> inline FunctorMemberPtr<O> createFunctor(R (O::*functionPointer)(P1)) { return new FunctorTemplate<R, O, false, P1, void, void, void, void>(functionPointer); } ///< Creates a new FunctorMember with the given function-pointer 594 template <class R, class O> inline FunctorMemberPtr<O> createFunctor(R (O::*functionPointer)()) { return new FunctorTemplate<R, O, false, void, void, void, void, void>(functionPointer); } ///< Creates a new FunctorMember with the given function-pointer 595 template <class R, class O, class P1, class P2, class P3, class P4, class P5> inline FunctorMemberPtr<O> createFunctor(R (O::*functionPointer)(P1, P2, P3, P4, P5) const) { return new FunctorTemplate<R, O, true, P1, P2, P3, P4, P5>(functionPointer); } ///< Creates a new FunctorMember with the given function-pointer 596 template <class R, class O, class P1, class P2, class P3, class P4> inline FunctorMemberPtr<O> createFunctor(R (O::*functionPointer)(P1, P2, P3, P4) const) { return new FunctorTemplate<R, O, true, P1, P2, P3, P4, void>(functionPointer); } ///< Creates a new FunctorMember with the given function-pointer 597 template <class R, class O, class P1, class P2, class P3> inline FunctorMemberPtr<O> createFunctor(R (O::*functionPointer)(P1, P2, P3) const) { return new FunctorTemplate<R, O, true, P1, P2, P3, void, void>(functionPointer); } ///< Creates a new FunctorMember with the given function-pointer 598 template <class R, class O, class P1, class P2> inline FunctorMemberPtr<O> createFunctor(R (O::*functionPointer)(P1, P2) const) { return new FunctorTemplate<R, O, true, P1, P2, void, void, void>(functionPointer); } ///< Creates a new FunctorMember with the given function-pointer 599 template <class R, class O, class P1> inline FunctorMemberPtr<O> createFunctor(R (O::*functionPointer)(P1) const) { return new FunctorTemplate<R, O, true, P1, void, void, void, void>(functionPointer); } ///< Creates a new FunctorMember with the given function-pointer 600 template <class R, class O> inline FunctorMemberPtr<O> createFunctor(R (O::*functionPointer)() const) { return new FunctorTemplate<R, O, true, void, void, void, void, void>(functionPointer); } ///< Creates a new FunctorMember with the given function-pointer 601 602 template <class R, class P1, class P2, class P3, class P4, class P5> inline FunctorStaticPtr createFunctor(R (*functionPointer)(P1, P2, P3, P4, P5)) { return new FunctorTemplate<R, void, false, P1, P2, P3, P4, P5>(functionPointer); } ///< Creates a new Functor with the given function-pointer 603 template <class R, class P1, class P2, class P3, class P4> inline FunctorStaticPtr createFunctor(R (*functionPointer)(P1, P2, P3, P4)) { return new FunctorTemplate<R, void, false, P1, P2, P3, P4, void>(functionPointer); } ///< Creates a new Functor with the given function-pointer 604 template <class R, class P1, class P2, class P3> inline FunctorStaticPtr createFunctor(R (*functionPointer)(P1, P2, P3)) { return new FunctorTemplate<R, void, false, P1, P2, P3, void, void>(functionPointer); } ///< Creates a new Functor with the given function-pointer 605 template <class R, class P1, class P2> inline FunctorStaticPtr createFunctor(R (*functionPointer)(P1, P2)) { return new FunctorTemplate<R, void, false, P1, P2, void, void, void>(functionPointer); } ///< Creates a new Functor with the given function-pointer 606 template <class R, class P1> inline FunctorStaticPtr createFunctor(R (*functionPointer)(P1)) { return new FunctorTemplate<R, void, false, P1, void, void, void, void>(functionPointer); } ///< Creates a new Functor with the given function-pointer 607 template <class R> inline FunctorStaticPtr createFunctor(R (*functionPointer)()) { return new FunctorTemplate<R, void, false, void, void, void, void, void>(functionPointer); } ///< Creates a new Functor with the given function-pointer 571 572 namespace detail 573 { 574 // Helper functions to deduce types and constness of operator() and return the correct FunctorTemplate 575 template <class F> 576 struct CallableHelper 577 { 578 template <class R, class... Params> static inline FunctorStaticPtr create(const F& functionObject, R(F::*)(Params...)) { return std::make_shared<FunctorTemplate<F, R, void, false, Params...>>(functionObject); } 579 template <class R, class... Params> static inline FunctorStaticPtr create(const F& functionObject, R(F::*)(Params...) const) { return std::make_shared<FunctorTemplate<F, R, void, false, Params...>>(functionObject); } // note: both const and non-const function-objects are treated as static functors with isconst=false. 580 }; 581 } 582 583 template <class R, class O, class OO, class... Params> inline FunctorMemberPtr<O> createFunctor(R (O::*functionPointer)(Params...), OO* object) { return std::make_shared<FunctorTemplate<void, R, O, false, Params...>>(functionPointer, object); } ///< Creates a new FunctorMember with the given function-pointer and an assigned object 584 template <class R, class O, class OO, class... Params> inline FunctorMemberPtr<O> createFunctor(R (O::*functionPointer)(Params...) const, OO* object) { return std::make_shared<FunctorTemplate<void, R, O, true, Params...>>(functionPointer, object); } ///< Creates a new FunctorMember with the given function-pointer and an assigned object 585 586 template <class R, class O, class... Params> inline FunctorMemberPtr<O> createFunctor(R (O::*functionPointer)(Params...)) { return std::make_shared<FunctorTemplate<void, R, O, false, Params...>>(functionPointer); } ///< Creates a new FunctorMember with the given function-pointer 587 template <class R, class O, class... Params> inline FunctorMemberPtr<O> createFunctor(R (O::*functionPointer)(Params...) const) { return std::make_shared<FunctorTemplate<void, R, O, true, Params...>>(functionPointer); } ///< Creates a new FunctorMember with the given function-pointer 588 589 template <class R, class... Params> inline FunctorStaticPtr createFunctor(R (*functionPointer)(Params...)) { return std::make_shared<FunctorTemplate<void, R, void, false, Params...>>(functionPointer); } ///< Creates a new FunctorStatic with the given function-pointer 590 591 /** Take care that this functor does not outlive objects that have been captured by reference in a lambda. */ 592 template <class F> inline FunctorStaticPtr createFunctor(const F& functionObject) { return detail::CallableHelper<F>::create(functionObject, &F::operator()); } ///< Creates a new Functor with a callable object 608 593 } 609 594
Note: See TracChangeset
for help on using the changeset viewer.