338 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			338 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
		
			Executable File
		
	
	
	
	
| ///////////////////////////////////////////////////////////////////////////////
 | |
| /// \file domain.hpp
 | |
| /// Contains definition of domain\<\> class template and helpers for
 | |
| /// defining domains with a generator and a grammar for controlling
 | |
| /// operator overloading.
 | |
| //
 | |
| //  Copyright 2008 Eric Niebler. 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 BOOST_PROTO_DOMAIN_HPP_EAN_02_13_2007
 | |
| #define BOOST_PROTO_DOMAIN_HPP_EAN_02_13_2007
 | |
| 
 | |
| #include <boost/ref.hpp>
 | |
| #include <boost/type_traits/is_same.hpp>
 | |
| #include <boost/proto/proto_fwd.hpp>
 | |
| #include <boost/proto/generate.hpp>
 | |
| #include <boost/proto/detail/as_expr.hpp>
 | |
| #include <boost/proto/detail/deduce_domain.hpp>
 | |
| 
 | |
| #if defined(_MSC_VER)
 | |
| # pragma warning(push)
 | |
| # pragma warning(disable : 4714) // function 'xxx' marked as __forceinline not inlined
 | |
| #endif
 | |
| 
 | |
| namespace boost { namespace proto
 | |
| {
 | |
| 
 | |
|     namespace detail
 | |
|     {
 | |
|         struct not_a_generator
 | |
|         {};
 | |
| 
 | |
|         struct not_a_grammar
 | |
|         {};
 | |
| 
 | |
|         struct not_a_domain
 | |
|         {};
 | |
|     }
 | |
| 
 | |
|     namespace domainns_
 | |
|     {
 | |
|         /// \brief For use in defining domain tags to be used
 | |
|         /// with \c proto::extends\<\>. A \e Domain associates
 | |
|         /// an expression type with a \e Generator, and optionally
 | |
|         /// a \e Grammar.
 | |
|         ///
 | |
|         /// The Generator determines how new expressions in the
 | |
|         /// domain are constructed. Typically, a generator wraps
 | |
|         /// all new expressions in a wrapper that imparts
 | |
|         /// domain-specific behaviors to expressions within its
 | |
|         /// domain. (See \c proto::extends\<\>.)
 | |
|         ///
 | |
|         /// The Grammar determines whether a given expression is
 | |
|         /// valid within the domain, and automatically disables
 | |
|         /// any operator overloads which would cause an invalid
 | |
|         /// expression to be created. By default, the Grammar
 | |
|         /// parameter defaults to the wildcard, \c proto::_, which
 | |
|         /// makes all expressions valid within the domain.
 | |
|         ///
 | |
|         /// The Super declares the domain currently being defined
 | |
|         /// to be a sub-domain of Super. Expressions in sub-domains
 | |
|         /// can be freely combined with expressions in its super-
 | |
|         /// domain (and <I>its</I> super-domain, etc.).
 | |
|         ///
 | |
|         /// Example:
 | |
|         /// \code
 | |
|         /// template<typename Expr>
 | |
|         /// struct MyExpr;
 | |
|         ///
 | |
|         /// struct MyGrammar
 | |
|         ///   : or_< terminal<_>, plus<MyGrammar, MyGrammar> >
 | |
|         /// {};
 | |
|         ///
 | |
|         /// // Define MyDomain, in which all expressions are
 | |
|         /// // wrapped in MyExpr<> and only expressions that
 | |
|         /// // conform to MyGrammar are allowed.
 | |
|         /// struct MyDomain
 | |
|         ///   : domain<generator<MyExpr>, MyGrammar>
 | |
|         /// {};
 | |
|         ///
 | |
|         /// // Use MyDomain to define MyExpr
 | |
|         /// template<typename Expr>
 | |
|         /// struct MyExpr
 | |
|         ///   : extends<Expr, MyExpr<Expr>, MyDomain>
 | |
|         /// {
 | |
|         ///     // ...
 | |
|         /// };
 | |
|         /// \endcode
 | |
|         ///
 | |
|         template<
 | |
|             typename Generator // = default_generator
 | |
|           , typename Grammar   // = proto::_
 | |
|           , typename Super     // = no_super_domain
 | |
|         >
 | |
|         struct domain
 | |
|           : Generator
 | |
|         {
 | |
|             typedef Generator proto_generator;
 | |
|             typedef Grammar   proto_grammar;
 | |
|             typedef Super     proto_super_domain;
 | |
|             typedef domain    proto_base_domain;
 | |
| 
 | |
|             /// INTERNAL ONLY
 | |
|             typedef void proto_is_domain_;
 | |
| 
 | |
|             /// \brief A unary MonomorphicFunctionObject that turns objects into Proto
 | |
|             /// expression objects in this domain.
 | |
|             ///
 | |
|             /// The <tt>as_expr\<\></tt> function object turns objects into Proto expressions, if
 | |
|             /// they are not already, by making them Proto terminals held by value if
 | |
|             /// possible. Objects that are already Proto expressions are left alone.
 | |
|             ///
 | |
|             /// If <tt>wants_basic_expr\<Generator\>::value</tt> is true, then let \c E be \c basic_expr;
 | |
|             /// otherwise, let \t E be \c expr. Given an lvalue \c t of type \c T:
 | |
|             ///
 | |
|             /// If \c T is not a Proto expression type the resulting terminal is
 | |
|             /// calculated as follows:
 | |
|             ///
 | |
|             ///   If \c T is a function type, an abstract type, or a type derived from
 | |
|             ///   \c std::ios_base, let \c A be <tt>T &</tt>.
 | |
|             ///   Otherwise, let \c A be the type \c T stripped of cv-qualifiers.
 | |
|             ///   Then, the result of applying <tt>as_expr\<T\>()(t)</tt> is
 | |
|             ///   <tt>Generator()(E\<tag::terminal, term\<A\> \>::make(t))</tt>.
 | |
|             ///
 | |
|             /// If \c T is a Proto expression type and its generator type is different from
 | |
|             /// \c Generator, the result is <tt>Generator()(t)</tt>.
 | |
|             ///
 | |
|             /// Otherwise, the result is \c t converted to an (un-const) rvalue.
 | |
|             ///
 | |
|             template<typename T, typename IsExpr = void, typename Callable = proto::callable>
 | |
|             struct as_expr
 | |
|               : detail::as_expr<
 | |
|                     T
 | |
|                   , typename detail::base_generator<Generator>::type
 | |
|                   , wants_basic_expr<Generator>::value
 | |
|                 >
 | |
|             {
 | |
|                 BOOST_PROTO_CALLABLE()
 | |
|             };
 | |
| 
 | |
|             /// INTERNAL ONLY
 | |
|             ///
 | |
|             template<typename T>
 | |
|             struct as_expr<T, typename T::proto_is_expr_, proto::callable>
 | |
|             {
 | |
|                 BOOST_PROTO_CALLABLE()
 | |
|                 typedef typename remove_const<T>::type result_type;
 | |
| 
 | |
|                 BOOST_FORCEINLINE
 | |
|                 result_type operator()(T &e) const
 | |
|                 {
 | |
|                     return e;
 | |
|                 }
 | |
|             };
 | |
| 
 | |
|             /// \brief A unary MonomorphicFunctionObject that turns objects into Proto
 | |
|             /// expression objects in this domain.
 | |
|             ///
 | |
|             /// The <tt>as_child\<\></tt> function object turns objects into Proto expressions, if
 | |
|             /// they are not already, by making them Proto terminals held by reference.
 | |
|             /// Objects that are already Proto expressions are simply returned by reference.
 | |
|             ///
 | |
|             /// If <tt>wants_basic_expr\<Generator\>::value</tt> is true, then let \c E be \c basic_expr;
 | |
|             /// otherwise, let \t E be \c expr. Given an lvalue \c t of type \c T:
 | |
|             ///
 | |
|             /// If \c T is not a Proto expression type the resulting terminal is
 | |
|             /// <tt>Generator()(E\<tag::terminal, term\<T &\> \>::make(t))</tt>.
 | |
|             ///
 | |
|             /// If \c T is a Proto expression type and its generator type is different from
 | |
|             /// \c Generator, the result is <tt>Generator()(t)</tt>.
 | |
|             ///
 | |
|             /// Otherwise, the result is the lvalue \c t.
 | |
|             ///
 | |
|             template<typename T, typename IsExpr = void, typename Callable = proto::callable>
 | |
|             struct as_child
 | |
|               : detail::as_child<
 | |
|                     T
 | |
|                   , typename detail::base_generator<Generator>::type
 | |
|                   , wants_basic_expr<Generator>::value
 | |
|                 >
 | |
|             {
 | |
|                 BOOST_PROTO_CALLABLE()
 | |
|             };
 | |
| 
 | |
|             /// INTERNAL ONLY
 | |
|             ///
 | |
|             template<typename T>
 | |
|             struct as_child<T, typename T::proto_is_expr_, proto::callable>
 | |
|             {
 | |
|                 BOOST_PROTO_CALLABLE()
 | |
|                 typedef T &result_type;
 | |
| 
 | |
|                 BOOST_FORCEINLINE
 | |
|                 result_type operator()(T &e) const
 | |
|                 {
 | |
|                     return e;
 | |
|                 }
 | |
|             };
 | |
|         };
 | |
| 
 | |
|         /// \brief The domain expressions have by default, if
 | |
|         /// \c proto::extends\<\> has not been used to associate
 | |
|         /// a domain with an expression.
 | |
|         ///
 | |
|         struct default_domain
 | |
|           : domain<>
 | |
|         {};
 | |
| 
 | |
|         /// \brief A domain to use when you prefer the use of
 | |
|         /// \c proto::basic_expr\<\> over \c proto::expr\<\>.
 | |
|         ///
 | |
|         struct basic_default_domain
 | |
|           : domain<basic_default_generator>
 | |
|         {};
 | |
| 
 | |
|         /// \brief A pseudo-domain for use in functions and
 | |
|         /// metafunctions that require a domain parameter. It
 | |
|         /// indicates that the domain of the parent node should
 | |
|         /// be inferred from the domains of the child nodes.
 | |
|         ///
 | |
|         /// \attention \c deduce_domain is not itself a valid domain.
 | |
|         ///
 | |
|         struct deduce_domain
 | |
|           : domain<detail::not_a_generator, detail::not_a_grammar, detail::not_a_domain>
 | |
|         {};
 | |
| 
 | |
|         /// \brief Given a domain, a tag type and an argument list,
 | |
|         /// compute the type of the expression to generate. This is
 | |
|         /// either an instance of \c proto::expr\<\> or
 | |
|         /// \c proto::basic_expr\<\>.
 | |
|         ///
 | |
|         template<typename Domain, typename Tag, typename Args, bool WantsBasicExpr>
 | |
|         struct base_expr
 | |
|         {
 | |
|             typedef proto::expr<Tag, Args, Args::arity> type;
 | |
|         };
 | |
| 
 | |
|         /// INTERNAL ONLY
 | |
|         ///
 | |
|         template<typename Domain, typename Tag, typename Args>
 | |
|         struct base_expr<Domain, Tag, Args, true>
 | |
|         {
 | |
|             typedef proto::basic_expr<Tag, Args, Args::arity> type;
 | |
|         };
 | |
| 
 | |
|     }
 | |
| 
 | |
|     /// A metafunction that returns \c mpl::true_
 | |
|     /// if the type \c T is the type of a Proto domain;
 | |
|     /// \c mpl::false_ otherwise. If \c T inherits from
 | |
|     /// \c proto::domain\<\>, \c is_domain\<T\> is
 | |
|     /// \c mpl::true_.
 | |
|     template<typename T, typename Void  /* = void*/>
 | |
|     struct is_domain
 | |
|       : mpl::false_
 | |
|     {};
 | |
| 
 | |
|     /// INTERNAL ONLY
 | |
|     ///
 | |
|     template<typename T>
 | |
|     struct is_domain<T, typename T::proto_is_domain_>
 | |
|       : mpl::true_
 | |
|     {};
 | |
| 
 | |
|     /// A metafunction that returns the domain of
 | |
|     /// a given type. If \c T is a Proto expression
 | |
|     /// type, it returns that expression's associated
 | |
|     /// domain. If not, it returns
 | |
|     /// \c proto::default_domain.
 | |
|     template<typename T, typename Void /* = void*/>
 | |
|     struct domain_of
 | |
|     {
 | |
|         typedef default_domain type;
 | |
|     };
 | |
| 
 | |
|     /// INTERNAL ONLY
 | |
|     ///
 | |
|     template<typename T>
 | |
|     struct domain_of<T, typename T::proto_is_expr_>
 | |
|     {
 | |
|         typedef typename T::proto_domain type;
 | |
|     };
 | |
| 
 | |
|     /// INTERNAL ONLY
 | |
|     ///
 | |
|     template<typename T>
 | |
|     struct domain_of<T &, void>
 | |
|     {
 | |
|         typedef typename domain_of<T>::type type;
 | |
|     };
 | |
| 
 | |
|     /// INTERNAL ONLY
 | |
|     ///
 | |
|     template<typename T>
 | |
|     struct domain_of<boost::reference_wrapper<T>, void>
 | |
|     {
 | |
|         typedef typename domain_of<T>::type type;
 | |
|     };
 | |
| 
 | |
|     /// INTERNAL ONLY
 | |
|     ///
 | |
|     template<typename T>
 | |
|     struct domain_of<boost::reference_wrapper<T> const, void>
 | |
|     {
 | |
|         typedef typename domain_of<T>::type type;
 | |
|     };
 | |
| 
 | |
|     /// A metafunction that returns \c mpl::true_
 | |
|     /// if the type \c SubDomain is a sub-domain of
 | |
|     /// \c SuperDomain; \c mpl::false_ otherwise.
 | |
|     template<typename SubDomain, typename SuperDomain>
 | |
|     struct is_sub_domain_of
 | |
|       : is_sub_domain_of<typename SubDomain::proto_super_domain, SuperDomain>
 | |
|     {};
 | |
| 
 | |
|     /// INTERNAL ONLY
 | |
|     ///
 | |
|     template<typename SuperDomain>
 | |
|     struct is_sub_domain_of<proto::no_super_domain, SuperDomain>
 | |
|       : mpl::false_
 | |
|     {};
 | |
| 
 | |
|     /// INTERNAL ONLY
 | |
|     ///
 | |
|     template<typename SuperDomain>
 | |
|     struct is_sub_domain_of<SuperDomain, SuperDomain>
 | |
|       : mpl::true_
 | |
|     {};
 | |
| 
 | |
| }}
 | |
| 
 | |
| #if defined(_MSC_VER)
 | |
| # pragma warning(pop)
 | |
| #endif
 | |
| 
 | |
| #endif
 |