On Wed, 2010-10-06 at 13:55 -0700, Roland McGrath wrote:
> template<typename input, typename arg_type>
> const value_type *add (const input &v, arg_type &arg)
> {
> return add (value_type (v, arg));
> }
>
> So it will always create a new value_type
Right. That's because in practice the input is always of a different
type, not the actual value_type. e.g., the input value argument will be
a const char * or a const std::string, when the value_type is actually
dwarf_output::value::value_string. The value_string template constructor
handles those as input types.
Thanks for the concrete example. This is actually what I keep missing,
every time I try to match concepts to code. The actual types (after
template instantiation) of some of these argument. While trying to
follow the arguments going down I somehow missed we extracted the actual
value data and that this is the input type here. Which is obvious in
retrospect if you realize that the value_type must be a concrete
initializer which takes as argument the actual data payload (not the
original dwarf/dwarf_edit::value::value_xxx). Sigh. But then what is
this arg_type &arg?
For example, dwarf_data::value_string is the element type inside the
_m_strings set. A value_string is derived from std::string and its
template constructor passes the input value argument to the normal
std::string constructor. That takes a std::string or a const char *, so
we just get the copied string. value_string::hasher uses more layers of
subr::hash* stuff, so it turns into a normal string hash function
(algorithm stolen from boost).
Why not use std::tr1::hash<std::string &> ?
When it gets into the value_set, it's wrapped in a
hashed_value<value_string>
object, which is just the value_string with its precomputed hash value.
The standard unordered_set logic then does the actual hash table insertion,
but its "hash function" is just to fetch the stored _m_hash from the
hashed_value<value_string>.
Aha. Sorry I was again confused about which hash function was being
used. But indeed we are using the hashed_value_type::hasher, not the
value_type::hasher. Doh.
This is so that we aren't recomputing the
string hash function of the elements inside each hash bucket to compare
to the new element, just doing integer comparison on the saved _m_hash.
The value_set::add method always returns the pointer to the object
sitting in the hash bucket. If this value was already in the set,
we haven't added anything. In either case, we just throw away the
just-created value_type (e.g. value_string) object, because unordered_set
stores its own copy.
That all makes sense, except for the throwing away. That seems wasteful,
but might be the best we can do when reusing the sdt unordered_set?
All of this stuff is essentially uninteresting. It's just the
layers of
C++ hooey to keep a hash table for each value_something type, and return
the const value_something * pointing into that hash table.
Yeah, sorry that I keep getting lost in the uninteresting stuff.
Thanks,
Mark