/* * (C) Copyright Christopher Diggins 2005 * (C) Copyright Pablo Aguilar 2005 * (C) Copyright Kevlin Henney 2001 * * Copyright (C) 2010-2011 IOhannes m zmölnig. forum::für::umläute. IEM. zmoelnig@iem.at * downloaded this code from http://www.codeproject.com/KB/cpp/dynamic_typing.aspx * changed namespace/defines "cdiggins" to something "gem" * * Distributed under the Boost Software License, Version 1.0. (See * accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) */ #ifndef GEM_ANY_HPP #define GEM_ANY_HPP #include "Gem/ExportDef.h" #ifdef _MSC_VER # pragma warning( push ) # pragma warning( disable: 4275 ) #endif #include #include #include #include //#define GEM_ANY_TYPEID_HACK namespace gem { struct GEM_EXTERN bad_any_cast : std::bad_cast { bad_any_cast(const std::type_info& src, const std::type_info& dest) : result(std::string("bad cast (")+src.name() + "->" + dest.name()+")") { } virtual ~bad_any_cast(void) #if __cplusplus <= 199711L throw() #endif { } virtual const char* what(void) const #if __cplusplus > 199711L noexcept #else throw() #endif { return result.c_str(); } const std::string result; }; namespace any_detail { // function pointer table struct fxn_ptr_table { const std::type_info& (*get_type)(void); void (*static_delete)(void**); void (*clone)(void* const*, void**); void (*move)(void* const*,void**); }; // static functions for small value-types template struct fxns { template struct type { static const std::type_info& get_type(void) { #if GEM_ANY_TYPEID_HACK const std::type_info&res=typeid(T); // the following is a dummy use of the type_info struct // to make the template engine work properly on OSX/10.9 static std::string _ = res.name(); return res; #else return typeid(T); #endif } static void static_delete(void** x) { reinterpret_cast(x)->~T(); } static void clone(void* const* src, void** dest) { new(dest) T(*reinterpret_cast(src)); } static void move(void* const* src, void** dest) { reinterpret_cast(dest)->~T(); *reinterpret_cast(dest) = *reinterpret_cast(src); } }; }; // static functions for big value-types (bigger than a void*) template<> struct fxns { template struct type { static const std::type_info& get_type(void) { #if GEM_ANY_TYPEID_HACK const std::type_info&res=typeid(T); return res; #else return typeid(T); #endif } static void static_delete(void** x) { delete(*reinterpret_cast(x)); } static void clone(void* const* src, void** dest) { *dest = new T(**reinterpret_cast(src)); } static void move(void* const* src, void** dest) { (*reinterpret_cast(dest))->~T(); **reinterpret_cast(dest) = **reinterpret_cast(src); } }; }; template struct get_table { static const bool is_small = sizeof(T) <= sizeof(void*); static fxn_ptr_table* get(void) { static fxn_ptr_table static_table = { fxns::template type::get_type , fxns::template type::static_delete , fxns::template type::clone , fxns::template type::move }; return &static_table; } }; struct empty { }; } // namespace any_detail struct GEM_EXTERN any { // structors template any(const T& x) : table(NULL), object(NULL) { table = any_detail::get_table::get(); #if defined(__GNUC__) && __GNUC__ >= 6 # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wplacement-new" #endif if (sizeof(T) <= sizeof(void*)) { new(&object) T(x); } else { object = new T(x); } #if defined(__GNUC__) && __GNUC__ >= 6 # pragma GCC diagnostic pop #endif } any(void) : table(NULL), object(NULL) { table = any_detail::get_table::get(); object = NULL; } any(const any& x) : table(NULL), object(NULL) { table = any_detail::get_table::get(); assign(x); } virtual ~any(void) { table->static_delete(&object); } // assignment any& assign(const any& x) { // are we copying between the same type? if (table == x.table) { // if so, we can avoid reallocation table->move(&x.object, &object); } else { reset(); x.table->clone(&x.object, &object); table = x.table; } return *this; } template any& assign(const T& x) { // are we copying between the same type? any_detail::fxn_ptr_table* x_table = any_detail::get_table::get(); if (table == x_table) { // if so, we can avoid deallocating and resuse memory #if defined(__GNUC__) && __GNUC__ >= 6 # pragma GCC diagnostic push # pragma GCC diagnostic ignored "-Wplacement-new" #endif if (sizeof(T) <= sizeof(void*)) { // create copy on-top of object pointer itself new(&object) T(x); } else { // create copy on-top of old version new(object) T(x); } } else { reset(); if (sizeof(T) <= sizeof(void*)) { // create copy on-top of object pointer itself new(&object) T(x); // update table pointer table = x_table; } else { object = new T(x); table = x_table; } #if defined(__GNUC__) && __GNUC__ >= 6 # pragma GCC diagnostic pop #endif } return *this; } // assignment operator template any& operator=(T const& x) { return assign(x); } any& operator=(const any& x) { return assign(x); } // utility functions any& swap(any& x) { std::swap(table, x.table); std::swap(object, x.object); return *this; } const std::type_info& get_type(void) const { return table->get_type(); } template const T& cast(void) const { if (!compatible()) { throw bad_any_cast(get_type(), typeid(T)); } if (sizeof(T) <= sizeof(void*)) { return *reinterpret_cast(&object); } else { return *reinterpret_cast(object); } } /// Returns true if the two types are the same. bool compatible(const any& x) const { return get_type() == x.get_type(); } /// Returns true if the two types are the same. template bool compatible() const { return (get_type() == typeid(T)); } // implicit casting is disabled by default #ifdef ANY_IMPLICIT_CASTING // automatic casting operator template operator T(void) const { return cast(); } #endif // implicit casting bool empty(void) const { return table == any_detail::get_table::get(); } void reset(void) { if (empty()) { return; } table->static_delete(&object); table = any_detail::get_table::get(); object = NULL; } // fields any_detail::fxn_ptr_table* table; void* object; }; // boost::any-like casting template T* any_cast(any* this_) { if (this_->get_type() != typeid(T)) { throw bad_any_cast(this_->get_type(), typeid(T)); } if (sizeof(T) <= sizeof(void*)) { return reinterpret_cast(&this_->object); } else { return reinterpret_cast(this_->object); } } template T const* any_cast(any const* this_) { return any_cast(const_cast(this_)); } template T const& any_cast(any const& this_) { return *any_cast(const_cast(&this_)); } #ifdef GEM_INTERNAL // Note: The "unsafe" versions of any_cast are not part of the // public interface (and hence protected by GEM_INTERNAL) and may // be removed at any time. They are required where we know what type // is stored in the any and can't use typeid() comparison, e.g., // when our types may travel across different shared libraries. template T* unsafe_any_cast(any* this_) { if (sizeof(T) <= sizeof(void*)) { return reinterpret_cast(&this_->object); } else { return reinterpret_cast(this_->object); } } template T const* unsafe_any_cast(any const* this_) { return unsafe_any_cast(const_cast(this_)); } template T const& unsafe_any_cast(any const& this_) { return *unsafe_any_cast(const_cast(&this_)); } #endif } #ifdef _MSC_VER # pragma warning( pop ) #endif #endif // GEM_ANY_HPP