# Sym.h

    00001 /*
    00002  *             Copyright (C) 2005 Maarten Keijzer
    00003  *
    00004  *          This program is free software; you can redistribute it and/or modify
    00005  *          it under the terms of version 2 of the GNU General Public License as
    00006  *          published by the Free Software Foundation.
    00007  *
    00008  *          This program is distributed in the hope that it will be useful,
    00009  *          but WITHOUT ANY WARRANTY; without even the implied warranty of
    00010  *          MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    00011  *          GNU General Public License for more details.
    00012  *
    00013  *          You should have received a copy of the GNU General Public License
    00014  *          along with this program; if not, write to the Free Software
    00015  *          Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    00016  */
    00017
    00018 #ifndef SYMNODE_H_
    00019 #define SYMNODE_H_
    00020
    00021 #include <cassert>
    00022
    00023 #if __GNUC__ >= 3
    00024 #include <backward/hash_map.h>
    00025 #elif __GNUC__ < 3
    00026 #include <hash_map.h>
    00027 using std::hash_map;
    00028 #endif
    00029
    00030 /* Empty 'extra statistics' structure, derive from this to keep other characteristics of nodes */
    00031 struct UniqueNodeStats { virtual ~UniqueNodeStats(){} };
    00032
    00033 #include "SymImpl.h"
    00034 #include "token.h"
    00035
    00036 #if __GNUC__ == 4
    00037 #define USE_TR1 1
    00038 #else
    00039 #define USE_TR1 0
    00040 #endif
    00041
    00042 #if USE_TR1
    00043 #include <tr1/unordered_map>
    00044 typedef std::tr1::unordered_map<detail::SymKey, detail::SymValue, detail::SymKey::Hash> SymMap;
    00045 #else
    00046 typedef hash_map<detail::SymKey, detail::SymValue, detail::SymKey::Hash> SymMap;
    00047 #endif
    00048
    00049 typedef SymMap::iterator SymIterator;
    00050
    00051 /* Sym is the tree, for which all the nodes are stored in a hash table.
    00052  * This makes checking for equality O(1) */
    00053 class Sym
    00054 {
    00055     public:
    00056
    00057         Sym() : node(dag.end()) {}
    00058         explicit Sym(token_t token, const SymVec& args);
    00059         explicit Sym(token_t token, const Sym& args);
    00060         explicit Sym(token_t var);
    00061
    00062         explicit Sym(SymIterator it) : node(it) { incref(); }
    00063
    00064         Sym(const Sym& oth) : node(oth.node) { incref(); }
    00065         ~Sym() { decref(); }
    00066
    00067         const Sym& operator=(const Sym& oth) {
    00068             if (oth.node == node) return *this;
    00069             decref();
    00070             node = oth.node;
    00071             incref();
    00072             return *this;
    00073         }
    00074
    00075         /* Unique Stats are user defined */
    00076         UniqueNodeStats* extra_stats() const { return empty()? 0 : node->second.uniqueNodeStats; }
    00077
    00078         int hashcode() const { return node->first.get_hash_code(); } //detail::SymKey::Hash hash; return hash(node->first); }
    00079
    00080         // Friends, need to touch the node
    00081         friend struct detail::SymKey::Hash;
    00082         friend struct detail::SymKey;
    00083
    00084         unsigned refcount() const { return empty()? 0: node->second.refcount; }
    00085
    00086         bool operator==(const Sym& other) const {
    00087             return node == other.node;
    00088         }
    00089         bool operator!=(const Sym& other) const { return !(*this == other); }
    00090
    00091         bool empty() const { return node == dag.end(); }
    00092
    00093         /* Support for traversing trees */
    00094         unsigned arity() const { return node->first.arity(); }
    00095         token_t    token() const { return node->first.token; }
    00096
    00097         const SymVec& args() const { return node->first.vec(); }
    00098
    00099         /* size() - depth */
    00100         unsigned size() const { return empty()? 0 : node->second.size; }
    00101         unsigned depth() const { return empty()? 0 : node->second.depth; }
    00102
    00103         SymMap::iterator iterator() const { return node; }
    00104
    00105         /* Statics accessing some static members */
    00106         static SymMap& get_dag() { return dag; }
    00107
    00108         /* This function can be set to create some UniqueNodeStats derivative that can contain extra stats for a node,
    00109          * it can for instance be used to create ERC's and what not. */
    00110         static void set_factory_function(UniqueNodeStats* (*f)(const Sym&)) { factory=f; }
    00111         static void clear_factory_function() { factory = 0; }
    00112
    00113         static const std::vector<unsigned>& token_refcount() { return token_count; }
    00114
    00115         unsigned address() const { return reinterpret_cast<unsigned>(&*node); }
    00116
    00117     private :
    00118
    00119         // implements getting subtrees
    00120         Sym private_get(size_t w) const;
    00121
    00122         unsigned __unchecked_refcount() const { return node->second.refcount; }
    00123
    00124         void incref() {
    00125             if (!empty()) {
    00126                 ++(node->second.refcount);
    00127                 ++token_count[token()];
    00128             }
    00129         }
    00130         void decref() {
    00131             if (!empty()) {
    00132                 --token_count[token()];
    00133                 if (--(node->second.refcount) == 0) {
    00134                     dag.erase(node);
    00135                 }
    00136             }
    00137         }
    00138
    00139         // The one and only data member, an iterator into the static map below
    00140         SymIterator node;
    00141
    00142         // A static hash_map that contains all live nodes..
    00143         static SymMap dag;
    00144
    00145         static std::vector<unsigned> token_count;
    00146
    00147         // Factory function for creating extra node stats, default will be 0
    00148         static UniqueNodeStats* (*factory)(const Sym&);
    00149
    00150 };
    00151
    00152 /* Utility hash functor for syms */
    00153 class HashSym {
    00154     public:
    00155     int operator()(const Sym& sym) const { return sym.hashcode(); }
    00156 };
    00157
    00158 /* Utility Functions */
    00159
    00160 // get_subtree retrieves a subtree by standard ordering (0=root, and then depth first)
    00161 Sym get_subtree(const Sym& org, size_t w);
    00162
    00163 // insert_subtree uses the same ordering as get and inserts the second argument, returning a new tree
    00164 Sym insert_subtree(const Sym& org, size_t w, const Sym& nw);
    00165
    00166 /* Get the successor from the hashtable, no particular purpose other than an interesting way to mutate */
    00167 inline Sym next(const Sym& sym) {
    00168     SymIterator it = sym.iterator();
    00169     ++it;
    00170     if (it == Sym::get_dag().end()) it = Sym::get_dag().begin();
    00171     return Sym(it);
    00172 }
    00173
    00174 #endif