#ifndef ANY_H
#define ANY_H
#include <typeinfo>
namespace _notYourNp
{
struct BaseHolder
{
BaseHolder()
{}
virtual ~BaseHolder()
{}
virtual BaseHolder* clone() = 0;
};
template <class T>
struct Holder : BaseHolder
{
Holder(const T& type)
: m_Content(type)
{}
~Holder()
{
}
BaseHolder* clone()
{
BaseHolder* tmpHolder = new Holder<T>(m_Content);
return tmpHolder;
}
T m_Content;
};
}
namespace exception
{
class bad_cast_any
{};
}
class Any
{
public:
Any()
: m_Content(0), m_Type(const_cast<std::type_info*>(&typeid(int)))
{}
~Any()
{
if (0 != m_Content)
{
delete m_Content;
}
}
template <class T>
operator T()
{
if (const_cast<std::type_info*>(&typeid(T)) != m_Type)
{
throw exception::bad_cast_any();
}
return static_cast<_notYourNp::Holder<T>*>(m_Content)->m_Content;
}
template<class T>
Any(const T& value)
: m_Content(0), m_Type(const_cast<std::type_info*>(&typeid(T)))
{
if(0 == m_Content)
{
m_Content = new _notYourNp::Holder<T>(value);
}
if (const_cast<std::type_info*>(&typeid(T)) != m_Type)
{
m_Type = const_cast<std::type_info*>(&typeid(T));
if (0 != m_Content)
{
delete m_Content;
}
m_Content = new _notYourNp::Holder<T>(value);
}
else
{
static_cast<_notYourNp::Holder<T>*>(m_Content)->m_Content = value;
}
}
Any(const Any& A)
: m_Content(0), m_Type(0)
{
if (0 != m_Content)
{
delete m_Content;
}
m_Content = A.m_Content->clone();
m_Type = A.m_Type;
}
template<class T>
T& operator = (const T& value)
{
if(0 == m_Content)
{
m_Content = new _notYourNp::Holder<T>(value);
}
if (const_cast<std::type_info*>(&typeid(T)) != m_Type)
{
m_Type = const_cast<std::type_info*>(&typeid(T));
if (0 != m_Content)
{
delete m_Content;
}
m_Content = new _notYourNp::Holder<T>(value);
}
else
{
static_cast<_notYourNp::Holder<T>*>(m_Content)->m_Content = value;
}
return static_cast<_notYourNp::Holder<T>*>(m_Content)->m_Content;
}
Any& operator = (const Any& value)
{
if (0 != m_Content && value.m_Type != m_Type)
{
delete m_Content;
}
m_Content = value.m_Content->clone();
m_Type = value.m_Type;
return *this;
}
template<class T>
T& get()
{
if (const_cast<std::type_info*>(&typeid(T)) != m_Type)
{
throw exception::bad_cast_any();
}
return static_cast<_notYourNp::Holder<T>*>(m_Content)->m_Content;
}
private:
std::type_info* m_Type;
_notYourNp::BaseHolder* m_Content;
};
template<class T>
T any_get(Any& any)
{
return any.get<T>();
}
template<class from, class to>
to any_cast(Any& any)
{
return static_cast<to>(static_cast<from>(any));
}
#endif
This is my try of an Any
class. I would like to have some opinions about it.
Maybe I can answer one questions about the _notYourNp
namespace before:
I just used it to hide the holder structs from the user and I didn't wanted them in my any class itself (so the name makes no sense --> not your namespace private). I know it's not the best idea I'm working on a better one, and yes I took some ideas from any (Like the name any and the naming any_cast<>
).
I hope for some ideas, opinions (also bad ones if there are some), but please, if you bring criticism, then only constructive (and yes throw it away is also constructive criticism).
I tried it on vc10, 13 and the cpp droid compiler for Android.
As accurate as I can measure it (by using int = time start //Code\ time stop)
it is surprising fast compared to boost::any
, I don't know why maybe there is a mistake anywhere.
Usage example:
int main()
{
Any var;
var = 5;
int i = var;
double d = any_cast<int, double>(var);
std::vector<Any> v;
v.push_back(5);
int z = v.at(0);
return 0;
}
EDIT***** Additional here is how I measured the speed for assigning and reading from my any (not very accurate how I already wrote, but enough to get a relation)
int placeholder;
double otherPlaceholder;
clock_t start, end;
double cpu_time_used;
start = clock();
for (unsigned int i = 0; RUNTIMES > i; ++i)
{
placeholder = any; //bzw for boost: placeholder = boost::any_cast<int>(any);
//and for boost::variant: boost::get<int(variant);
}
//measuring the speed for getting the value from any
//for (unsigned int i = 0; RUNTIMES > i; ++i)
//{
// any = placeholder;
// any = otherPlaceholder;
//}
end = clock();
cpu_time_used = ((double)(end - start)) / CLOCKS_PER_SEC;
//the 3000000 or 6000000 to get a 0.xx value
double timing = (cpu_time_used / RUNTIMES) / 3000000
//double timing = (cpu_time_used / RUNTIMES) / 6000000 for reading speed
The performance testing code is not written by me! So no questions about it to me please (https://stackoverflow.com/questions/795827/testing-the-performance-of-a-c-app).
And this are the results saved in a log.txt
mango::Any assign reference timing: 0.8075 x 10 power( - 6 ) seconds
mango::Any get value reference timing: 0.0466667 x 10 power( - 6 ) seconds
boost::any assign reference timing: 0.931667 x 10 power( - 6 ) seconds
boost::any get value reference timing: 0.353333 x 10 power( - 6 ) seconds
boost::variant assign reference timing: 2.0225 x 10 power( - 6 ) seconds
boost::variant get value reference timing: 0.465 x 10 power( - 6 ) seconds
And here is my newer version of Any
#ifndef ANY_H
#define ANY_H
#include <typeinfo>
namespace mango
{
namespace exception
{
class bad_cast
{};
}
namespace detail
{
template <class T> void killContent(void* target);
template <class T> void reproduceAny(void* target, void*& pool);
}
class Any
{
public:
Any()
: m_Content(new int), m_ContentType(const_cast<std::type_info*>(&typeid(int))), kill(&detail::killContent<int>), reproduceAnyContent(&detail::reproduceAny<int>)
{}
~Any()
{
if (nullptr != m_Content)
{
kill(m_Content);
}
}
template<class T>
operator T&()
{
if (const_cast<std::type_info*>(&typeid(T)) != m_ContentType)
{
throw exception::bad_cast_any();
}
return *static_cast<T*>(m_Content);
}
template<class T>
Any(const T& value)
: m_Content(new T(value)), m_ContentType(const_cast<std::type_info*>(&typeid(T))), kill(&detail::killContent<T>), reproduceAnyContent(&detail::reproduceAny<T>)
{
if (nullptr == m_Content)
{
m_Content = new T(value);
kill = &detail::killContent<T>;
reproduceAnyContent = &detail::reproduceAny<T>;
}
if (const_cast<std::type_info*>(&typeid(T)) != m_ContentType)
{
m_ContentType = const_cast<std::type_info*>(&typeid(T));
if (nullptr != m_Content)
{
kill(m_Content);
}
m_Content = new T(value);
kill = &detail::killContent<T>;
reproduceAnyContent = &detail::reproduceAny<T>;
}
else
{
*static_cast<T*>(m_Content) = value;
}
}
Any(const Any& C)
: m_Content(nullptr), m_ContentType(nullptr), kill(nullptr), reproduceAnyContent(nullptr)
{
if (nullptr != m_Content)
{
kill(m_Content);
}
reproduceAnyContent(C.m_Content, m_Content);
kill = C.kill;
reproduceAnyContent = C.reproduceAnyContent;
m_ContentType = C.m_ContentType;
}
template<class T>
T& operator = (const T& value)
{
if (nullptr == m_Content)
{
m_Content = new T(value);
kill = &detail::killContent<T>;
reproduceAnyContent = &detail::reproduceAny<T>;
}
if (const_cast<std::type_info*>(&typeid(T)) != m_ContentType)
{
m_ContentType = const_cast<std::type_info*>(&typeid(T));
if (nullptr != m_Content)
{
kill(m_Content);
}
m_Content = new T(value);
kill = &detail::killContent<T>;
reproduceAnyContent = &detail::reproduceAny<T>;
}
else
{
*static_cast<T*>(m_Content) = value;
}
return *static_cast<T*>(m_Content);
}
Any& operator = (const Any& value)
{
if (nullptr != m_Content)
{
kill(m_Content);
}
reproduceAnyContent(value.m_Content, m_Content);
kill = value.kill;
reproduceAnyContent = value.reproduceAnyContent;
m_ContentType = value.m_ContentType;
return *this;
}
template<class T>
T& get()
{
if (const_cast<std::type_info*>(&typeid(T)) != m_ContentType)
{
throw exception::bad_cast_any();
}
return *static_cast<T*>(m_Content);
}
private:
void* m_Content;
std::type_info* m_ContentType;
void(*kill)(void* target);
void(*reproduceAnyContent)(void* target, void*& pool);
};
template<class T>
T any_get(Any& any)
{
return any.get<T>();
}
template<class from, class to>
to any_cast(Any& any)
{
return static_cast<to>(static_cast<from>(any));
}
namespace detail
{
template <class T>
void killContent(void* target)
{
delete static_cast<T*>(target);
}
template <class T>
void reproduceAny(void* target, void*& pool)
{
pool = new T(*static_cast<T*>(target));
}
}
}
#endif //Any_H