term_utils.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 
00018 #ifndef __TERM_UTILS_HH
00019 # define __TERM_UTILS_HH
00020 
00021 # include <functional>
00022 # include <strategies/failure.hh>
00023 # include <max_shared/max_shared_ptr.hh>
00024 # include "hash/tuple_hash.hh"
00025 # include "type_traits/overloading_priority.hh"
00026 # include "term_concept.hh"
00027 
00028 namespace aurelia {
00029 
00030   template <typename Constructor, typename... SubPatterns>
00031   struct pattern;
00032 
00033   template <typename Term, typename Constr>
00034   struct get_tuple {
00035   };
00036 
00037   template <typename Strat, typename tuple, size_t N, size_t size>
00038   struct tuple_all {
00039     static void apply(const Strat& s, tuple& t) {
00040       std::get<N>(t) = s(std::get<N>(t));
00041       tuple_all<Strat, tuple, N+1, size>::apply(s, t);
00042     }
00043   };
00044 
00045   template <typename Strat, typename tuple, size_t size>
00046   struct tuple_all<Strat, tuple, size, size> {
00047     static void apply(const Strat&, tuple&) {
00048     }
00049   };
00050 
00051   template <typename Term, typename Constr>
00052   struct virtual_term_constr {
00053     typedef typename get_tuple<Term,Constr>::tuple tuple;
00054 
00055     virtual const tuple&
00056     getvalues(const Constr&) const throw (failure) {
00057       throw failure();
00058     }
00059 
00060     virtual Term build(tuple&&) const {
00061       throw failure();
00062     }
00063 
00064     template <typename Strat>
00065     Term all_prim(const Strat& s) const {
00066       tuple out(getvalues(Constr()));
00067       tuple_all<Strat, tuple, 0, std::tuple_size<tuple>::value>
00068         ::apply(s, out);
00069       return build(std::move(out));
00070     }
00071   };
00072 
00073   template <typename T, typename... Tail>
00074   struct pos_of;
00075 
00076   template <typename T, typename Head, typename... Tail>
00077   struct pos_of<T, Head, Tail...> {
00078     enum: size_t { value = (size_t)pos_of<T, Tail...>::value+1 };
00079   };
00080 
00081   template <typename T, typename... Tail>
00082   struct pos_of<T, T, Tail...> {
00083     enum: size_t { value = 0 };
00084   };
00085 
00086   template <typename Term, typename VirtualTerm, typename Strat,
00087             typename... Constrs>
00088   struct dispatch_all {
00089     static Term apply(const Strat&, size_t, const VirtualTerm&) {
00090       throw failure();
00091     }
00092   };
00093 
00094   template <typename Term, typename VirtualTerm, typename Strat,
00095             typename Constr, typename... Constrs>
00096   struct dispatch_all<Term, VirtualTerm, Strat, Constr, Constrs...> {
00097     static Term apply(const Strat& s, size_t n, const VirtualTerm& v) {
00098       if (n == 0)
00099         return static_cast<const virtual_term_constr<Term, Constr>*>(&v)
00100           ->all_prim(s);
00101       return dispatch_all<Term, VirtualTerm, Strat, Constrs...>
00102 	::apply(s, n-1, v);
00103     }
00104   };
00105 
00106   template <typename Term, typename... Constr>
00107   struct virtual_term: public virtual_term_constr<Term, Constr>... {
00108     virtual size_t constr() const = 0;
00109 
00110     template <typename C, typename ...V>
00111     void match(pattern<C, V...>& p) const throw (failure) {
00112       p.subpatterns =
00113         ((const virtual_term_constr<Term,C>*)this)->getvalues(p.constructor);
00114     }
00115 
00116     template <typename Strat>
00117     Term all_prim(const Strat& s) const {
00118       return dispatch_all<Term, virtual_term, Strat, Constr...>
00119 	::apply(s, constr(), *this);
00120     }
00121 
00122     virtual bool operator==(const virtual_term& other) const = 0;
00123     virtual bool operator!=(const virtual_term& other) const = 0;
00124 
00125     virtual size_t hash() const = 0;
00126   };
00127 
00128   template <typename Constr, typename Term>
00129   struct ConstrNb {
00130   };
00131 
00132   template <typename Constr, typename Term, typename... Constrs>
00133   struct ConstrNb<Constr, virtual_term<Term, Constrs...> > {
00134     enum: size_t { value = (size_t)pos_of<Constr, Constrs...>::value };
00135   };
00136 
00137   template <typename Type, typename Constr>
00138   struct build_type {};
00139 
00140   template <typename Real, typename... Constrs>
00141   struct term {
00142     typedef virtual_term<Real, Constrs...> virt;
00143     std::shared_ptr<virt> l;
00144 
00145     term(virt *ptr): l(ptr) {}
00146 
00147     term(const term&) = default;
00148 
00149     term(term&& other): l(std::move(other.l)) {
00150     }
00151 
00152     term(): l((virt*)NULL) {}
00153 
00154     Real& operator=(term&& other) {
00155       std::swap(l, other.l);
00156       return *static_cast<Real*>(this);
00157     }
00158 
00159     Real& operator=(const term& other) {
00160       if (&other == this)
00161         return *static_cast<Real*>(this);
00162       return *this = term(other);
00163     }
00164 
00165     template <typename Constr, typename ...V>
00166     void match(pattern<Constr, V...>& p) const throw (failure) {
00167       l->match(p);
00168     }
00169 
00170     bool operator==(const term& other) const {
00171       return *l == *(other.l);
00172     }
00173 
00174     bool operator!=(const term& other) const {
00175       return *l != *(other.l);
00176     }
00177 
00178     size_t hash() const {
00179       if (l.get() == (virt*)NULL)
00180         return 0;
00181       return l->hash();
00182     }
00183 
00184     template <typename Strat>
00185     term all_prim(const Strat& s) const {
00186       return l->all_prim(s);
00187     }
00188   };
00189 
00190   template <typename Strat, typename T, typename... Constrs>
00191   term<T, Constrs...> all_primitive(const Strat& s,
00192                                     const term<T, Constrs...>& term) {
00193     return term.all_prim(s);
00194   }
00195 
00196   template <typename Real, typename... Constrs>
00197   struct term_model<term<Real, Constrs...> > {
00198     struct model {
00199       typedef term<Real, Constrs...> type;
00200     };
00201   };
00202 
00203   template <typename Real, typename Constr, typename Super>
00204   struct std_term: public Super::virt {
00205     enum { constrnb = (size_t)ConstrNb<Constr, typename Super::virt>::value };
00206 
00207     typedef typename get_tuple<Super, Constr>::tuple tuple;
00208     struct core_type {
00209       tuple args;
00210       size_t hash() const {
00211         return std::hash<tuple>()(args);
00212       };
00213 
00214       core_type() = default;
00215       core_type(tuple&& args): args(std::move(args)) {}
00216       core_type(core_type&& other): args(std::move(other.args)) {
00217       }
00218 
00219       bool operator==(const core_type& other) const {
00220         return args == other.args;
00221       }
00222 
00223       bool operator!=(const core_type& other) const {
00224         return args != other.args;
00225       }
00226     };
00227     max_shared_ptr<core_type> core;
00228 
00229     virtual size_t constr() const {
00230       return constrnb;
00231     }
00232 
00233     virtual Super build(tuple&& t) const {
00234       return std_term(std::move(t));
00235     }
00236 
00237     virtual size_t hash() const {
00238       return core->hash();
00239     }
00240 
00241     operator Super() const {
00242       return Super((typename Super::virt*)new std_term(*this));
00243     }
00244 
00245     std_term(const tuple& args): core(args) {}
00246     std_term(tuple&& args): core(std::move(args)) {}
00247 
00248     std_term(const std_term& other): core(other.core) {}
00249     std_term(std_term&& other): core(std::move(other.core)) {}
00250 
00251     virtual const tuple& getvalues(const Constr&) const throw() {
00252       return (*core).args;
00253     }
00254 
00255     virtual bool operator==(const typename Super::virt& other) const {
00256       const std_term* ro = dynamic_cast<const std_term*>(&other);
00257       if (ro == NULL)
00258         return false;
00259       return core == ro->core;
00260     }
00261 
00262     virtual bool operator!=(const typename Super::virt& other) const {
00263       const std_term* ro = dynamic_cast<const std_term*>(&other);
00264       if (ro == NULL)
00265         return true;
00266       return core != ro->core;
00267     }
00268   };
00269 
00270   template <typename T, typename Constr, size_t N,
00271             typename tuple, typename... SubPatterns>
00272   struct build_real_type;
00273 
00274   template <typename T, typename Constr, size_t N,
00275             typename tuple, typename Head, typename... SubPatterns>
00276   struct build_real_type<T,
00277                          Constr, N, tuple, Head, SubPatterns...> {
00278     template <typename... Args>
00279     static T
00280     build(const tuple& t, Args... args) {
00281       static_assert((N+sizeof...(SubPatterns)+1) ==
00282                     std::tuple_size<tuple>::value,
00283                     "Was not the right number of arguments");
00284       static_assert(N == sizeof...(Args),
00285                     "Was not the right number of arguments");
00286       return build_real_type<T, Constr, N+1, tuple, SubPatterns...>
00287         ::build(t, std::forward<Args>(args)..., *std::get<N>(t));
00288     }
00289   };
00290 
00291   template <typename T,
00292             typename Constr, size_t N, typename tuple>
00293   struct build_real_type<T, Constr, N, tuple> {
00294     template <typename... Args>
00295     static T
00296     build(const tuple&, Args... args) {
00297       static_assert(N == std::tuple_size<tuple>::value,
00298                     "Was not the right number of arguments");
00299       static_assert(N == sizeof...(Args),
00300                     "Was not the right number of arguments");
00301       return T(new typename build_type<T, Constr>::
00302                type(std::forward<Args>(args)...));
00303     }
00304   };
00305 
00306 }
00307 
00308 #endif