1 //  (C) Copyright Gennadiy Rozental 2011-2014.
2 //  Distributed under the Boost Software License, Version 1.0.
3 //  (See accompanying file LICENSE_1_0.txt or copy at
4 //  http://www.boost.org/LICENSE_1_0.txt)
5 
6 //  See http://www.boost.org/libs/test for the library home page.
7 //
8 ///@file
9 /// Defines monomorphic dataset n+m dimentional *. Samples in this
10 /// dataset is grid of elements in DS1 and DS2. There will be total
11 /// |DS1| * |DS2| samples
12 // ***************************************************************************
13 
14 #ifndef BOOST_TEST_DATA_MONOMORPHIC_GRID_HPP_101512GER
15 #define BOOST_TEST_DATA_MONOMORPHIC_GRID_HPP_101512GER
16 
17 // Boost.Test
18 #include <boost/test/data/config.hpp>
19 
20 
21 #if !defined(BOOST_TEST_NO_GRID_COMPOSITION_AVAILABLE) || defined(BOOST_TEST_DOXYGEN_DOC__)
22 
23 #include <boost/test/data/monomorphic/dataset.hpp>
24 #include <boost/test/detail/suppress_warnings.hpp>
25 
26 //____________________________________________________________________________//
27 
28 namespace boost {
29 namespace unit_test {
30 namespace data {
31 namespace monomorphic {
32 
33 namespace ds_detail {
34 
35 // !! ?? variadic template implementation; use forward_as_tuple?
36 template<typename T1, typename T2>
37 struct grid_traits {
38     typedef std::tuple<T1,T2> type;
39     typedef typename monomorphic::traits<type>::ref_type ref_type;
40 
41     static ref_type
tuple_mergeboost::unit_test::data::monomorphic::ds_detail::grid_traits42     tuple_merge(T1 const& a1, T2 const& a2)
43     {
44         return ref_type(a1,a2);
45     }
46 };
47 
48 //____________________________________________________________________________//
49 
50 template<typename T1, typename T2,typename T3>
51 struct grid_traits<T1,std::tuple<T2,T3>> {
52     typedef std::tuple<T1,T2,T3> type;
53     typedef typename monomorphic::traits<type>::ref_type ref_type;
54 
55     static ref_type
tuple_mergeboost::unit_test::data::monomorphic::ds_detail::grid_traits56     tuple_merge(T1 const& a1, std::tuple<T2 const&,T3 const&> const& a2)
57     {
58         return ref_type(a1,get<0>(a2),get<1>(a2));
59     }
60 };
61 
62 //____________________________________________________________________________//
63 
64 template<typename T1, typename T2,typename T3>
65 struct grid_traits<std::tuple<T1,T2>,T3> {
66     typedef std::tuple<T1,T2,T3> type;
67     typedef typename monomorphic::traits<type>::ref_type ref_type;
68 
69     static ref_type
tuple_mergeboost::unit_test::data::monomorphic::ds_detail::grid_traits70     tuple_merge(std::tuple<T1 const&,T2 const&> const& a1, T3 const& a2)
71     {
72         return ref_type(get<0>(a1),get<1>(a1),a2);
73     }
74 };
75 
76 //____________________________________________________________________________//
77 
78 } // namespace ds_detail
79 
80 // ************************************************************************** //
81 // **************                       grid                    ************** //
82 // ************************************************************************** //
83 
84 
85 //! Implements the dataset resulting from a cartesian product/grid operation on datasets.
86 //!
87 //! The arity of the resulting dataset is the sum of the arity of its operands.
88 template<typename DS1, typename DS2>
89 class grid : public monomorphic::dataset<typename ds_detail::grid_traits<typename boost::decay<DS1>::type::data_type,
90                                                                          typename boost::decay<DS2>::type::data_type>::type> {
91     typedef typename boost::decay<DS1>::type::data_type T1;
92     typedef typename boost::decay<DS2>::type::data_type T2;
93 
94     typedef typename monomorphic::dataset<T1>::iter_ptr ds1_iter_ptr;
95     typedef typename monomorphic::dataset<T2>::iter_ptr ds2_iter_ptr;
96 
97     typedef typename ds_detail::grid_traits<T1,T2>::type T;
98     typedef monomorphic::dataset<T> base;
99     typedef typename base::iter_ptr iter_ptr;
100 
101     struct iterator : public base::iterator {
102         typedef typename monomorphic::traits<T>::ref_type ref_type;
103 
104         // Constructor
iteratorboost::unit_test::data::monomorphic::grid::iterator105         explicit    iterator( ds1_iter_ptr iter1, DS2 const& ds2 )
106         : m_iter1( iter1 )
107         , m_iter2( ds2.begin() )
108         , m_ds2( ds2 )
109         , m_ds2_pos( 0 )
110         {}
111 
112         // forward iterator interface
operator *boost::unit_test::data::monomorphic::grid::iterator113         virtual ref_type    operator*()     { return ds_detail::grid_traits<T1,T2>::tuple_merge( **m_iter1, **m_iter2 ); }
operator ++boost::unit_test::data::monomorphic::grid::iterator114         virtual void        operator++()
115         {
116             ++m_ds2_pos;
117             if( m_ds2_pos != m_ds2.size() )
118                 ++(*m_iter2);
119             else {
120                 m_ds2_pos = 0;
121                 ++(*m_iter1);
122                 m_iter2 = m_ds2.begin();
123             }
124         }
125 
126     private:
127         // Data members
128         ds1_iter_ptr    m_iter1;
129         ds2_iter_ptr    m_iter2;
130         DS2 const&      m_ds2;
131         data::size_t    m_ds2_pos;
132     };
133 
134 public:
135     enum { arity = boost::decay<DS1>::type::arity + boost::decay<DS2>::type::arity };
136 
137     //! Constructor
grid(DS1 && ds1,DS2 && ds2)138     grid( DS1&& ds1, DS2&& ds2 )
139     : m_ds1( std::forward<DS1>( ds1 ) )
140     , m_ds2( std::forward<DS2>( ds2 ) )
141     {}
142 
143     //! Move constructor
grid(grid && j)144     grid( grid&& j )
145     : m_ds1( std::forward<DS1>( j.m_ds1 ) )
146     , m_ds2( std::forward<DS2>( j.m_ds2 ) )
147     {}
148 
149     // dataset interface
size() const150     virtual data::size_t    size() const    { return m_ds1.size() * m_ds2.size(); }
begin() const151     virtual iter_ptr        begin() const   { return boost::make_shared<iterator>( m_ds1.begin(), m_ds2 ); }
152 
153 private:
154     // Data members
155     DS1             m_ds1;
156     DS2             m_ds2;
157 };
158 
159 //____________________________________________________________________________//
160 
161 // A grid dataset is a dataset
162 template<typename DS1, typename DS2>
163 struct is_dataset<grid<DS1,DS2> > : mpl::true_ {};
164 
165 //____________________________________________________________________________//
166 
167 namespace result_of {
168 
169 /// Result type of the grid operation on dataset.
170 template<typename DS1Gen, typename DS2Gen>
171 struct grid {
172     typedef monomorphic::grid<typename DS1Gen::type,typename DS2Gen::type> type;
173 };
174 
175 } // namespace result_of
176 
177 //____________________________________________________________________________//
178 
179 
180 
181 //! Grid operation
182 template<typename DS1, typename DS2>
183 inline typename boost::lazy_enable_if_c<is_dataset<DS1>::value && is_dataset<DS2>::value,
184                                         result_of::grid<mpl::identity<DS1>,mpl::identity<DS2>>
185 >::type
operator *(DS1 && ds1,DS2 && ds2)186 operator*( DS1&& ds1, DS2&& ds2 )
187 {
188     BOOST_TEST_DS_ASSERT( !ds1.size().is_inf() && !ds2.size().is_inf(), "Grid dimension can't have infinite size" );
189 
190     return grid<DS1,DS2>( std::forward<DS1>( ds1 ),  std::forward<DS2>( ds2 ) );
191 }
192 
193 //! @overload boost::unit_test::data::operator*
194 template<typename DS1, typename DS2>
195 inline typename boost::lazy_enable_if_c<is_dataset<DS1>::value && !is_dataset<DS2>::value,
196                                         result_of::grid<mpl::identity<DS1>,data::result_of::make<DS2>>
197 >::type
operator *(DS1 && ds1,DS2 && ds2)198 operator*( DS1&& ds1, DS2&& ds2 )
199 {
200     return std::forward<DS1>(ds1) * data::make(std::forward<DS2>(ds2));
201 }
202 
203 //! @overload boost::unit_test::data::operator*
204 template<typename DS1, typename DS2>
205 inline typename boost::lazy_enable_if_c<!is_dataset<DS1>::value && is_dataset<DS2>::value,
206                                         result_of::grid<data::result_of::make<DS1>,mpl::identity<DS2>>
207 >::type
operator *(DS1 && ds1,DS2 && ds2)208 operator*( DS1&& ds1, DS2&& ds2 )
209 {
210     return data::make(std::forward<DS1>(ds1)) * std::forward<DS2>(ds2);
211 }
212 
213 //____________________________________________________________________________//
214 
215 } // namespace monomorphic
216 
217 } // namespace data
218 } // namespace unit_test
219 } // namespace boost
220 
221 #include <boost/test/detail/enable_warnings.hpp>
222 
223 #endif // BOOST_TEST_NO_GRID_COMPOSITION_AVAILABLE
224 
225 #endif // BOOST_TEST_DATA_MONOMORPHIC_GRID_HPP_101512GER
226 
227