| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348 |
- #ifndef ANKI_UTIL_VARIANT_H
- #define ANKI_UTIL_VARIANT_H
- #include "anki/util/Visitor.h"
- #include "anki/util/Exception.h"
- #include <iosfwd>
- #include <memory>
- namespace anki {
- /// @addtogroup util
- /// @{
- /// @addtogroup patterns
- /// @{
- // Forwards
- template<typename Data, typename VariantBase>
- class VariantDerived;
- template<typename... Types>
- class VariantBase;
- /// The variant base class
- template<typename... Types>
- class VariantBase:
- public Visitable<VariantDerived<Types, VariantBase<Types...>>...>
- {
- public:
- typedef Visitable<VariantDerived<Types, VariantBase<Types...>>...> Base;
- typedef VariantBase<Types...> Self;
- typedef typename BaseType::ConstVisitor ConstVisitor;
- typedef typename BaseType::MutableVisitor MutableVisitor;
- static const int TEMPLATE_PARAMETERS_NUM = sizeof...(Types);
- /// Default constructor
- VariantBase(int typeId_)
- : typeId(typeId_)
- {}
- virtual ~VariantBase()
- {}
- uint getTypeId() const
- {
- return typeId;
- }
- /// Get the parameter's value. It throws if the @a Data is incompatible
- template<typename Data>
- const Data& get() const
- {
- checkValue<Data>();
- return static_cast<const VariantDerived<Data, SelfType>&>(*this).get();
- }
- /// Generic setter. It throws if the @a Data is incompatible
- template<typename Data>
- void set(const Data& x)
- {
- checkValue<Data>();
- static_cast<VariantDerived<Data, SelfType>&>(*this).set(x);
- }
- /// Compare the derived classes
- virtual bool equal(const SelfType& b) const = 0;
- /// Copy the derived classes
- virtual void copy(const SelfType& b) = 0;
- /// Check if two derived are the same type
- bool areSameType(const SelfType& b) const
- {
- return typeId == b.typeId;
- }
- /// Print
- friend std::ostream& operator<<(std::ostream& s, const SelfType& x)
- {
- PrintVisitor v(s);
- x.accept(v);
- return s;
- }
- protected:
- static constexpr char* INCOMPATIBLES_ERR = "Incompatible parameter types";
- private:
- template<typename... Types_>
- struct PrintVisitor;
- template<typename First, typename... Types_>
- struct PrintVisitor<First, Types_...>: PrintVisitor<Types_...>
- {
- PrintVisitor(std::ostream& stream)
- : PrintVisitor<Types_...>(stream)
- {}
- void visit(const First& x)
- {
- PrintVisitor<Types_...>::stream << x;
- }
- };
- template<typename First>
- struct PrintVisitor<First>: ConstVisitorType
- {
- std::ostream& stream;
- PrintVisitor(std::ostream& stream_)
- : stream(stream_)
- {}
- void visit(const First& x)
- {
- stream << x;
- }
- };
- using PrintVisitor = PrintVisitor<VariantDerived<Types, SelfType>...>;
- uint typeId; ///< type ID
- /// Use const struff to check if @a Data is compatible with this
- template<typename Data>
- void checkValue() const
- {
- typedef VariantDerived<Data, SelfType> Vd;
- const int id = BaseType::template getTypeId<Vd>();
- if(id != typeId)
- {
- throw ANKI_EXCEPTION(INCOMPATIBLES_ERR);
- }
- }
- };
- /// VariantDerived template class. Using the @a TData and the @a TVariantBase
- /// it constructs a variant class
- template<typename TData, typename TVariantBase>
- class VariantDerived: public TVariantBase
- {
- public:
- typedef TData Data;
- typedef TVariantBase Base;
- typedef VariantDerived<DataType, BaseType> Self;
- typedef typename BaseType::ConstVisitor ConstVisitor;
- typedef typename BaseType::MutableVisitor MutableVisitor;
- static const int TYPE_ID =
- BaseType::BaseType::template getTypeId<SelfType>();
- /// Constructor
- VariantDerived()
- : BaseType(TYPE_ID), data(DataType())
- {}
- /// Constructor
- VariantDerived(const DataType& x)
- : BaseType(TYPE_ID), data(x)
- {}
- /// Copy constructor
- VariantDerived(const SelfType& b)
- : BaseType(TYPE_ID), data(b.data)
- {}
- /// @name Accessors
- /// @{
- void set(const DataType& x)
- {
- data = x;
- }
- const DataType& get() const
- {
- return data;
- }
- /// @}
- /// Compare
- bool operator==(const SelfType& b) const
- {
- return data == b.data;
- }
- /// Implements the VariantBase::equal
- bool equal(const BaseType& b) const
- {
- if(!BaseType::areSameType(b))
- {
- throw ANKI_EXCEPTION(BaseType::INCOMPATIBLES_ERR);
- }
- return *this == static_cast<const SelfType&>(b);
- }
- /// Implements the VariantBase::copy
- void copy(const BaseType& b)
- {
- if(!BaseType::areSameType(b))
- {
- throw ANKI_EXCEPTION(BaseType::INCOMPATIBLES_ERR);
- }
- data = static_cast<const SelfType&>(b).data;
- }
- /// Implements VariantBase::accept
- void accept(ConstVisitorType& v) const
- {
- v.visit(*this);
- }
- /// Implements VariantBase::accept
- void accept(MutableVisitorType& v)
- {
- v.visit(*this);
- }
- /// Print
- friend std::ostream& operator<<(std::ostream& s, const SelfType& x)
- {
- s << x.data;
- return s;
- }
- private:
- DataType data; ///< The data
- };
- /// XXX
- /// @note It is no possible to have default constructor because we cannot have
- /// template default constructor
- template<typename... Types>
- class Variant
- {
- public:
- typedef Variant<Types...> SelfType;
- typedef VariantBase<Types...> VariantBaseType;
- /// Default constructor
- Variant()
- {}
- /// Constructor with data
- template<typename Data>
- explicit Variant(const Data& x)
- : ptr(new VariantDerived<Data, VariantBaseType>(x))
- {}
- /// Copy constructor
- Variant(const SelfType& x)
- {
- CopyVisitorType v(*this);
- x.ptr->accept(v);
- }
- ~Variant()
- {}
- /// Get the parameter's value. It throws if the @a Data is incompatible
- template<typename Data>
- const Data& get() const
- {
- return ptr->get<Data>();
- }
- /// Generic setter. It throws if the @a Data is incompatible
- template<typename Data>
- void set(const Data& x)
- {
- ptr->set<Data>(x);
- }
- /// Copy
- SelfType& operator=(const SelfType& b)
- {
- ptr->copy(*b.ptr);
- return *this;
- }
- /// Compare
- bool operator==(const SelfType& b) const
- {
- return ptr->equal(*b.ptr);
- }
- /// set value
- template<typename Data>
- SelfType& operator=(const Data& b)
- {
- set<Data>(b);
- return *this;
- }
- friend std::ostream& operator<<(std::ostream& s, const SelfType& x)
- {
- s << *x.ptr;
- return s;
- }
- private:
- // Forward
- template<typename... Types_>
- struct CopyVisitor;
- /// Visitor used to copy the data of a VariantBase to a Variant
- template<typename First, typename... Types_>
- struct CopyVisitor<First, Types_...>: CopyVisitor<Types_...>
- {
- using CopyVisitor<Types_...>::visit;
- CopyVisitor(SelfType& a)
- : CopyVisitor<Types_...>(a)
- {}
- void visit(const First& b)
- {
- CopyVisitor<Types_...>::a.ptr.reset(new First(b.get()));
- }
- };
- // Specialized for one
- template<typename First>
- struct CopyVisitor<First>: VariantBaseType::ConstVisitorType
- {
- SelfType& a;
- CopyVisitor(SelfType& a_)
- : a(a_)
- {}
- void visit(const First& b)
- {
- a.ptr.reset(new First(b.get()));
- }
- };
- typedef CopyVisitor<VariantDerived<Types, VariantBaseType>...>
- CopyVisitorType;
- /// The only data member, a pointer to a VariantBase class
- std::unique_ptr<VariantBaseType> ptr;
- };
- /// @}
- /// @}
- } // end namespace anki
- #endif
|