choice.hh

00001 // This file is a part of Aurelia.
00002 // Copyright (C) 2010  Valentin David
00003 // Copyright (C) 2010  University of Bergen
00004 //
00005 // This program is free software: you can redistribute it and/or modify
00006 // it under the terms of the GNU General Public License as published by
00007 // the Free Software Foundation, either version 3 of the License, or
00008 // (at your option) any later version.
00009 //
00010 // This program is distributed in the hope that it will be useful,
00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 // GNU General Public License for more details.
00014 //
00015 // You should have received a copy of the GNU General Public License
00016 // along with this program.  If not, see <http://www.gnu.org/licenses/>.
00017 #ifndef __CHOICE_HH
00018 # define __CHOICE_HH
00019 
00020 # include "../strategies.hh"
00021 # include <type_traits>
00022 
00023 namespace aurelia {
00024 
00028   template <typename T>
00029   T common_convertible(T, T);
00030 
00031   template <typename T,
00032             typename U,
00033             typename =
00034             typename std::enable_if<std::is_convertible<U, T>::value>::type>
00035   T common_convertible(T, U);
00036 
00037   template <typename T,
00038             typename U,
00039             typename =
00040             typename std::enable_if<std::is_convertible<T, U>::value>::type>
00041   U common_convertible(T, U);
00042 
00043   template <typename Strat1, typename Strat2>
00044   struct choice_strategy;
00045 
00049   template <typename Strat1, typename Strat2, typename T>
00050   struct strategy_model<choice_strategy<Strat1, Strat2>, T, false> {
00051     struct model {
00052       typedef typename strategy_model<Strat1, T>::model model1;
00053       typedef typename strategy_model<Strat2, T>::model model2;
00054 
00055       typedef typename strategy_concept<model1>::check require1;
00056       typedef typename strategy_concept<model2>::check require2;
00057 
00058       typedef choice_strategy<Strat1, Strat2> strat;
00059       typedef T input;
00060       typedef
00061       decltype(common_convertible(std::declval<typename model1::output>(),
00062                                   std::declval<typename model2::output>()))
00063       output;
00064     };
00065   };
00066 
00069   template <typename Strat1, typename Strat2>
00070   struct choice_strategy {
00071   private:
00072     Strat1 s1;
00073     Strat2 s2;
00074   public:
00075     choice_strategy(const Strat1& s1, const Strat2& s2): s1(s1), s2(s2) {
00076     }
00077 
00078     template <typename T>
00079     typename strategy_model<choice_strategy, T>::model::output
00080     operator()(const T& term) const {
00081       try {
00082         return s1(term);
00083       }
00084       catch (failure) {
00085         return s2(term);
00086       }
00087     }
00088   };
00089 
00094   template <typename Strat1, typename Strat2>
00095   choice_strategy<Strat1, Strat2> operator+(const Strat1& s1, const Strat2& s2) {
00096     return choice_strategy<Strat1, Strat2>(s1, s2);
00097   }
00098 }
00099 
00100 #endif