2010-08-09 13:28:56 +00:00
|
|
|
#ifndef NALL_ANY_HPP
|
|
|
|
#define NALL_ANY_HPP
|
|
|
|
|
|
|
|
#include <typeinfo>
|
2012-06-18 10:13:51 +00:00
|
|
|
#include <nall/traits.hpp>
|
2010-08-09 13:28:56 +00:00
|
|
|
|
|
|
|
namespace nall {
|
2013-05-02 11:25:45 +00:00
|
|
|
|
|
|
|
struct any {
|
|
|
|
bool empty() const { return container; }
|
2013-07-29 09:42:45 +00:00
|
|
|
void reset() { if(container) { delete container; container = nullptr; } }
|
|
|
|
|
|
|
|
const std::type_info& type() const {
|
|
|
|
return container ? container->type() : typeid(void);
|
|
|
|
}
|
2013-05-02 11:25:45 +00:00
|
|
|
|
|
|
|
template<typename T> any& operator=(const T& value) {
|
|
|
|
typedef typename type_if<
|
|
|
|
std::is_array<T>::value,
|
|
|
|
typename std::remove_extent<typename std::add_const<T>::type>::type*,
|
|
|
|
T
|
|
|
|
>::type auto_t;
|
|
|
|
|
|
|
|
if(type() == typeid(auto_t)) {
|
|
|
|
static_cast<holder<auto_t>*>(container)->value = (auto_t)value;
|
|
|
|
} else {
|
|
|
|
if(container) delete container;
|
|
|
|
container = new holder<auto_t>((auto_t)value);
|
2010-08-09 13:28:56 +00:00
|
|
|
}
|
|
|
|
|
2013-05-02 11:25:45 +00:00
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2013-07-29 09:42:45 +00:00
|
|
|
any& operator=(const any& source) {
|
|
|
|
if(container) { delete container; container = nullptr; }
|
|
|
|
if(source.container) container = source.container->copy();
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
any& operator=(any&& source) {
|
|
|
|
if(container) delete container;
|
|
|
|
container = source.container;
|
|
|
|
source.container = nullptr;
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
2013-05-02 11:25:45 +00:00
|
|
|
any() = default;
|
2013-07-29 09:42:45 +00:00
|
|
|
any(const any& source) { operator=(source); }
|
|
|
|
any(any&& source) { operator=(std::move(source)); }
|
2013-05-02 11:25:45 +00:00
|
|
|
template<typename T> any(const T& value) { operator=(value); }
|
2013-07-29 09:42:45 +00:00
|
|
|
~any() { reset(); }
|
2013-05-02 11:25:45 +00:00
|
|
|
|
|
|
|
private:
|
|
|
|
struct placeholder {
|
|
|
|
virtual const std::type_info& type() const = 0;
|
2013-07-29 09:42:45 +00:00
|
|
|
virtual placeholder* copy() const = 0;
|
|
|
|
virtual ~placeholder() {}
|
2010-08-09 13:28:56 +00:00
|
|
|
};
|
2013-05-02 11:25:45 +00:00
|
|
|
placeholder* container = nullptr;
|
2010-08-09 13:28:56 +00:00
|
|
|
|
2013-05-02 11:25:45 +00:00
|
|
|
template<typename T> struct holder : placeholder {
|
|
|
|
T value;
|
|
|
|
const std::type_info& type() const { return typeid(T); }
|
2013-07-29 09:42:45 +00:00
|
|
|
placeholder* copy() const { return new holder(value); }
|
2013-05-02 11:25:45 +00:00
|
|
|
holder(const T& value) : value(value) {}
|
|
|
|
};
|
2010-08-09 13:28:56 +00:00
|
|
|
|
2013-05-02 11:25:45 +00:00
|
|
|
template<typename T> friend T any_cast(any&);
|
|
|
|
template<typename T> friend T any_cast(const any&);
|
|
|
|
template<typename T> friend T* any_cast(any*);
|
|
|
|
template<typename T> friend const T* any_cast(const any*);
|
|
|
|
};
|
|
|
|
|
|
|
|
template<typename T> T any_cast(any& value) {
|
|
|
|
typedef typename std::remove_reference<T>::type nonref;
|
|
|
|
if(value.type() != typeid(nonref)) throw;
|
|
|
|
return static_cast<any::holder<nonref>*>(value.container)->value;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T> T any_cast(const any& value) {
|
|
|
|
typedef const typename std::remove_reference<T>::type nonref;
|
|
|
|
if(value.type() != typeid(nonref)) throw;
|
|
|
|
return static_cast<any::holder<nonref>*>(value.container)->value;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T> T* any_cast(any* value) {
|
|
|
|
if(!value || value->type() != typeid(T)) return nullptr;
|
|
|
|
return &static_cast<any::holder<T>*>(value->container)->value;
|
|
|
|
}
|
|
|
|
|
|
|
|
template<typename T> const T* any_cast(const any* value) {
|
|
|
|
if(!value || value->type() != typeid(T)) return nullptr;
|
|
|
|
return &static_cast<any::holder<T>*>(value->container)->value;
|
|
|
|
}
|
2010-08-09 13:28:56 +00:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|