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;
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;
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;
}
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
{
return !(*this == other);
}
+
+ void recollect (dwarf_output_collector *c)
+ {
+ std::transform (begin (), end (), begin (),
+ std::bind2nd (make<compile_units> (), c));
+ }
};
private:
}
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
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>
#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>
{
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)
+ {}
+ };
+
};
};
#include "c++/dwarf_edit"
#include "c++/dwarf_comparator"
#include "c++/dwarf_tracker"
+#include "c++/dwarf_output"
using namespace elfutils;
using namespace std;
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;