]> git.ipfire.org Git - thirdparty/elfutils.git/commitdiff
unfinished
authorRoland McGrath <roland@redhat.com>
Tue, 16 Jun 2009 13:03:42 +0000 (06:03 -0700)
committerRoland McGrath <roland@redhat.com>
Fri, 26 Jun 2009 03:38:40 +0000 (20:38 -0700)
libdw/c++/dwarf_output
libdw/c++/subr.hh
src/dwarfcmp.cc

index d4d2ee6111b513c071a11f5630620e207d54ed66..ac015c74e10f222e4367a00b073a0de0334a9f88 100644 (file)
 
 namespace elfutils
 {
+  class dwarf_output_collector;
+
   class dwarf_output
   {
+  public:
+    class compile_units;
+    class debug_info_entry;
+    typedef debug_info_entry compile_unit;
+
+  private:
+    template<typename input>
+    static inline const input &
+    collect (dwarf_output_collector *c,
+            const subr::auto_ref<const input> &p)
+    {
+      return static_cast<const input &> (p);
+    }
+
+    template<typename input>
+    static inline const debug_info_entry &
+    collect (dwarf_output_collector *,
+            const typename input::debug_info_entry &);
+
   public:
     class compile_units;
 
@@ -79,52 +100,32 @@ namespace elfutils
 
     class debug_info_entry
     {
-    public:
-
-      class children : public std::vector<debug_info_entry>
-      {
-       friend class debug_info_entry;
-      private:
-        children () {}
-
-       template<typename childrens>
-       children (const childrens &other)
-         : std::vector<debug_info_entry> (other.begin (), other.end ()) {}
-      };
-
-      class attributes : public std::map<int, attr_value>
-      {
-       friend class debug_info_entry;
-      private:
-       attributes () {}
-
-       template<typename attrs>
-       attributes (const attrs &other)
-         : std::map<int, attr_value> (other.begin (), other.end ()) {}
-
-      public:
-       template<typename attrs>
-       inline operator attrs () const
-       {
-         return attrs (begin (), end ());
-       }
-      };
+      friend class dwarf_output;
 
     private:
+      typedef subr::hashed_unordered_map<int, attr_value> _attributes;
+      typedef subr::hashed_vector<debug_info_entry> _children;
+
       const int _m_tag;
-      const attributes _m_attributes;
-      const children _m_children;
+      const _attributes _m_attributes;
+      const _children _m_children;
+      size_t _m_hash;
 
-    public:
       /* The template constructor lets us copy in from any class that has
         compatibly iterable containers for attributes and children.  */
-      template<typename die>
-      debug_info_entry (const die &die)
+      template<typename die_type>
+      debug_info_entry (const die_type &die)
        : _m_tag (die.tag ()),
          _m_attributes (die.attributes ()),
-         _m_children (die.children ())
-      {}
+         _m_children (die.children ()),
+         _m_hash (0)
+      {
+       subr::hash_combine (_m_hash, _m_tag);
+       subr::hash_combine (_m_hash, _m_attributes);
+       subr::hash_combine (_m_hash, _m_children);
+      }
 
+    public:
       inline int tag () const
       {
        return _m_tag;
@@ -135,20 +136,12 @@ namespace elfutils
        return !_m_children.empty ();
       }
 
-      inline class children &children ()
-      {
-       return _m_children;
-      }
-      inline const class children &children () const
+      inline const _children &children () const
       {
        return _m_children;
       }
 
-      inline class attributes &attributes ()
-      {
-       return _m_attributes;
-      }
-      inline const class attributes &attributes () const
+      inline const _attributes &attributes () const
       {
        return _m_attributes;
       }
@@ -162,27 +155,63 @@ namespace elfutils
       template<typename die>
       bool operator!= (const die &other) const
       {
-       return !(*this == other);;
+       return !(*this == other);
       }
     };
 
-    typedef debug_info_entry::attributes::value_type attribute;
+    typedef debug_info_entry::_attributes::value_type attribute;
 
-    class compile_unit : public debug_info_entry
-    {
-    };
-
-    // Main container anchoring all the output.
-    class compile_units : public std::vector<compile_unit>
+  public:
+    /* Main container anchoring all the output.
+
+       This is the only container that actually lives in the dwarf_output
+       object.  All others live in the dwarf_output_collector's sets, and
+       we return const references to those copies.
+
+       This vector is actually mutable as a std::vector.  But note that you
+       should never remove a compile_unit, though you can reorder the
+       vector.  Nothing is ever removed from the collector, so your final
+       output file can wind up with unreferenced data being encoded.  If
+       you do remove any elements, then you should start a fresh collector
+       and construct a new dwarf_output object by copying using that
+       collector (or, equivalently, call o.compile_units ().recollect (C)
+       on the new collector C).  */
+    class compile_units
+      : public std::vector<subr::auto_ref<const debug_info_entry> >
     {
       friend class dwarf_output;
     private:
-      // Constructor copying CUs from input container.
+      typedef std::vector<subr::auto_ref<const debug_info_entry> > _base;
+
       template<typename input>
-      compile_units(const input &units)
-       : std::vector<compile_unit> (units.begin (), units.end ())
+      struct make
+       : public std::binary_function<typename input::value_type,
+                                     dwarf_output_collector *,
+                                     _base::value_type>
+      {
+       _base::value_type operator () (const typename input::value_type &cu,
+                                      dwarf_output_collector *c) const
+       {
+         return _base::value_type (collect (c, cu));
+       }
+      };
+
+      // Construct empty container.
+      compile_units ()
+       : _base ()
       {}
 
+      // Constructor copying CUs from input container.
+      template<typename input>
+      compile_units (const input &units, dwarf_output_collector *c)
+       : _base ()
+      {
+       for (typename input::const_iterator it = units.begin ();
+            it != units.end ();
+            ++it)
+         push_back (make<input> () (*it, c));
+      }
+
     public:
       template<typename other_children>
       bool operator== (const other_children &other) const
@@ -194,6 +223,12 @@ namespace elfutils
       {
        return !(*this == other);
       }
+
+      void recollect (dwarf_output_collector *c)
+      {
+       std::transform (begin (), end (), begin (),
+                       std::bind2nd (make<compile_units> (), c));
+      }
     };
 
   private:
@@ -206,9 +241,17 @@ namespace elfutils
     }
 
   public:
-    // Constructor copying CUs from an input file (dwarf or dwarf_output).
+    // Constructor for an empty file, can add to its compile_units ().
+    dwarf_output ()
+      : _m_units ()
+    {}
+
+    // Constructor copying CUs from an input file (can be any of dwarf,
+    // dwarf_edit, or dwarf_output).
     template<typename input>
-    dwarf_output (const input &dw) : _m_units (dw.compile_units ()) {}
+    dwarf_output (const input &dw, dwarf_output_collector *c)
+      : _m_units (dw.compile_units (), c)
+    {}
 
     template<typename file>
     inline bool operator== (const file &other) const
@@ -221,4 +264,24 @@ namespace elfutils
       return !(*this == other);
     }
   };
