Last active
January 30, 2016 16:20
-
-
Save jslee02/d4bd440df1f3c1a64bb9 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <memory> | |
#include <typeinfo> | |
#include <typeindex> | |
#include <map> | |
template <typename T> struct type {}; | |
class Addon {}; | |
class Addon1 : public Addon {}; | |
class Derived1 : public Addon1 {}; | |
class Addon2 : public Addon {}; | |
class Derived2 : public Addon2 {}; | |
class AddonManager | |
{ | |
public: | |
using AddonMap = std::map< std::type_index, std::unique_ptr<Addon> >; | |
using SpecAddonMap = std::map< std::type_index, std::pair< std::unique_ptr<Addon>, const bool> >; | |
template <class T> | |
bool isSpecializedFor() | |
{ | |
SpecAddonMap::iterator itSpec = mSpecAddonMap.find( typeid(T) ); | |
const bool foundInSpecMap = itSpec != mSpecAddonMap.end(); | |
if (foundInSpecMap) | |
return true; | |
return false; | |
} | |
template <class T> | |
bool remove() | |
{ | |
AddonMap::iterator it = mAddonMap.find( typeid(T) ); | |
const bool found = it != mAddonMap.end(); | |
if (found) | |
{ | |
mAddonMap.erase(it); | |
return true; | |
} | |
SpecAddonMap::iterator itSpec = mSpecAddonMap.find( typeid(T) ); | |
const bool foundInSpecMap = itSpec != mSpecAddonMap.end(); | |
if (foundInSpecMap && itSpec->second.second) | |
{ | |
itSpec->second.first = nullptr; | |
return true; | |
} | |
return false; | |
} | |
protected: | |
AddonMap mAddonMap; | |
SpecAddonMap mSpecAddonMap; | |
}; | |
template <class... OtherSpecAddonPairs> | |
class SpecializedAddonManager { }; | |
template <class AddonPair> | |
class SpecializedAddonManager<AddonPair> : public virtual AddonManager | |
{ | |
public: | |
using SpecialAddon = typename AddonPair::first_type; | |
using OptionalityType = typename AddonPair::second_type; | |
SpecializedAddonManager() | |
{ | |
_registerAddon(OptionalityType()); | |
} | |
template <typename T> | |
void _registerAddon(T) | |
{ | |
using SpecAddonMapKeyT = std::pair< std::unique_ptr<Addon>, const bool>; | |
using SpecAddonMapT = std::pair< std::type_index, SpecAddonMapKeyT >; | |
mSpecAddonMap.insert(SpecAddonMapT(typeid( SpecialAddon ), SpecAddonMapKeyT(nullptr, false))); | |
mSpecAddonIterator = mSpecAddonMap.find(typeid( SpecialAddon )); | |
} | |
void _registerAddon(std::true_type) | |
{ | |
using SpecAddonMapKeyT = std::pair< std::unique_ptr<Addon>, const bool>; | |
using SpecAddonMapT = std::pair< std::type_index, SpecAddonMapKeyT >; | |
mSpecAddonMap.insert(SpecAddonMapT(typeid( SpecialAddon ), SpecAddonMapKeyT(nullptr, true))); | |
mSpecAddonIterator = mSpecAddonMap.find(typeid( SpecialAddon )); | |
} | |
template <typename T> | |
bool isSpecializedFor() { return _isSpecializedFor(type<T>()); } | |
template <typename T> | |
bool _isSpecializedFor(type<T>) { return false; } | |
bool _isSpecializedFor(type<SpecialAddon>) { return true; } | |
template <typename T> | |
bool isOptional() { return _isOptional(type<T>(), OptionalityType()); } | |
template <typename T, typename U> | |
bool _isOptional(type<T>, U) { return false; } | |
bool _isOptional(type<typename AddonPair::first_type>, std::true_type) | |
{ | |
return true; | |
} | |
bool _isOptional(type<typename AddonPair::first_type>, std::false_type) | |
{ | |
return false; | |
} | |
template <class T> | |
bool remove() | |
{ | |
return _remove(type<T>(), OptionalityType()); | |
} | |
template <typename T, typename U> | |
bool _remove(type<T>, U) | |
{ | |
return AddonManager::remove<T>(); | |
} | |
bool _remove(type<SpecialAddon>, std::true_type) | |
{ | |
mSpecAddonIterator->second.first = nullptr; | |
return true; | |
} | |
bool _remove(type<SpecialAddon>, std::false_type) | |
{ | |
// not allowed to remove | |
return false; | |
} | |
protected: | |
AddonManager::SpecAddonMap::iterator mSpecAddonIterator; | |
}; | |
template <class... OtherBases> | |
class AddonManagerJoiner { }; | |
template <class Base1> | |
class AddonManagerJoiner<Base1> : public Base1 { }; | |
template <class Base1, class Base2> | |
class AddonManagerJoiner<Base1, Base2> : public Base1, public Base2 | |
{ | |
public: | |
template <class T> | |
bool remove() | |
{ | |
if(Base1::template isSpecializedFor<T>()) | |
return Base1::template remove<T>(); | |
return Base2::template remove<T>(); | |
} | |
template <class T> | |
bool isSpecializedFor() | |
{ | |
return Base1::template isSpecializedFor<T>() | |
|| Base2::template isSpecializedFor<T>(); | |
} | |
}; | |
class DerivedSpecializedAddonManager : public SpecializedAddonManager<std::pair<Addon1, std::true_type>> {}; | |
class JointAddon : public Addon {}; | |
class RevoluteJointAddon : public Addon {}; | |
class PrismaticJointAddon : public Addon {}; | |
class Joint : public virtual AddonManager {}; | |
class RevoluteJoint : | |
public AddonManagerJoiner< | |
Joint, | |
SpecializedAddonManager<std::pair<RevoluteJointAddon, std::false_type>>> | |
{}; | |
class PrismaticJoint : | |
public AddonManagerJoiner< | |
Joint, | |
SpecializedAddonManager<std::pair<PrismaticJointAddon, std::true_type>>> | |
{}; | |
int main(int argc, char *argv[]) | |
{ | |
using OptionalDerivedSpecializedAddonManager = SpecializedAddonManager<std::pair<Addon1, std::true_type>>; | |
using NotOptionalDerivedSpecializedAddonManager = SpecializedAddonManager<std::pair<Addon1, std::false_type>>; | |
OptionalDerivedSpecializedAddonManager optionalManager; | |
std::cout << optionalManager.isOptional<Addon1>() << std::endl; // 1 | |
std::cout << optionalManager.isOptional<Addon2>() << std::endl; // 0 | |
std::cout << optionalManager.isOptional<int>() << std::endl; // 0 | |
std::cout << optionalManager.isOptional<Derived1>() << std::endl; // 0 | |
std::cout << optionalManager.isOptional<Derived2>() << std::endl; // 0 | |
NotOptionalDerivedSpecializedAddonManager notOptionalManager; | |
std::cout << notOptionalManager.isOptional<Addon1>() << std::endl; // 0 | |
SpecializedAddonManager<std::pair<Addon1, std::true_type>> derived; | |
std::cout << derived.isOptional<Addon1>() << std::endl; // 1 | |
std::cout << derived.isOptional<Addon2>() << std::endl; // 0 | |
std::cout << derived.isOptional<float>() << std::endl; // 0 | |
std::cout << derived.isOptional<Derived1>() << std::endl; // 0 | |
std::cout << derived.isOptional<Derived2>() << std::endl; // 0 | |
Joint* joint = nullptr; | |
std::unique_ptr<RevoluteJoint> revJoint(new RevoluteJoint()); | |
std::unique_ptr<PrismaticJoint> priJoint(new PrismaticJoint()); | |
std::cout << std::endl; | |
// std::cout << revJoint->isSpecializedFor<JointAddon>() << std::endl; // 1 | |
std::cout << revJoint->isSpecializedFor<RevoluteJointAddon>() << std::endl; // 1 | |
std::cout << revJoint->isSpecializedFor<PrismaticJointAddon>() << std::endl; // 0 | |
std::cout << std::endl; | |
// std::cout << priJoint->isSpecializedFor<JointAddon>() << std::endl; // 1 | |
std::cout << priJoint->isSpecializedFor<RevoluteJointAddon>() << std::endl; // 0 | |
std::cout << priJoint->isSpecializedFor<PrismaticJointAddon>() << std::endl; // 1 | |
joint = static_cast<Joint*>(revJoint.get()); | |
std::cout << std::endl; | |
// std::cout << joint->isSpecializedFor<JointAddon>() << std::endl; // 0 | |
std::cout << joint->isSpecializedFor<RevoluteJointAddon>() << std::endl; // 1 | |
std::cout << joint->isSpecializedFor<PrismaticJointAddon>() << std::endl; // 0 | |
joint = static_cast<Joint*>(priJoint.get()); | |
std::cout << std::endl; | |
// std::cout << joint->isSpecializedFor<JointAddon>() << std::endl; // 0 | |
std::cout << joint->isSpecializedFor<RevoluteJointAddon>() << std::endl; // 0 | |
std::cout << joint->isSpecializedFor<PrismaticJointAddon>() << std::endl; // 1 | |
std::cout << std::endl; | |
// std::cout << revJoint->remove<JointAddon>() << std::endl; // 0 | |
std::cout << revJoint->remove<RevoluteJointAddon>() << std::endl; // 0 | |
std::cout << revJoint->remove<PrismaticJointAddon>() << std::endl; // 0 | |
std::cout << std::endl; | |
// std::cout << priJoint->remove<JointAddon>() << std::endl; // 0 | |
std::cout << priJoint->remove<RevoluteJointAddon>() << std::endl; // 0 | |
std::cout << priJoint->remove<PrismaticJointAddon>() << std::endl; // 1 | |
joint = static_cast<Joint*>(revJoint.get()); | |
std::cout << std::endl; | |
// std::cout << joint->remove<JointAddon>() << std::endl; // 0 | |
std::cout << joint->remove<RevoluteJointAddon>() << std::endl; // 0 | |
std::cout << joint->remove<PrismaticJointAddon>() << std::endl; // 0 | |
joint = static_cast<Joint*>(priJoint.get()); | |
std::cout << std::endl; | |
// std::cout << joint->remove<JointAddon>() << std::endl; // 0 | |
std::cout << joint->remove<RevoluteJointAddon>() << std::endl; // 0 | |
std::cout << joint->remove<PrismaticJointAddon>() << std::endl; // 1 | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment