Skip to content

Instantly share code, notes, and snippets.

@jslee02
Last active January 30, 2016 16:20
Show Gist options
  • Save jslee02/d4bd440df1f3c1a64bb9 to your computer and use it in GitHub Desktop.
Save jslee02/d4bd440df1f3c1a64bb9 to your computer and use it in GitHub Desktop.
#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