-}
+
+  class dwarf_output_collector
+  {
+    friend class dwarf_output;
+
+  private:
+    subr::value_set<dwarf_output::debug_info_entry> _m_die;
+
+  };
+
+  template<typename input>
+  inline const dwarf_output::debug_info_entry &
+  dwarf_output::collect (dwarf_output_collector *c,
+                        const typename input::debug_info_entry &die)
+  {
+    return c->_m_die.add (die);
+  }
+
+};
+
+#endif // <elfutils/dwarf_output>
index e11846279356188df18bee241b8da9dd3f883d62..527f0c073193247bc20c262926369f716a4f97ea 100644 (file)
 #include <cstring>
 #include <iostream>
 #include <sstream>
+#include <tr1/unordered_map>
+#include <tr1/unordered_set>
+#include <vector>
+#include <algorithm>
 
 namespace elfutils
 {
   namespace subr
   {
+    // XXX
+    template<typename T>
+    struct hash { };
+
+    template <typename T>
+    inline void hash_combine (size_t &seed, const T &v)
+    {
+      seed ^= hash<T> (v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
+    }
+
     template<typename string>
     struct name_equal : public std::binary_function<const char *, string, bool>
     {
@@ -262,6 +276,174 @@ namespace elfutils
        return indexed_iterator (_m_contents, _m_idx--);
       }
     };
+
+    // Pair of some value and its precomputed hash.
+    template<typename value_type>
+    class hashed_value
+      : public std::pair<size_t, const value_type>
+    {
+    private:
+      typedef std::pair<size_t, const value_type> _base;
+
+    public:
+      hashed_value (const value_type &v)
+       : _base (subr::hash<value_type> (v), v) {}
+      hashed_value (const hashed_value<value_type> &v)
+       : _base (v.first, v.second) {}
+
+      bool operator== (const hashed_value<value_type> &other)
+       const
+      {
+       return other.first == this->first && other.second == this->second;
+      }
+
+      struct hasher
+       : public std::unary_function<hashed_value<value_type>, size_t>
+      {
+       size_t operator () (const hashed_value<value_type> &v)
+       {
+         return v.first;
+       }
+      };
+    };
+
+    // Set of hashed_value's.
+    template<typename value_type>
+    class value_set
+      : public std::tr1::unordered_set<hashed_value<value_type>,
+                                      struct hashed_value<value_type>::hasher>
+    {
+    public:
+      typedef hashed_value<value_type> hashed_value_type;
+
+    private:
+      typedef std::tr1::unordered_set<hashed_value_type,
+                                     struct hashed_value_type::hasher> _base;
+
+    public:
+      const value_type &add (const value_type &v)
+      {
+       std::pair<class _base::iterator, bool> p
+         = _base::insert (hashed_value_type (v));
+       if (p.second)
+         {
+           // XXX hook for collection: abbrev building, etc.
+         }
+       return *p.first;
+      };
+    };
+
+    // A vector of hashed_value's that itself acts like a hashed_value.
+    template<typename value_type>
+    class hashed_vector
+      : public std::vector<hashed_value<value_type> >
+    {
+    private:
+      typedef hashed_value<value_type> elt_type;
+      typedef std::vector<elt_type> _base;
+
+      size_t _m_hash;
+
+    public:
+      template<typename iterator>
+      hashed_vector (iterator first, iterator last)
+       : _base (first, last), _m_hash (0)
+      {
+       struct hashit
+       {
+         size_t &_m_hash;
+         hashit (size_t &h) : _m_hash (h) {}
+         inline void operator () (const elt_type &p)
+         {
+           subr::hash_combine (_m_hash, p.first);
+         }
+       };
+       std::for_each (_base::begin (), _base::end (), hashit (_m_hash));
+      }
+
+      template<typename container>
+      hashed_vector (const container &other)
+       : hashed_vector (other.begin (), other.end ())
+      {}
+
+      bool operator== (const hashed_vector &other) const
+      {
+       return (other._m_hash == _m_hash &&
+               other.size () == _base::size ()
+               && std::equal (_base::begin (), _base::end (), other.begin ()));
+      }
+
+      struct hasher
+       : public std::unary_function<hashed_vector<value_type>, size_t>
+      {
+       size_t operator () (const hashed_vector<value_type> &v)
+       {
+         return v._m_hash;
+       }
+      };
+    };
+
+    // An unordered_map of hashed_value's that itself acts like a hashed_value.
+    template<typename key_type, typename value_type>
+    class hashed_unordered_map
+      : public std::tr1::unordered_map<key_type,
+                                      hashed_value<value_type>,
+                                      class hashed_value<value_type>::hasher>
+    {
+    private:
+      typedef std::tr1::unordered_map<key_type,
+                                     hashed_value<value_type>,
+                                     class hashed_value<value_type>::hasher>
+      _base;
+
+      size_t _m_hash;
+
+    public:
+      template<typename iterator>
+      hashed_unordered_map (iterator first, iterator last)
+       : _base (first, last), _m_hash (0)
+      {
+       class hashit
+       {
+         size_t &_m_hash;
+         hashit (size_t &h) : _m_hash (h) {}
+
+         void operator () (const typename _base::value_type &p)
+         {
+           subr::hash_combine (_m_hash, subr::hash<key_type> (p.first));
+           subr::hash_combine (_m_hash, p.second.first);
+         }
+       };
+       std::for_each (_base::begin (), _base::end (), hashit (_m_hash));
+      }
+
+      template<typename container>
+      hashed_unordered_map (const container &other)
+       : hashed_unordered_map (other.begin (), other.end ())
+      {}
+    };
+
+    template<typename T>
+    class auto_ref
+    {
+    private:
+      T *_m_ptr;
+
+    public:
+      auto_ref (const T &other)
+       : _m_ptr (&other)
+      {}
+
+      inline operator T& () const
+      {
+       return *_m_ptr;
+      }
+
+      auto_ref (const auto_ref<T> &other)
+       : _m_ptr (other._m_ptr)
+      {}
+    };
+
   };
 };
 
