[Home]CPPTM Answers - Exercise 5-5

BOOST WIKI | RecentChanges | Preferences | Page List | Links List

 // (by Ariel Badichi)
 #include <boost/static_assert.hpp>
 #include <boost/type_traits/is_same.hpp>
 #include <boost/mpl/iterator_tags.hpp>
 #include <boost/mpl/next.hpp>
 #include <boost/mpl/prior.hpp>
 #include <boost/mpl/at.hpp>
 #include <boost/mpl/deref.hpp>
 #include <boost/mpl/advance.hpp>
 #include <boost/mpl/distance.hpp>
 #include <boost/mpl/plus.hpp>
 #include <boost/mpl/minus.hpp>
 #include <boost/mpl/int.hpp>
 #include <boost/mpl/size.hpp>
 #include <boost/mpl/clear.hpp>
 #include <boost/mpl/push_front.hpp>
 #include <boost/mpl/push_back.hpp>
 #include <boost/mpl/eval_if.hpp>
 #include <boost/mpl/greater.hpp>
 #include <boost/mpl/less.hpp>
 #include <boost/mpl/void.hpp>
 #include <boost/mpl/bool.hpp>
 #include <boost/mpl/equal.hpp>
 #include <boost/mpl/insert.hpp>
 #include <boost/mpl/pop_front.hpp>
 #include <boost/mpl/pop_back.hpp>
 #include <boost/mpl/erase.hpp>

 namespace mpl = boost::mpl;

 typedef mpl::int_<0> zero;
 typedef mpl::int_<1> one;
 typedef mpl::int_<2> two;
 typedef mpl::int_<3> three;

 struct none {};
 struct tiny_tag {};

 template<typename T0 = none, typename T1 = none, typename T2 = none>
 struct tiny
 {
     typedef tiny_tag tag;
     typedef tiny type;
     typedef T0 t0;
     typedef T1 t1;
     typedef T2 t2;
 };

 template<typename Tiny, typename Pos>
 struct tiny_iterator
 {
     typedef mpl::random_access_iterator_tag category;
 };

 template<typename Tiny, int N>
 struct tiny_at;

 template<typename Tiny>
 struct tiny_at<Tiny, 0>
 {
     typedef typename Tiny::t0 type;
 };

 template<typename Tiny>
 struct tiny_at<Tiny, 1>
 {
     typedef typename Tiny::t1 type;
 };

 template<typename Tiny>
 struct tiny_at<Tiny, 2>
 {
     typedef typename Tiny::t2 type;
 };

 template<typename T0, typename T1, typename T2>
 struct tiny_size : three {};

 template<typename T0, typename T1>
 struct tiny_size<T0, T1, none> : two {};

 template<typename T0>
 struct tiny_size<T0, none, none> : one {};

 template<>
 struct tiny_size<none, none, none> : zero {};

 /*
 template<typename Tiny, typename T, int N>
 struct tiny_push_back;

 template<typename Tiny, typename T>
 struct tiny_push_back<Tiny, T, 0> : tiny<T> {};

 template<typename Tiny, typename T>
 struct tiny_push_back<Tiny, T, 1> : tiny<typename Tiny::t0, T> {};

 template<typename Tiny, typename T>
 struct tiny_push_back<Tiny, T, 2> 
     : tiny<typename Tiny::t0, typename Tiny::t1, T> {};
 */

 template<typename Tiny>
 struct check_not_full
 {
     BOOST_STATIC_ASSERT((mpl::less<
                              typename mpl::size<Tiny>::type, 
                              three
                          >::value));
 };

 template<typename Tiny>
 struct check_not_empty
 {
     BOOST_STATIC_ASSERT((mpl::greater<
                              typename mpl::size<Tiny>::type, 
                              zero
                          >::value));
 };

 template<typename Tiny, typename T, int N>
 struct tiny_insert;

 template<typename Tiny, typename T>
 struct tiny_insert<Tiny, T, 0> : tiny<T, typename Tiny::t0, typename Tiny::t1>
                                , check_not_full<Tiny>
 {};

 template<typename Tiny, typename T>
 struct tiny_insert<Tiny, T, 1> : tiny<typename Tiny::t0, T, typename Tiny::t1>
                                , check_not_full<Tiny>
 {};

 template<typename Tiny, typename T>
 struct tiny_insert<Tiny, T, 2> : tiny<typename Tiny::t0, typename Tiny::t1, T>
                                , check_not_full<Tiny>
 {};

 template<typename T0, typename T1, typename T2>
 struct tiny_pop_front : tiny<T1, T2> {};

 template<typename T0, typename T1, typename T2>
 struct tiny_pop_back : tiny<T0, T1> {};

 template<typename T0, typename T1>
 struct tiny_pop_back<T0, T1, none> : tiny<T0> {};

 template<typename T0>
 struct tiny_pop_back<T0, none, none> : tiny<> {};

 template<typename Tiny, int N>
 struct tiny_erase;

 template<typename Tiny>
 struct tiny_erase<Tiny, 0> : tiny<typename Tiny::t1, typename Tiny::t2> {};

 template<typename Tiny>
 struct tiny_erase<Tiny, 1> : tiny<typename Tiny::t0, typename Tiny::t2> {};

 template<typename Tiny>
 struct tiny_erase<Tiny, 2> : tiny<typename Tiny::t0, typename Tiny::t1> {};

 template<typename Tiny, typename Pos>
 struct tiny_has_item : mpl::eval_if<
                           mpl::and_<
                               mpl::greater<
                                   typename mpl::size<Tiny>::type,
                                   Pos
                               >,
                               mpl::greater<
                                   Pos,
                                   mpl::prior<zero>::type
                               >
                           >,

                           mpl::true_,
                           mpl::false_
                        >
 {};

 template<typename Tiny, int First, int Last>
 struct tiny_erase_range;

 template<typename Tiny>
 struct tiny_erase_range<Tiny, 0, 1> 
     : mpl::erase<Tiny, tiny_iterator<Tiny, zero> > {};

 template<typename Tiny>
 struct tiny_erase_range<Tiny, 0, 2>
 {
     typedef typename mpl::erase<Tiny, tiny_iterator<Tiny, one> >::type temp;
     typedef typename mpl::erase<temp, tiny_iterator<temp, zero> >::type type;
 };

 template<typename Tiny>
 struct tiny_erase_range<Tiny, 0, 3>
 {
     typedef typename mpl::erase<Tiny, tiny_iterator<Tiny, two> >::type tmp1;
     typedef typename mpl::erase<tmp1, tiny_iterator<tmp1, one> >::type tmp2;
     typedef typename mpl::erase<tmp2, tiny_iterator<tmp2, zero> >::type type;
 };

 template<typename Tiny>
 struct tiny_erase_range<Tiny, 1, 2> 
     : mpl::erase<Tiny, tiny_iterator<Tiny, one> > {};

 template<typename Tiny>
 struct tiny_erase_range<Tiny, 1, 3>
 {
     typedef typename mpl::erase<Tiny, tiny_iterator<Tiny, two> >::type tmp1;
     typedef typename mpl::erase<tmp1, tiny_iterator<tmp1, one> >::type type;
 };

 template<typename Tiny>
 struct tiny_erase_range<Tiny, 2, 3> 
     : mpl::erase<Tiny, tiny_iterator<Tiny, two> > {};

 namespace boost
 {
     namespace mpl
     {
         template<typename Tiny, typename Pos>
         struct next<tiny_iterator<Tiny, Pos> >
         {
             BOOST_STATIC_ASSERT((mpl::greater<
                                      typename size<Tiny>::type, 
                                      Pos
                                  >::value));

             typedef tiny_iterator<Tiny, typename mpl::next<Pos>::type> type;
         };

         template<typename Tiny, typename Pos>
         struct prior<tiny_iterator<Tiny, Pos> >
         {
             BOOST_STATIC_ASSERT((mpl::greater<
                                      Pos,
                                      zero
                                  >::value));

             typedef tiny_iterator<Tiny, typename mpl::prior<Pos>::type> type;
         };

         template<>
         struct at_impl<tiny_tag>
         {
             template<typename Tiny, typename N>
             struct apply : tiny_at<Tiny, N::value> 
             {
                 BOOST_STATIC_ASSERT((mpl::greater<
                                          typename size<Tiny>::type, 
                                          N
                                      >::value));
             };
         };

         template<typename Tiny, typename Pos>
         struct deref<tiny_iterator<Tiny, Pos> > : at<Tiny, Pos> {};

         template<typename Tiny, typename Pos, typename N>
         struct advance<tiny_iterator<Tiny, Pos>, N>
         {
             typedef typename mpl::plus<Pos, N>::type new_pos;

             BOOST_STATIC_ASSERT((mpl::greater<
                                      typename size<Tiny>::type, 
                                      new_pos
                                  >::value));

             BOOST_STATIC_ASSERT((mpl::greater<
                                      new_pos,
                                      mpl::int_<-1>
                                  >::value));

             typedef tiny_iterator<
                         Tiny,
                         new_pos
                     > type;
         };

         template<typename Tiny, typename Pos1, typename Pos2>
         struct distance<tiny_iterator<Tiny, Pos1>, tiny_iterator<Tiny, Pos2> > 
             : mpl::minus<Pos2, Pos1> {};

         template<>
         struct begin_impl<tiny_tag>
         {
             template<typename Tiny>
             struct apply
             {
                 typedef tiny_iterator<Tiny, zero> type;
             };
         };

         template<>
         struct end_impl<tiny_tag>
         {
             template<typename Tiny>
             struct apply
             {
                 typedef tiny_iterator<
                             Tiny,
                             typename tiny_size<
                                          typename Tiny::t0,
                                          typename Tiny::t1,
                                          typename Tiny::t2
                                      >::type
                         > type;
             };
         };

         template<>
         struct size_impl<tiny_tag>
         {
             template<typename Tiny>
             struct apply 
                 : tiny_size<
                       typename Tiny::t0, 
                       typename Tiny::t1, 
                       typename Tiny::t2
                   > {};
         };

         template<>
         struct clear_impl<tiny_tag>
         {
             template<typename Tiny>
             struct apply : tiny<> {};
         };

         template<>
         struct push_front_impl<tiny_tag>
         {
             template<typename Tiny, typename T>
             struct apply : tiny<T, typename Tiny::t0, typename Tiny::t1> 
             {
                 BOOST_STATIC_ASSERT((mpl::less<
                                          typename size<Tiny>::type, 
                                          three 
                                      >::value));
             };
         };

         template<>
         struct push_back_impl<tiny_tag>
         {
             template<typename Tiny, typename T>
             struct apply : tiny_insert<Tiny, T, size<Tiny>::value> {};
         };

         template<>
         struct insert_impl<tiny_tag>
         {
             template<typename Tiny, typename Pos, typename T>
             struct apply;

             template<typename Tiny, typename Pos, typename T>
             struct apply<Tiny, tiny_iterator<Tiny, Pos>, T> 
                 : tiny_insert<Tiny, T, Pos::value> {};
         };

         template<>
         struct pop_front_impl<tiny_tag>
         {
             template<typename Tiny>
             struct apply 
                 : check_not_empty<Tiny>
                 , tiny_pop_front<
                       typename Tiny::t0, 
                       typename Tiny::t1, 
                       typename Tiny::t2
                   > {};
         };

         template<>
         struct pop_back_impl<tiny_tag>
         {
             template<typename Tiny>
             struct apply : check_not_empty<Tiny>
                          , tiny_pop_back<
                                typename Tiny::t0, 
                                typename Tiny::t1, 
                                typename Tiny::t2
                            > {};
         };

         template<>
         struct erase_impl<tiny_tag>
         {
             template<typename Tiny, typename First, typename Last>
             struct apply;

             template<typename Tiny, typename First, typename Last>
             struct apply<Tiny, tiny_iterator<Tiny, First>, Last>
                 : tiny_erase<Tiny, First::value> 
             {
                 BOOST_STATIC_ASSERT((tiny_has_item<
                                          Tiny, First
                                      >::type::value));
             };

             template<typename Tiny, typename First, typename Last>
             struct apply<
                        Tiny, 
                        tiny_iterator<Tiny, First>, 
                        tiny_iterator<Tiny, Last> 
                    > : tiny_erase_range<Tiny, First::value, Last::value>
             {
             };
         };
     }
 }

 template<typename Tiny, typename Pos>
 struct check_at
 {
     typedef typename mpl::at<Tiny, Pos>::type item_at;

     typedef typename mpl::begin<Tiny>::type beg;
     typedef typename mpl::deref<
                          typename mpl::advance<beg, Pos>::type
                      >::type item;

     BOOST_STATIC_ASSERT((boost::is_same<item_at, item>::value));

     typedef check_at type;
 };

 template<typename Tiny>
 struct test
 {
     typedef test type;

     BOOST_STATIC_ASSERT((boost::is_same<Tiny, typename Tiny::type>::value));

     typedef typename mpl::begin<Tiny>::type beg;
     typedef typename mpl::end<Tiny>::type end;
     typedef typename mpl::distance<beg, end>::type distance;
     typedef typename mpl::size<Tiny>::type size;

     BOOST_STATIC_ASSERT(size::value == distance::value);

     typedef typename mpl::eval_if<
                          mpl::greater<size, two>,
                          check_at<Tiny, two>,
                          mpl::true_
                      >::type at2;

     typedef typename mpl::eval_if<
                          mpl::greater<size, one>,
                          check_at<Tiny, one>,
                          mpl::true_
                      >::type at1;

     typedef typename mpl::eval_if<
                          mpl::greater<size, zero>,
                          check_at<Tiny, zero>,
                          mpl::true_
                      >::type at0;
 };

 int main()
 {
     typedef tiny<> tiny0;
     typedef tiny<int> tiny1;
     typedef tiny<char *, const long> tiny2;
     typedef tiny<unsigned short, double &, bool> tiny3;

     test<tiny0>::type;
     test<tiny1>::type;
     test<tiny2>::type;
     test<tiny3>::type;

     typedef mpl::clear<tiny3>::type clean;
     BOOST_STATIC_ASSERT((mpl::equal<tiny0, clean>::type::value));

     {
         typedef mpl::push_front<tiny0, int>::type tiny0_1;
         typedef mpl::push_front<tiny1, int>::type tiny1_2;
         typedef mpl::push_front<tiny2, int>::type tiny2_3;
         //typedef mpl::push_front<tiny3, int>::type invalid;
     }

     {
         typedef mpl::push_back<tiny0, int>::type tiny0_1;
         typedef mpl::push_back<tiny1, int>::type tiny1_2;
         typedef mpl::push_back<tiny2, int>::type tiny2_3;
         //typedef mpl::push_back<tiny3, int>::type invalid;
     }

     {
         //typedef mpl::at<tiny0, zero>::type invalid;
     }

     {
         typedef mpl::begin<tiny0>::type beg;
         //typedef mpl::next<beg>::type invalid;
     }

     {
         typedef mpl::begin<tiny0>::type beg;
         //typedef mpl::deref<beg>::type invalid;
     }

     {
         typedef mpl::end<tiny0>::type end;
         //typedef mpl::prior<end>::type invalid;
     }

     {
         typedef mpl::begin<tiny0>::type beg;
         //typedef mpl::advance<beg, one>::type invalid;
     }

     {
         typedef mpl::end<tiny0>::type end;
         //typedef mpl::advance<end, mpl::int_<-1> >::type invalid;
     }

     {
         typedef tiny_iterator<tiny0, zero> i0;
         typedef mpl::insert<tiny0, i0, long>::type i0_1;
         BOOST_STATIC_ASSERT((mpl::equal<i0_1, tiny<long> >::type::value));
         typedef tiny_iterator<i0_1, zero> i1;
         typedef mpl::insert<i0_1, i1, int>::type i1_2;
         BOOST_STATIC_ASSERT((mpl::equal<
                                  i1_2, tiny<int, long> >::type::value));
         typedef tiny_iterator<i1_2, zero> i2;
         typedef mpl::insert<i1_2, i2, char>::type i2_3;
         BOOST_STATIC_ASSERT((mpl::equal<
                                  i2_3, tiny<char, int, long> >::type::value));
         typedef tiny_iterator<i2_3, zero> i3;
         //typedef mpl::insert<i2_3, i3, bool>::type invalid;
     }

     {
         typedef tiny_iterator<tiny1, one> i0;
         typedef mpl::insert<tiny1, i0, long>::type i1_2;
         BOOST_STATIC_ASSERT((mpl::equal<
                                  i1_2, tiny<int, long> >::type::value));
         typedef tiny_iterator<i1_2, one> i1;
         typedef mpl::insert<i1_2, i1, char>::type i2_3;
         BOOST_STATIC_ASSERT((mpl::equal<
                                  i2_3, tiny<int, char, long> >::type::value));
         typedef tiny_iterator<i2_3, one> i2;
         //typedef mpl::insert<i2_3, i2, bool>::type invalid;
     }

     {
         typedef tiny_iterator<tiny2, two> i0;
         typedef mpl::insert<tiny2, i0, long>::type i2_3;
         BOOST_STATIC_ASSERT((mpl::equal<
                                  i2_3, tiny<char *, const long, long>
                              >::type::value));
         typedef tiny_iterator<i2_3, two> i1;
         //typedef mpl::insert<i2_3, i1, char>::type invalid;
     }

     {
         typedef mpl::pop_front<tiny3>::type t2;
         BOOST_STATIC_ASSERT((mpl::equal<
                                  t2, 
                                  tiny<double &, bool> 
                              >::type::value));
         typedef mpl::pop_front<t2>::type t1;
         BOOST_STATIC_ASSERT((mpl::equal<
                                  t1,
                                  tiny<bool>
                              >::type::value));
         typedef mpl::pop_front<t1>::type t0;
         BOOST_STATIC_ASSERT((mpl::equal<t0, tiny<> >::type::value));
         //typedef mpl::pop_front<t0>::type invalid;
     }

     {
         typedef mpl::pop_back<tiny3>::type t2;
         BOOST_STATIC_ASSERT((mpl::equal<
                                  t2, 
                                  tiny<unsigned short, double &> 
                              >::type::value));
         typedef mpl::pop_back<t2>::type t1;
         BOOST_STATIC_ASSERT((mpl::equal<
                                  t1,
                                  tiny<unsigned short>
                              >::type::value));
         typedef mpl::pop_back<t1>::type t0;
         BOOST_STATIC_ASSERT((mpl::equal<t0, tiny<> >::type::value));
         //typedef mpl::pop_back<t0>::type invalid;
     }

     {
         typedef tiny_iterator<tiny3, zero> i0;
         typedef mpl::erase<tiny3, i0>::type e0;
         BOOST_STATIC_ASSERT((mpl::equal<
                                  e0, 
                                  tiny<double &, bool> 
                              >::type::value));

         typedef tiny_iterator<tiny3, one> i1;
         typedef mpl::erase<tiny3, i1>::type e1;
         BOOST_STATIC_ASSERT((mpl::equal<
                                  e1, 
                                  tiny<unsigned short, bool> 
                              >::type::value));

         typedef tiny_iterator<tiny3, two> i2;
         typedef mpl::erase<tiny3, i2>::type e2;
         BOOST_STATIC_ASSERT((mpl::equal<
                                  e2, 
                                  tiny<unsigned short, double &> 
                              >::type::value));
     }

     {
         typedef tiny_iterator<tiny2, zero> i0;
         typedef mpl::erase<tiny2, i0>::type e0;
         BOOST_STATIC_ASSERT((mpl::equal<e0, tiny<const long> >::type::value));

         typedef tiny_iterator<tiny2, one> i1;
         typedef mpl::erase<tiny2, i1>::type e1;
         BOOST_STATIC_ASSERT((mpl::equal<e1, tiny<char *> >::type::value));

         typedef tiny_iterator<tiny2, two> i2;
         //typedef mpl::erase<tiny2, i2>::type invalid;
     }

     {
         typedef tiny_iterator<tiny1, zero> i0;
         typedef mpl::erase<tiny1, i0>::type e0;
         BOOST_STATIC_ASSERT((mpl::equal<e0, tiny<> >::type::value));

         typedef tiny_iterator<tiny1, one> i1;
         //typedef mpl::erase<tiny1, i1>::type invalid;
     }

     {
         typedef tiny_iterator<tiny0, zero> i0;
         //typedef mpl::erase<tiny0, i0>::type invalid;
     }

     {
         typedef tiny_iterator<tiny3, zero> i0;
         typedef tiny_iterator<tiny3, one> i1;
         typedef tiny_iterator<tiny3, two> i2;
         typedef tiny_iterator<tiny3, three> i3;

         //typedef mpl::erase<tiny3, i0, i0>::type invalid0;

         typedef mpl::erase<tiny3, i0, i1>::type e0;
         BOOST_STATIC_ASSERT((mpl::equal<e0, tiny<double &, bool> >::type::value));

         typedef mpl::erase<tiny3, i0, i2>::type e1;
         BOOST_STATIC_ASSERT((mpl::equal<e1, tiny<bool> >::type::value));

         typedef mpl::erase<tiny3, i0, i3>::type e2;
         BOOST_STATIC_ASSERT((mpl::equal<e2, tiny<> >::type::value));

         //typedef mpl::erase<tiny3, i1, i1>::type invalid1;

         typedef mpl::erase<tiny3, i1, i2>::type e3;
         BOOST_STATIC_ASSERT((mpl::equal<e3, tiny<unsigned short, bool> >::type::value));

         typedef mpl::erase<tiny3, i1, i3>::type e4;
         BOOST_STATIC_ASSERT((mpl::equal<e4, tiny<unsigned short> >::type::value));

         //typedef mpl::erase<tiny3, i2, i2>::type invalid2;

         typedef mpl::erase<tiny3, i2, i3>::type e5;
         BOOST_STATIC_ASSERT((mpl::equal<e5, tiny<unsigned short, double &> >::type::value));
     }

     {
         typedef tiny_iterator<tiny2, zero> i0;
         typedef tiny_iterator<tiny2, one> i1;
         typedef tiny_iterator<tiny2, two> i2;
         typedef tiny_iterator<tiny2, three> i3;

         typedef mpl::erase<tiny2, i0, i1>::type e0;
         BOOST_STATIC_ASSERT((mpl::equal<e0, tiny<const long> >::type::value));

         typedef mpl::erase<tiny2, i0, i2>::type e1;
         BOOST_STATIC_ASSERT((mpl::equal<e1, tiny<> >::type::value));

         //typedef mpl::erase<tiny2, i0, i3>::type invalid0;

         typedef mpl::erase<tiny2, i1, i2>::type e2;
         BOOST_STATIC_ASSERT((mpl::equal<e2, tiny<char *> >::type::value));

         //typedef mpl::erase<tiny2, i1, i3>::type invalid1;
         //typedef mpl::erase<tiny2, i2, i3>::type invalid2;
     }

     {
         typedef tiny_iterator<tiny1, zero> i0;
         typedef tiny_iterator<tiny1, one> i1;
         typedef tiny_iterator<tiny1, two> i2;

         typedef mpl::erase<tiny1, i0, i1>::type e0;
         BOOST_STATIC_ASSERT((mpl::equal<e0, tiny<> >::type::value));

         //typedef mpl::erase<tiny1, i0, i2>::type invalid0;
         //typedef mpl::erase<tiny1, i1, i2>::type invalid1;
     }

     {
         typedef tiny_iterator<tiny0, zero> i0;
         typedef tiny_iterator<tiny0, one> i1;

         //typedef mpl::erase<tiny0, i0, i1>::type invalid;
     }

     return 0;
 }

BOOST WIKI | RecentChanges | Preferences | Page List | Links List
Edit text of this page | View other revisions
Last edited March 27, 2005 11:41 am (diff)
Search:
Disclaimer: This site not officially maintained by Boost Developers