std::string to_string () const;
};
- public:
template<typename impl, bool alloc_values = true>
struct value
{
static const bool delete_value = alloc_values;
+ template<typename flavor>
+ static inline flavor &
+ variant (flavor *&, const value_dispatch *&)
+ {
+ assert (!alloc_values);
+ throw std::logic_error ("can't happen!");
+ }
+
+ template<typename flavor>
+ static inline flavor &
+ variant (flavor *&result, value_dispatch *&value)
+ {
+ assert (alloc_values);
+ if (value == NULL)
+ {
+ result = new flavor;
+ value = result;
+ return *result;
+ }
+ result = dynamic_cast<flavor *> (value);
+ if (result == NULL)
+ throw std::runtime_error ("wrong value type");
+ return *result;
+ }
+
template<typename flavor, typename input, typename arg_type>
static inline value_dispatch *
make (flavor *&result, int /*whatattr*/, const input &x, arg_type &arg)
class attr_value
{
friend class attributes_type<impl, vw>;
+ friend class value<impl>;
- private:
+ protected:
typename vw::value_cell_type *_m_value;
typedef typename impl::debug_info_entry::pointer die_ptr;
template<typename flavor>
inline flavor &variant ()
{
- if (_m_value == NULL)
- _m_value = new flavor;
- return const_variant<flavor> ();
+ flavor *p;
+ return vw::variant (p, _m_value);
}
public:
template<class impl, typename v>
class attributes_type
- : public std::map<int, attr_value<impl, v> >
+ : public std::map<int, typename impl::attr_value>
{
friend class impl::debug_info_entry;
private:
- typedef std::map<int, attr_value<impl, v> > base_type;
+ typedef std::map<int, typename impl::attr_value> base_type;
protected:
inline attributes_type () {}
+ template<typename input, typename arg_type>
+ inline void set (const input &other, arg_type &c)
+ {
+ for (typename input::const_iterator attr = other.begin ();
+ attr != other.end ();
+ ++attr)
+ (*this)[(*attr).first].set ((*attr).first, (*attr).second, c);
+ }
+
public: // XXX should be protected
/* We don't use the base_type (begin, end) iterator constructor here
inline attributes_type (const input &other, arg_type &c)
: base_type ()
{
- for (typename input::const_iterator attr = other.begin ();
- attr != other.end ();
- ++attr)
- (*this)[(*attr).first].set ((*attr).first, (*attr).second, c);
+ set (other, c);
}
-#if 0
- // dwarf_output probably will do it this way (?)
- template<typename input, typename arg_type>
- inline attributes_type (const input &other, arg_type &c)
- : base_type (subr::argify2nd<input, attributes_type, arg_type &>
- (other.begin (), c),
- subr::argify2nd<input, attributes_type, arg_type &>
- (other.end (), c))
- {}
-#endif
-
public:
typedef typename base_type::key_type key_type;
typedef typename base_type::value_type value_type;
#include "dwarf_edit"
#include "dwarf_ref_maker"
#include <functional>
+#include <tr1/unordered_set>
/* Read the comments for elfutils::dwarf first.
class compile_units;
class debug_info_entry;
+ class attr_value;
protected:
template<typename input> class copier; // Below.
public:
- typedef dwarf_data::attr_value<dwarf_output, value> attr_value;
-
class debug_info_entry
{
friend class subr::create_container;
public:
- typedef dwarf_data::attributes_type<dwarf_output, value> attributes_type;
+ class attributes_type
+ : public dwarf_data::attributes_type<dwarf_output, value>
+ {
+ friend class debug_info_entry;
+
+ private:
+ typedef dwarf_data::attributes_type<dwarf_output, value> _base;
+
+ size_t _m_hash;
+
+ inline attributes_type ()
+ : _base (), _m_hash (0)
+ {}
+
+ struct same_attr : public std::equal_to<value_type>
+ {
+ bool operator () (const value_type &a,
+ const value_type &b) const
+ {
+ return a.first == b.first && a.second.is (b.second);
+ }
+ };
+
+ public:
+ friend class subr::hashed_hasher<attributes_type>;
+ typedef subr::hashed_hasher<attributes_type> hasher;
+
+ template<typename input, typename arg_type>
+ inline attributes_type (const input &other, arg_type &c)
+ : _base (other, c), _m_hash (0)
+ {
+ // Precompute our hash value based on our contents.
+ for (iterator i = begin (); i != end (); ++i)
+ subr::hash_combine (_m_hash, *i);
+ }
+
+ inline bool are (const attributes_type &these) const
+ {
+ return (_m_hash == these._m_hash
+ && size () == these.size ()
+ && std::equal (begin (), end (), these.begin (),
+ same_attr ()));
+ }
+ };
class children_type : public std::list<debug_info_entry>
{
protected:
int _m_tag;
- attributes_type _m_attributes;
+ const attributes_type *_m_attributes;
children_type _m_children;
// This is can only be used by the children_type constructor,
// which immediately calls set.
inline debug_info_entry ()
- : _m_tag (-1), _m_attributes (), _m_children ()
+ : _m_tag (-1), _m_attributes (NULL), _m_children ()
{}
- template<typename die_type, typename arg_type>
- inline void set (const die_type &die, arg_type &arg)
+ template<typename die_type, typename input_dw>
+ inline void set (const die_type &die, copier<input_dw> &c)
{
+ assert (_m_attributes == NULL);
try
{
_m_tag = die.tag ();
- _m_attributes.swap (attributes_type (die.attributes (), arg));
- _m_children.swap (children_type (die.children (), arg));
+ _m_attributes = c.add_attributes (die.attributes ());
+ _m_children.swap (children_type (die.children (), c));
}
catch (...)
{
// Never leave a partially-formed DIE.
_m_tag = -1;
- _m_attributes.clear ();
+ _m_attributes = NULL;
_m_children.clear ();
throw;
};
public:
inline debug_info_entry (int t)
- : _m_tag (t), _m_attributes (), _m_children ()
+ : _m_tag (t), _m_attributes (NULL), _m_children ()
{
if (unlikely (t <= 0))
throw std::invalid_argument ("invalid tag");
/* The template constructor lets us copy in from any class that has
compatibly iterable containers for attributes and children. */
- template<typename die_type, typename tracker>
- debug_info_entry (const die_type &die, tracker &t)
+ template<typename die_type, typename input_dw>
+ debug_info_entry (const die_type &die, copier<input_dw> &c)
: _m_tag (die.tag ()),
- _m_attributes (die.attributes (), t),
- _m_children (die.children (), t)
+ _m_attributes (c.add_attributes (die.attributes ())),
+ _m_children (die.children (), c)
{}
inline int tag () const
inline const attributes_type &attributes () const
{
- return _m_attributes;
+ return *_m_attributes;
}
template<typename die>
}
};
+ class attr_value
+ : public dwarf_data::attr_value<dwarf_output, value>
+ {
+ private:
+ typedef dwarf_data::attr_value<dwarf_output, value> _base;
+
+ public:
+
+ /* These constructors can only be used by the containers
+ used in the collector. The attributes_type map in an
+ actual debug_info_entry object is always const. */
+ inline attr_value ()
+ : _base ()
+ {}
+
+ inline attr_value (const attr_value &other)
+ : _base ()
+ {
+ this->_m_value = other._m_value;
+ }
+
+ /* Two identical values in fact share the same cell in the collector.
+ So we can use simple pointer comparison here. */
+ inline bool is (const attr_value &that) const
+ {
+ return this->_m_value == that._m_value;
+ }
+
+ // The is () test works only on a dwarf_output sharing the same collector.
+ inline bool operator== (const attr_value &other) const
+ {
+ return is (other) || _base::operator== (other);
+ }
+ inline bool operator!= (const attr_value &other) const
+ {
+ return !(*this == other);
+ }
+
+ /* We can use the _m_value pointer itself as a perfect hash, because
+ all identical values share the same cell in the collector. */
+ struct hasher : public std::unary_function<attr_value, size_t>
+ {
+ inline size_t operator () (const attr_value &v) const
+ {
+ return (uintptr_t) v._m_value;
+ }
+ };
+ };
+
typedef debug_info_entry::attributes_type::value_type attribute;
typedef dwarf_data::compile_unit<dwarf_output> compile_unit;
}
};
+ /*
+template<typename flavor>
+ inline flavor &dwarf_output::attr_value::_base::flavor ()
+ {
+ assert (!"should be impossible");
+ throw std::logic_error ("should be impossible");
+ }
+ */
+
// Explicit specializations.
template<>
std::string
friend class dwarf_output;
private:
+ typedef dwarf_output::debug_info_entry die_type;
+ typedef die_type::attributes_type attrs_type;
+
subr::value_set<dwarf_output::value::value_string> _m_strings;
subr::value_set<dwarf_output::value::value_identifier> _m_identifiers;
subr::value_set<dwarf_output::value::value_address> _m_address;
{
return flag ? &flag_true : &flag_false;
}
+
+ struct same_attrs : public std::equal_to<die_type::attributes_type>
+ {
+ bool operator () (const die_type::attributes_type &a,
+ const die_type::attributes_type &b) const
+ {
+ return a.are (b);
+ }
+ };
+
+ typedef std::tr1::unordered_set<attrs_type, attrs_type::hasher,
+ same_attrs> attrs_set;
+ attrs_set _m_attr_sets;
+
+ template<typename input, typename copier_type>
+ inline const attrs_type *add_attributes (const input &x, copier_type &c)
+ {
+ std::pair<attrs_set::iterator, bool> p
+ = _m_attr_sets.insert (attrs_type (x, c));
+ if (p.second)
+ {
+ // XXX hook for collection: abbrev building, etc.
+ }
+ return &(*p.first);
+ }
+
};
template<class dw>
{
return _m_collector->_m_locations.add (x);
}
+
+ template<typename input>
+ inline const debug_info_entry::attributes_type *
+ add_attributes (const input &x)
+ {
+ return _m_collector->add_attributes (x, *this);
+ }
};
// Copy construction instantiates a copier derived from the collector.