concept/congruence.hh

00001 // This file is a part of Catsfoot.
00002 // Copyright (C) 2011  Uni Research
00003 //
00004 // This program is free software: you can redistribute it and/or modify
00005 // it under the terms of the GNU Lesser Public License as published by
00006 // the Free Software Foundation, either version 3 of the License, or
00007 // (at your option) any later version.
00008 //
00009 // This program is distributed in the hope that it will be useful,
00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 // GNU Lesser Public License for more details.
00013 //
00014 // You should have received a copy of the GNU Lesser Public License
00015 // along with this program.  If not, see <http://www.gnu.org/licenses/>.
00016 
00017 #ifndef CONGRUENCE_HH
00018 # define CONGRUENCE_HH
00019 
00020 # include "../concept/concept_tools.hh"
00021 # include "../concept/concepts.hh"
00022 # include "../axioms/axioms.hh"
00023 # include "../utils/call_with.hh"
00024 # include <type_traits>
00025 
00026 namespace catsfoot {
00027 
00030   template <typename T, typename Rel>
00031   struct equivalence: public concept {
00032     typedef concept_list<
00033       is_callable<Rel(T, T)>,
00034       std::is_convertible<typename is_callable<Rel(T, T)>::result_type,
00035                           bool>
00036       > requirements;
00037 
00038     static void reflexivity(const Rel& rel, const T& a) {
00039       axiom_assert(rel(a,a));
00040     }
00041 
00042     static void symmetry(const Rel& rel,
00043                          const T& a, const T& b) {
00044       if (rel(a, b))
00045         axiom_assert(rel(b, a));
00046     }
00047 
00048     static void transitivity(const Rel& rel,
00049                              const T& a, const T& b, const T& c) {
00050       if (rel(a, b) && rel(b, c))
00051         axiom_assert(rel(a, c));
00052     }
00053 
00054     AXIOMS(reflexivity, symmetry, transitivity);
00055   };
00056 
00059   template <typename T>
00060   struct equivalence_eq: public concept {
00061     typedef concept_list<
00062       equality<T>,
00063       equivalence<T, op_eq>
00064       > requirements;
00065   };
00066 
00068   template <typename T>
00069   struct verified<equivalence_eq<T> >:
00070     public verified<equivalence<T, op_eq> > {
00071   };
00072 
00074   template <typename T>
00075   struct verified<equivalence<T, op_eq> >
00076 #ifndef DOC_GEN
00077     : public verified<equivalence_eq<T> >
00078 #endif
00079   {
00080   };
00081 
00084   template <typename Rel, typename... E,
00085             typename Index = std::integral_constant<size_t, 0>,
00086             typename = typename std::enable_if
00087             <(Index::value == sizeof...(E))>::type,
00088             typename = void>
00089   bool
00090   tuple_rel(Rel, const std::tuple<E...>&, const std::tuple<E...>&,
00091             Index = Index())
00092   {
00093     return true;
00094   }
00095 
00098   template <typename Rel, typename... E,
00099             typename Index = std::integral_constant<size_t, 0>,
00100             typename
00101 #ifndef DOC_GEN
00102             = typename
00103             std::enable_if
00104             <(Index::value < sizeof...(E))>::type
00105 #endif
00106              >
00107   bool
00108   tuple_rel(Rel rel, const std::tuple<E...>& a,
00109             const std::tuple<E...>& b, Index = Index()) {
00110     return rel(std::get<Index::value>(a), std::get<Index::value>(b))
00111       && tuple_rel(rel, a, b,
00112                    std::integral_constant<size_t, Index::value + 1>{});
00113   }
00114 
00117   template <typename Rel, typename Op, typename... Args>
00118   struct congruence: public concept {
00119 
00120     typedef concept_list<
00121       equivalence<Args, Rel>...,
00122       is_callable<Op(Args...)>,
00123       equivalence<typename is_callable<Op(Args...)>::result_type,
00124                   Rel>
00125       > requirements;
00126 
00127     static void congruence_axiom(const std::tuple<Args...>& args1,
00128                                  const std::tuple<Args...>& args2,
00129                                  const Op& op,
00130                                  const Rel& rel) {
00131       if (tuple_rel(rel, args1, args2))
00132         axiom_assert(rel(call_with(op,args1), call_with(op,args2)));
00133     }
00134 
00135     AXIOMS(congruence_axiom);
00136   };
00137 
00140   template <typename T, typename... Args>
00141   struct congruence_eq: public concept {
00142     typedef concept_list<
00143       congruence<op_eq, T, Args...>
00144       > requirements;
00145   };
00146 
00148   template <typename T, typename... Args>
00149   struct verified<congruence_eq<T, Args...> >:
00150     public verified<congruence<op_eq, T, Args...> > {
00151   };
00152 
00154   template <typename T, typename... Args>
00155   struct verified<congruence<op_eq, T, Args...> >
00156 #ifndef DOC_GEN
00157     : public verified<congruence_eq<T, Args...> >
00158 #endif
00159   {
00160   };
00161 
00162 }
00163 
00164 #endif