1 ///////////////////////////////////////////////////////////////////////////////
2 /// \file deduce_domain.hpp
3 /// Contains definition of deduce_domain\<\> class templates
4 /// for finding the domain that is common among the specified
5 /// domains
6 //
7 //  Copyright 2010 Daniel Wallin, Eric Niebler. Distributed under the Boost
8 //  Software License, Version 1.0. (See accompanying file
9 //  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
10 //
11 // Many thanks to Daniel Wallin who first implemented this code. Thanks
12 // also to Jeremiah Willcock, John Bytheway and Krishna Achuthan who
13 // offered alternate solutions to this tricky programming problem.
14 
15 #ifndef BOOST_PROTO_DEDUCE_DOMAIN_HPP_EAN_05_22_2010
16 #define BOOST_PROTO_DEDUCE_DOMAIN_HPP_EAN_05_22_2010
17 
18 #include <boost/config.hpp>
19 #include <boost/preprocessor/cat.hpp>
20 #include <boost/preprocessor/facilities/intercept.hpp>
21 #include <boost/preprocessor/iteration/local.hpp>
22 #include <boost/preprocessor/iteration/iterate.hpp>
23 #include <boost/preprocessor/repetition/enum_params.hpp>
24 #include <boost/preprocessor/repetition/enum_binary_params.hpp>
25 #include <boost/preprocessor/repetition/repeat_from_to.hpp>
26 #include <boost/preprocessor/arithmetic/inc.hpp>
27 #include <boost/mpl/assert.hpp>
28 #include <boost/type_traits/is_same.hpp>
29 #include <boost/proto/proto_fwd.hpp>
30 
31 #ifndef BOOST_PROTO_ASSERT_VALID_DOMAIN
32 # define BOOST_PROTO_ASSERT_VALID_DOMAIN(DOM) BOOST_MPL_ASSERT_NOT((boost::is_same<DOM, boost::proto::detail::not_a_domain>))
33 #endif
34 
35 namespace boost
36 {
37     namespace proto
38     {
39         namespace detail
40         {
41             template<typename Domain>
42             struct domain_
43               : domain_<typename Domain::proto_super_domain>
44             {
45                 typedef Domain type;
46                 typedef domain_<typename Domain::proto_super_domain> base;
47             #ifdef BOOST_NO_CXX11_DECLTYPE
48                 using base::deduce98;
49                 static int const index = base::index + 1;
50                 static typename sized_type<index>::type deduce98(domain_<Domain>*);
51             #else
52                 using base::deduce0x;
53                 static Domain deduce0x(domain_<Domain>*);
54             #endif
55             };
56 
57             template<>
58             struct domain_<not_a_domain>
59             {
60                 typedef not_a_domain type;
61             #ifdef BOOST_NO_CXX11_DECLTYPE
62                 static int const index = 1;
63                 static sized_type<1>::type deduce98(void*);
64             #else
65                 static not_a_domain deduce0x(void*);
66             #endif
67             };
68 
69             template<>
70             struct domain_<default_domain>
71               : domain_<not_a_domain>
72             {};
73 
74             template<>
75             struct domain_<basic_default_domain>
76               : domain_<not_a_domain>
77             {};
78 
79             sized_type<1>::type default_test(void*, void*);
80             sized_type<2>::type default_test(domain_<default_domain>*, void*);
81             sized_type<2>::type default_test(domain_<basic_default_domain>*, void*);
82             sized_type<3>::type default_test(void*, domain_<default_domain>*);
83             sized_type<3>::type default_test(void*, domain_<basic_default_domain>*);
84             sized_type<4>::type default_test(domain_<default_domain>*, domain_<default_domain>*);
85             sized_type<4>::type default_test(domain_<basic_default_domain>*, domain_<default_domain>*);
86             sized_type<4>::type default_test(domain_<default_domain>*, domain_<basic_default_domain>*);
87             sized_type<4>::type default_test(domain_<basic_default_domain>*, domain_<basic_default_domain>*);
88 
89         #ifdef BOOST_NO_CXX11_DECLTYPE
90             template<int N, typename Domain>
91             struct nth_domain
92               : nth_domain<N - 1, typename Domain::base>
93             {};
94 
95             template<typename Domain>
96             struct nth_domain<0, Domain>
97               : Domain
98             {};
99         #endif
100 
101             template<typename D0>
102             struct common_domain1
103             {
104                 typedef D0 type;
105             };
106 
107             template<typename E0>
108             struct deduce_domain1
109               : domain_of<E0>
110             {};
111 
112             template<
113                 typename D0
114               , typename D1
115               , int DefaultCase = sizeof(proto::detail::default_test((domain_<D0>*)0, (domain_<D1>*)0))
116             >
117             struct common_domain2
118             {
119             #ifdef BOOST_NO_CXX11_DECLTYPE
120                 static int const index = domain_<D0>::index - sizeof(domain_<D0>::deduce98((domain_<D1>*)0));
121                 typedef typename nth_domain<index, domain_<D0> >::type type;
122             #else
123                 typedef decltype(domain_<D0>::deduce0x((domain_<D1>*)0)) type;
124             #endif
125             };
126 
127             template<typename D0, typename D1>
128             struct common_domain2<D0, D1, 2>
129             {
130                 typedef D1 type;
131             };
132 
133             template<typename D0, typename D1>
134             struct common_domain2<D0, D1, 3>
135             {
136                 typedef D0 type;
137             };
138 
139             template<typename D0>
140             struct common_domain2<D0, default_domain, 4>
141             {
142                 typedef D0 type;
143             };
144 
145             template<typename D0>
146             struct common_domain2<D0, basic_default_domain, 4>
147             {
148                 typedef D0 type;
149             };
150 
151             template<typename D1>
152             struct common_domain2<default_domain, D1, 4>
153             {
154                 typedef D1 type;
155             };
156 
157             template<typename D1>
158             struct common_domain2<basic_default_domain, D1, 4>
159             {
160                 typedef D1 type;
161             };
162 
163             template<>
164             struct common_domain2<default_domain, default_domain, 4>
165             {
166                 typedef default_domain type;
167             };
168 
169             template<>
170             struct common_domain2<basic_default_domain, default_domain, 4>
171             {
172                 typedef default_domain type;
173             };
174 
175             template<>
176             struct common_domain2<default_domain, basic_default_domain, 4>
177             {
178                 typedef default_domain type;
179             };
180 
181             template<>
182             struct common_domain2<basic_default_domain, basic_default_domain, 4>
183             {
184                 typedef basic_default_domain type;
185             };
186 
187             template<typename E0, typename E1>
188             struct deduce_domain2
189               : common_domain2<
190                     typename domain_of<E0>::type
191                   , typename domain_of<E1>::type
192                 >
193             {};
194 
195             #include <boost/proto/detail/deduce_domain_n.hpp>
196         }
197     }
198 }
199 
200 #endif // BOOST_PROTO_DEDUCE_DOMAIN_HPP_EAN_05_22_2010
201