/*
Ousía
Copyright (C) 2014, 2015 Benjamin Paaßen, Andreas Stöckel
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
/**
* @file Rtti.hpp
*
* Classes used for storing runtime type information (RTTI). RTTI is used to
* resolve objects of a certain type in the object graph and to attach
* information that should be accessible to the script engine.
*
* Why is this needed? C++ provides the typeid operator to
* retrieve a reference at an internal table associated with type information
* for the given class. However, there is no native way for attaching additonal
* information to this type information table. Additional information we need to
* store is the inheritance graph (which cannot easily be extracted from C++)
* and information relevant for script engines (such as a list of methods and
* properties). One could of course store information about the type within each
* instance of this type, however when managing thousands of objects
* this would create a significant overhead.
*
* How to use: The Rtti class allows to attach information to a certain
* C++ class. To do so, create a global constant of the type Rtti in the
* source file associated with the type declaration, where T is the type you
* want to register. As the type must only be registered once, you must not
* declare the variable as "static" in the header file (this would register it
* whever the header is included). If you want to access the global constant
* from other Rtti definitions (as parent), create a forward declaration
* in the header file. If you want to access the RTTI of a certain object or
* type, use the global typeOf() function (however, don't use it
* within global variable initializations).
*
* Example:
* In the header file:
* \code{.hpp}
* // Only needed if the type needs to be accessed
* // from other compilation units!
* extern const Rtti MyType_Rtti;
* \endcode
* In the source file:
* \code{.cpp}
* const Rtti MyType_Rtti{"MyType", {&MyOtherType_Rtti}, [...]};
* \endcode
*
* @author Andreas Stöckel (astoecke@techfak.uni-bielefeld.de)
*/
#ifndef _OUSIA_RTTI_HPP_
#define _OUSIA_RTTI_HPP_
#include
#include
#include
#include
namespace ousia {
class RttiBase;
/**
* Helper class used to globally store and access the runtime type information.
*/
class RttiStore {
private:
/**
* Function used internally to access the static map storing all registered
* native types and their corresponding type information.
*/
static std::unordered_map &table();
public:
/**
* Registers the given pointer to the RttiBase class in the RTTI table. Does
* not override information for already registered types.
*
* @param native is a reference at the native type information provided
* by the compiler.
* @param rtti is a pointer pointing at the type information that should be
* stored for this type.
*/
static void store(const std::type_info &native, const RttiBase *rtti);
/**
* Looks up the type information stored for the given native type
* information.
*/
static const RttiBase &lookup(const std::type_info &native);
};
/**
* The Rtti class allows for attaching data to native types that can be accessed
* at runtime. This type information can e.g. be retrieved using the "type"
* method of the Managed class. This system is used for attaching human readable
* names, parent types and script engine functionality. Use the Rtti class for
* convenient registration of type information.
*/
class RttiBase {
private:
/**
* Set containing references to the parent types.
*/
const std::vector parents;
public:
/**
* Human readable name associated with the type.
*/
const std::string name;
/**
* Default constructor. Creates a Rtti instance with name "unknown"
* and no parents.
*/
RttiBase() : name("unknown") {}
/**
* Creates a new RttiBase instance and registers it in the global type
* table. Use the Rtti class for more convinient registration of type
* information.
*
* @param name is the name of the type.
* @param native is a reference at the native type information provided by
* the compiler.
* @param parents is a list of parent types.
*/
RttiBase(
std::string name, const std::type_info &native,
std::vector parents = std::vector{})
: parents(std::move(parents)), name(std::move(name))
{
RttiStore::store(native, this);
}
/**
* Returns true if this Rtti instance is the given type or has the
* given type as one of its parents.
*
* @param other is the other type for which the relation to this type
* should be checked.
*/
bool isa(const RttiBase &other) const;
};
/**
* The Rtti class allows for attaching data to native types that can be accessed
* at runtime. This type information can e.g. be retrieved using the "type"
* method of the Managed class. This system is used for attaching human
* readable names, parent types and script engine functionality.
*
* @tparam T is the class for which the type information should be registered.
*/
template
class Rtti : public RttiBase {
public:
/**
* Creates a new RttiBase instance and registers it in the global type
* table.
*
* @param name is the name of the type.
* @param parents is a list of parent types.
*/
Rtti(std::string name, const std::vector &parents =
std::vector{})
: RttiBase(name, typeid(T), parents)
{
}
};
/**
* Function that can be used to retrieve the RTTI information of a Managed
* object. Do not use this function in the initialization of global Rtti
* variables, use pointers at the other global variable instead (as the
* initialization order is not well defined).
*
* @tparam T is the C++ type for which the type information should be returned.
*/
template
inline const RttiBase &typeOf()
{
return RttiStore::lookup(typeid(T));
}
/**
* Function that can be used to retrieve the RTTI information of a Managed
* object. Do not use this function in the initialization of global Rtti
* variables, use pointers at the other global variable instead (as the
* initialization order is not well defined).
*
* @tparam T is the C++ type for which the type information should be returned.
* @param obj is a dummy object for which the type information should be
* returned.
*/
template
inline const RttiBase &typeOf(const T &obj)
{
return RttiStore::lookup(typeid(obj));
}
/**
* Struct defining static constants describing certain Variant types. These
* constants are used to e.g. define the type of function arguments while
* allowing for both primitive variant types and more complex variant types.
*/
struct RttiTypes {
/**
* Type of no particular color.
*/
static const RttiBase None;
/**
* Constant representing a variant int type.
*/
static const RttiBase Int;
/**
* Constant representing a variant double type.
*/
static const RttiBase Double;
/**
* Constant representing a variant string type.
*/
static const RttiBase String;
/**
* Constant representing a variant array type.
*/
static const RttiBase Array;
/**
* Constant representing a variant map type.
*/
static const RttiBase Map;
};
}
#endif /* _OUSIA_RTTI_HPP_ */