term.hh

Go to the documentation of this file.
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 
00020 
00021 #ifndef __TERM_HH
00022 # define __TERM_HH
00023 
00024 # include "constructor.hh"
00025 # include <cassert>
00026 # include <cstdlib>
00027 # include "../strategies/failure.hh"
00028 # include "../lists/listable.hh"
00029 # include "../max_shared/max_shared_ptr.hh"
00030 # include "../memory/pool_allocator.hh"
00031 
00032 namespace aurelia {
00033 
00034   template <typename Pool>
00035   struct untyped_term;
00036 
00037   template <typename Pool>
00038   struct untyped_term_core {
00039   private:
00040     untyped_constructor<Pool> _constructor;
00041     const untyped_term<Pool>* children;
00042     unsigned _hash;
00043 
00044   public:
00045     ~untyped_term_core() {
00046       if (children != NULL) {
00047         for (unsigned i = 0; i < _constructor->arity(); ++i)
00048           (children+i)->~untyped_term();
00049         free((void*)children);
00050       }
00051     }
00052 
00053     untyped_term_core(): _constructor("", 0), _hash(0) {
00054       children = NULL;
00055     }
00056 
00057   private:
00058     void copy(const list_nil&, untyped_term<Pool>*) {
00059     }
00060 
00061     template <typename T,
00062               typename M =
00063               typename aurelia::list_model<T>::model,
00064               typename = typename
00065               std::enable_if<!std::is_same<void,
00066                                            typename M::head_t>::value>::type>
00067     void copy(const T& l, untyped_term<Pool>* list) {
00068       typedef typename aurelia::list_concept<M>::check require;
00069       new (list+(unsigned)M::size-1) untyped_term<Pool>(head(l));
00070       copy(tail(l), list);
00071     }
00072 
00073   public:
00074 
00075     template <typename OtherPool,
00076               typename =
00077               typename
00078               std::enable_if<!std::is_same<Pool, OtherPool>::value>::type>
00079     untyped_term_core(const untyped_term<OtherPool>& other):
00080       _constructor(other->constructor()) {
00081       untyped_term<Pool>* tc = NULL;
00082       _hash = _constructor->hash();
00083       if (_constructor->arity() != 0) {
00084         tc = (untyped_term<Pool>*)malloc(_constructor->arity()*sizeof(untyped_term<Pool>));
00085         for (unsigned i = 0; i < _constructor->arity(); ++i) {
00086           new (tc+i) untyped_term<Pool>((*other)[i]);
00087           _hash ^= tc[i]->hash();
00088           _hash = (_hash << 11) | (_hash >> 21);
00089         }
00090       }
00091       children = tc;
00092     }
00093 
00094     template <typename L,
00095               typename M = typename list_model<L>::model>
00096     untyped_term_core(const untyped_constructor<Pool>& c, const L& ch):
00097       _constructor(c), children(NULL)
00098     {
00099       if (c->arity() != M::size) {
00100         throw failure();
00101       }
00102       _hash = c->hash();
00103       untyped_term<Pool>* tc = NULL;
00104       if (M::size != 0)
00105         tc = (untyped_term<Pool>*)malloc((unsigned)M::size*sizeof(untyped_term<Pool>));
00106       copy(ch, tc);
00107       children = tc;
00108       for (unsigned i = 0; i < c->arity(); ++i) {
00109         _hash ^= children[i]->hash();
00110         _hash = (_hash << 11) | (_hash >> 21);
00111       }
00112     }
00113 
00114     untyped_term_core(const untyped_constructor<Pool>& c, const untyped_term<Pool>& ch)
00115       : _constructor(c) {
00116       if (c->arity() != 1) {
00117         children = NULL;
00118         throw failure();
00119       }
00120       _hash = c.hash();
00121       untyped_term<Pool>* tc = (untyped_term<Pool>*)malloc(sizeof(untyped_term<Pool>));
00122       new (tc) untyped_term<Pool>(ch);
00123       _hash ^= tc[0]->hash();
00124       _hash = (_hash << 11) | (_hash >> 21);
00125       children = tc;
00126     }
00127 
00128     untyped_term_core(const untyped_constructor<Pool>& c, const untyped_term<Pool>* ch)
00129       : _constructor(c) {
00130       _hash = c->hash();
00131       if (c->arity() != 0)
00132         children = ch;
00133       else
00134         children = NULL;
00135       for (unsigned i = 0; i < c->arity(); ++i) {
00136         _hash ^= children[i]->hash();
00137         _hash = (_hash << 11) | (_hash >> 21);
00138       }
00139     }
00140 
00141     untyped_term_core(untyped_term_core&& other):
00142       _constructor(std::move(other._constructor)),
00143       children(NULL),
00144       _hash(other._hash)
00145     {
00146       std::swap(children, other.children);
00147     }
00148 
00149     untyped_term_core(const untyped_term_core& other)
00150       : _constructor(other._constructor) {
00151       _hash = other._hash;
00152       untyped_term<Pool>* tc = NULL;
00153       if (_constructor->arity() != 0) {
00154         tc = (untyped_term<Pool>*)malloc(_constructor->arity()*sizeof(untyped_term<Pool>));
00155         for (unsigned i = 0; i < _constructor->arity(); ++i) {
00156           new (tc+i) untyped_term<Pool>(other.children[i]);
00157         }
00158       }
00159       children = tc;
00160     }
00161 
00162     untyped_term_core& operator=(const untyped_term_core& other) {
00163       return (*this) = untyped_term_core(other);
00164     }
00165 
00166     untyped_term_core& operator=(untyped_term_core&& other) {
00167       std::swap(_constructor, other._constructor);
00168       std::swap(children, other.children);
00169       std::swap(_hash, other._hash);
00170       return *this;
00171     }
00172 
00173     unsigned hash() const {
00174       return _hash;
00175     }
00176 
00177     bool operator==(const untyped_term_core& other) const {
00178       if (_constructor != other._constructor)
00179         return false;
00180       for (unsigned i = 0; i < _constructor->arity(); ++i)
00181         if (children[i] != other.children[i])
00182           return false;
00183       return true;
00184     }
00185 
00186     const untyped_term<Pool>& operator[](unsigned n) const {
00187       if (n >= _constructor->arity())
00188         throw failure();
00189       return children[n];
00190     }
00191 
00192     const untyped_constructor<Pool>& constructor() const {
00193       return _constructor;
00194     }
00195   };
00196 
00197   template <typename Pool>
00198   struct untyped_term:
00199     public max_shared_ptr<untyped_term_core<Pool>,
00200                           member_hash,
00201                           std::equal_to<untyped_term_core<Pool> >,
00202                           pool_allocator<untyped_term_core<Pool> > > {
00203   public:
00204     typedef max_shared_ptr<untyped_term_core<Pool>,
00205                            member_hash,
00206                            std::equal_to<untyped_term_core<Pool> >,
00207                            pool_allocator<untyped_term_core<Pool> > > super;
00208 
00209     untyped_term(const untyped_term& other): super((const super&)(other)) {
00210     }
00211 
00212     untyped_term(untyped_term&& other): super((super&&)std::move(other)) {
00213     }
00214 
00215     untyped_term(): super() {
00216     }
00217 
00218     template <typename OtherPool,
00219               typename =
00220               typename
00221               std::enable_if<!std::is_same<Pool, OtherPool>::value>::type>
00222     bool operator==(const untyped_term<OtherPool>& other) const {
00223       return *this == untyped_term(other);
00224     }
00225 
00226     bool operator==(const untyped_term& other) const {
00227       return this->super::operator==(other);
00228     }
00229 
00230     untyped_term& operator=(const untyped_term& other) {
00231       this->super::operator=(other);
00232       return *this;
00233     }
00234 
00235     untyped_term& operator=(untyped_term&& other) {
00236       this->super::operator=(other);
00237       return *this;
00238     }
00239 
00240     template <typename OtherPool,
00241               typename =
00242               typename
00243               std::enable_if<!std::is_same<Pool, OtherPool>::value>::type>
00244     untyped_term(const untyped_term<OtherPool>& other): super(other) {}
00245 
00246     template <typename L,
00247               typename M = typename list_model<L>::model>
00248     untyped_term(const untyped_constructor<Pool>& c, const L&l): super(c, l) {
00249     }
00250 
00251     untyped_term(const untyped_constructor<Pool>& c, const untyped_term<Pool>&l): super(c, l) {
00252     }
00253 
00254     untyped_term(const untyped_constructor<Pool>& c, const untyped_term<Pool>* l): super(c, l) {
00255     }
00256 
00257     untyped_term(const untyped_constructor<Pool>& c): super(c, list_nil()) {}
00258 
00259     untyped_constructor<Pool> constructor() const {
00260       return (*this)->constructor();
00261     }
00262 
00263     const untyped_term<Pool>& operator[](unsigned i) const {
00264       return (**this)[i];
00265     }
00266 
00267     operator list_cons<untyped_term<Pool>, list_nil>() const {
00268       return list_cons<untyped_term<Pool>, list_nil>()(*this, list_nil());
00269     }
00270 
00271     unsigned hash() const {
00272       return (*this)->hash();
00273     }
00274   };
00275 
00276   template <typename Stream, typename Pool>
00277   void print(Stream& s, const untyped_term<Pool>& t, bool inlist = false) {
00278     if (t.constructor() == untyped_constructor<Pool>::AS_EMPTY_LIST) {
00279       if (!inlist)
00280         s << "[]";
00281     } else if (t.constructor() == untyped_constructor<Pool>::AS_LIST) {
00282       if (!inlist)
00283         s << "[";
00284       else
00285         s << ",";
00286       bool snd = false;
00287       for (unsigned i = 0;
00288            i < t.constructor().arity();
00289            ++i) {
00290         print(s, t[i],snd);
00291       snd = true;
00292       }
00293       if (!inlist)
00294         s << "]";
00295     } else {
00296       s << t.constructor().name();
00297       if (t.constructor().arity() != 0)
00298         s << "(";
00299       for (unsigned i = 0;
00300            i < t.constructor().arity();
00301            ++i) {
00302         if (i != 0)
00303         s << ",";
00304         print(s, t[i]);
00305       }
00306       if (t.constructor().arity() != 0)
00307         s << ")";
00308     }
00309   }
00310 
00311   template <typename Stream, typename Pool>
00312   Stream& operator<<(Stream& s, const untyped_term<Pool>& t) {
00313     print(s, t);
00314     return s;
00315   }
00316 
00317   template <typename Pool>
00318   struct listable_model<untyped_term<Pool> > {
00319     struct model {
00320       typedef untyped_term<Pool> type;
00321     };
00322   };
00323 
00324   template <typename Pool>
00325   template <typename L,
00326             typename,
00327             template <typename> class,
00328             typename>
00329   untyped_term<Pool> untyped_constructor<Pool>::operator[](const L& l) const {
00330     return untyped_term<Pool>(*this, l);
00331   }
00332 
00333 }
00334 
00335 namespace std {
00336   template <typename Pool>
00337   struct hash<aurelia::untyped_term<Pool> > {
00338     unsigned operator()(const aurelia::untyped_term<Pool>& t) const {
00339       return t.hash();
00340     }
00341   };
00342 }
00343 
00344 namespace aurelia {
00345 
00346   template <typename T>
00347   bool diff_no_conv(const T& a, const T& b) {
00348     return a != b;
00349   }
00350 
00351   template <typename T, typename U>
00352   bool diff_no_conv(const T& a, const U& b) {
00353     return true;
00354   }
00355 
00356   template <typename Strat, typename T>
00357   untyped_term<T> all_primitive(const Strat& s, const untyped_term<T>& term) {
00358     if (term.constructor().arity()) {
00359       bool changed = false;
00360       unsigned i = 0;
00361       untyped_term<T> *list = NULL;
00362       try {
00363         list = (untyped_term<T>*)malloc(term.constructor()->arity()
00364                                 *sizeof(untyped_term<T>));
00365         if (list == NULL)
00366           throw failure();
00367         for (;
00368              i < term.constructor().arity();
00369              ++i) {
00370           new (list+i) untyped_term<T>(s(term[i]));
00371           changed = changed || diff_no_conv(list[i], term[i]);
00372         }
00373       }
00374       catch (...) {
00375         if (list == NULL)
00376           throw ;
00377         for (unsigned j = 0; j < i; ++j) {
00378           (list+j)->~untyped_term<T>();
00379         }
00380         free(list);
00381       throw ;
00382       }
00383       if (changed)
00384         return untyped_term<T>(term.constructor(), list);
00385       else {
00386         for (unsigned j = 0;
00387              j < term.constructor().arity();
00388              ++j)
00389           (list+j)->~untyped_term<T>();
00390         free(list);
00391         return term;
00392       }
00393     }
00394     else
00395       return term;
00396   }
00397 
00398 }
00399 
00400 #endif