index ecadfd52b72d1d6ed1b9459bd91e0877fb2de75a..370f1ad06795d8a0e96862da55e9af5dad1e1145 100644 (file)
@@ -47,6 +47,7 @@
 #include "c++/dwarf_edit"
 #include "c++/dwarf_comparator"
 #include "c++/dwarf_tracker"
+#include "c++/dwarf_output"
 
 using namespace elfutils;
 using namespace std;
@@ -313,9 +314,26 @@ main (int argc, char *argv[])
 
       if (test_writer)
        {
-         dwarf_edit out1 (file1);
-         dwarf_edit out2 (file2);
-         test_classes (file1, file2, out1, out2, same);
+         dwarf_edit edit1 (file1);
+         dwarf_edit edit2 (file2);
+         test_classes (file1, file2, edit1, edit2, same);
+
+         {
+           dwarf_output_collector c1;
+           dwarf_output_collector c2;
+           dwarf_output out1 (file1, &c1);
+           dwarf_output out2 (file2, &c2);
+           test_classes (file1, file2, out1, out2, same);
+           test_classes (edit1, edit2, out1, out2, same);
+         }
+         {
+           dwarf_output_collector c1;
+           dwarf_output_collector c2;
+           dwarf_output out1 (edit1, &c1);
+           dwarf_output out2 (edit2, &c2);
+           test_classes (file1, file2, out1, out2, same);
+           test_classes (edit1, edit2, out1, out2, same);
+         }
        }
 
       result = !same;