MAINT-1175: merge backout LLRegistrySingleton<std::type_info::name()>

master
Nat Goodspeed 2012-07-18 16:31:22 -04:00
commit 5e1e44ca7e
4 changed files with 95 additions and 96 deletions

View File

@ -212,14 +212,6 @@ namespace LLInitParam
public:
struct CompareTypeID
{
bool operator()(const std::type_info* lhs, const std::type_info* rhs) const
{
return lhs->before(*rhs);
}
};
typedef std::vector<std::pair<std::string, bool> > name_stack_t;
typedef std::pair<name_stack_t::iterator, name_stack_t::iterator> name_stack_range_t;
typedef std::vector<std::string> possible_values_t;
@ -242,20 +234,20 @@ namespace LLInitParam
template <typename T> bool readValue(T& param)
{
parser_read_func_map_t::iterator found_it = mParserReadFuncs->find(&typeid(T));
if (found_it != mParserReadFuncs->end())
boost::optional<parser_read_func_t> found_it = mParserReadFuncs->find<T>();
if (found_it)
{
return found_it->second(*this, (void*)&param);
return (*found_it)(*this, (void*)&param);
}
return false;
}
template <typename T> bool writeValue(const T& param, name_stack_t& name_stack)
{
parser_write_func_map_t::iterator found_it = mParserWriteFuncs->find(&typeid(T));
if (found_it != mParserWriteFuncs->end())
boost::optional<parser_write_func_t> found_it = mParserWriteFuncs->find<T>();
if (found_it)
{
return found_it->second(*this, (const void*)&param, name_stack);
return (*found_it)(*this, (const void*)&param, name_stack);
}
return false;
}
@ -263,10 +255,10 @@ namespace LLInitParam
// dispatch inspection to registered inspection functions, for each parameter in a param block
template <typename T> bool inspectValue(name_stack_t& name_stack, S32 min_count, S32 max_count, const possible_values_t* possible_values)
{
parser_inspect_func_map_t::iterator found_it = mParserInspectFuncs->find(&typeid(T));
if (found_it != mParserInspectFuncs->end())
boost::optional<parser_inspect_func_t> found_it = mParserInspectFuncs->find<T>();
if (found_it)
{
found_it->second(name_stack, min_count, max_count, possible_values);
(*found_it)(name_stack, min_count, max_count, possible_values);
return true;
}
return false;
@ -281,14 +273,14 @@ namespace LLInitParam
template <typename T>
void registerParserFuncs(parser_read_func_t read_func, parser_write_func_t write_func = NULL)
{
mParserReadFuncs->insert(std::make_pair(&typeid(T), read_func));
mParserWriteFuncs->insert(std::make_pair(&typeid(T), write_func));
mParserReadFuncs->insert<T>(read_func);
mParserWriteFuncs->insert<T>(write_func);
}
template <typename T>
void registerInspectFunc(parser_inspect_func_t inspect_func)
{
mParserInspectFuncs->insert(std::make_pair(&typeid(T), inspect_func));
mParserInspectFuncs->insert<T>(inspect_func);
}
bool mParseSilently;

View File

@ -34,9 +34,21 @@
#include "lltypeinfolookup.h"
template <typename T>
class LLRegistryDefaultComparator
struct LLRegistryDefaultComparator
{
bool operator()(const T& lhs, const T& rhs) { return lhs < rhs; }
// It would be Bad if this comparison were used for const char*
BOOST_STATIC_ASSERT(! (boost::is_same<typename boost::remove_const<typename boost::remove_pointer<T>::type>::type, char>::value));
bool operator()(const T& lhs, const T& rhs) const { return lhs < rhs; }
};
// comparator for const char* registry keys
template <>
struct LLRegistryDefaultComparator<const char*>
{
bool operator()(const char* lhs, const char* rhs) const
{
return strcmp(lhs, rhs) < 0;
}
};
template <typename KEY, typename VALUE>
@ -72,7 +84,7 @@ public:
{
friend class LLRegistry<KEY, VALUE, COMPARATOR>;
public:
typedef typename LLRegistryMapSelector<KEY, VALUE>::type registry_map_t;
typedef std::map<KEY, VALUE, COMPARATOR> registry_map_t;
bool add(ref_const_key_t key, ref_const_value_t value)
{

View File

@ -13,11 +13,47 @@
#define LL_LLTYPEINFOLOOKUP_H
#include <boost/unordered_map.hpp>
#include <boost/function.hpp>
#include <boost/mem_fn.hpp>
#include <boost/iterator/transform_iterator.hpp>
#include <boost/functional/hash.hpp>
#include <boost/optional.hpp>
#include <functional> // std::binary_function
#include <typeinfo>
#include <map>
/**
* The following helper classes are based on the Boost.Unordered documentation:
* http://www.boost.org/doc/libs/1_45_0/doc/html/unordered/hash_equality.html
*/
/**
* Compute hash for a string passed as const char*
*/
struct const_char_star_hash: public std::unary_function<const char*, std::size_t>
{
std::size_t operator()(const char* str) const
{
std::size_t seed = 0;
for ( ; *str; ++str)
{
boost::hash_combine(seed, *str);
}
return seed;
}
};
/**
* Compute equality for strings passed as const char*
*
* I (nat) suspect that this is where the default behavior breaks for the
* const char* values returned from std::type_info::name(). If you compare the
* two const char* pointer values, as a naive, unspecialized implementation
* will surely do, they'll compare unequal.
*/
struct const_char_star_equal: public std::binary_function<const char*, const char*, bool>
{
bool operator()(const char* lhs, const char* rhs) const
{
return strcmp(lhs, rhs) == 0;
}
};
/**
* LLTypeInfoLookup is specifically designed for use cases for which you might
@ -26,87 +62,55 @@
* you can't rely on always getting the same std::type_info* for a given type:
* different load modules will produce different std::type_info*.
* LLTypeInfoLookup contains a workaround to address this issue.
*
* The API deliberately diverges from std::map in several respects:
* * It avoids iterators, not only begin()/end() but also as return values
* from insert() and find(). This bypasses transform_iterator overhead.
* * Since we literally use compile-time types as keys, the essential insert()
* and find() methods accept the key type as a @em template parameter,
* accepting and returning value_type as a normal runtime value. This is to
* permit future optimization (e.g. compile-time type hashing) without
* changing the API.
*/
template <typename VALUE>
class LLTypeInfoLookup
{
// We present an interface like this:
typedef std::map<const std::type_info*, VALUE> intf_map_type;
// Use this for our underlying implementation: lookup by
// std::type_info::name() string. Note that we must store a std::pair<const
// std::type_info*, VALUE> -- in other words, an intf_map_type::value_type
// pair -- so we can present iterators that do the right thing.
// (This might result in a lookup with one std::type_info* returning an
// iterator to a different std::type_info*, but frankly, my dear, we don't
// give a damn.)
typedef boost::unordered_map<std::string, typename intf_map_type::value_type> impl_map_type;
// Iterator shorthand
typedef typename intf_map_type::iterator intf_iterator;
typedef typename intf_map_type::const_iterator intf_const_iterator;
typedef typename intf_map_type::value_type intf_value_type;
typedef typename impl_map_type::iterator impl_iterator;
typedef typename impl_map_type::const_iterator impl_const_iterator;
typedef typename impl_map_type::value_type impl_value_type;
// Type of function that transforms impl_value_type to intf_value_type
typedef boost::function<intf_value_type&(impl_value_type&)> iterfunc;
typedef boost::function<const intf_value_type&(const impl_value_type&)> const_iterfunc;
// std::type_info::name() string. This is one of the rare cases in which I
// dare use const char* directly, rather than std::string, because I'm
// sure that every value returned by std::type_info::name() is static.
// HOWEVER, specify our own hash + equality functors: naively comparing
// distinct const char* values won't work.
typedef boost::unordered_map<const char*, VALUE,
const_char_star_hash, const_char_star_equal> impl_map_type;
public:
typedef LLTypeInfoLookup<VALUE> self;
typedef typename intf_map_type::key_type key_type;
typedef typename intf_map_type::mapped_type mapped_type;
typedef intf_value_type value_type;
// Iterators are different because we have to transform
// impl_map_type::iterator to intf_map_type::iterator.
typedef boost::transform_iterator<iterfunc, impl_iterator> iterator;
typedef boost::transform_iterator<const_iterfunc, impl_const_iterator> const_iterator;
typedef VALUE value_type;
LLTypeInfoLookup() {}
iterator begin() { return transform(mMap.begin()); }
iterator end() { return transform(mMap.end()); }
const_iterator begin() const { return const_transform(mMap.begin()); }
const_iterator end() const { return const_transform(mMap.end()); }
bool empty() const { return mMap.empty(); }
std::size_t size() const { return mMap.size(); }
// Shorthand -- I've always wished std::map supported this signature.
std::pair<iterator, bool> insert(const std::type_info* key, const VALUE& value)
{
return insert(value_type(key, value));
}
std::pair<iterator, bool> insert(const value_type& pair)
template <typename KEY>
bool insert(const value_type& value)
{
// Obtain and store the std::type_info::name() string as the key.
// Save the whole incoming pair as the value!
std::pair<impl_iterator, bool>
inserted(mMap.insert(impl_value_type(pair.first->name(), pair)));
// Have to transform the iterator before returning.
return std::pair<iterator, bool>(transform(inserted.first), inserted.second);
// Return just the bool from std::map::insert()'s return pair.
return mMap.insert(typename impl_map_type::value_type(typeid(KEY).name(), value)).second;
}
iterator find(const std::type_info* key)
template <typename KEY>
boost::optional<value_type> find() const
{
return transform(mMap.find(key->name()));
}
const_iterator find(const std::type_info* key) const
{
return const_transform(mMap.find(key->name()));
// Use the std::type_info::name() string as the key.
typename impl_map_type::const_iterator found = mMap.find(typeid(KEY).name());
if (found == mMap.end())
return boost::optional<value_type>();
return found->second;
}
private:
iterator transform(impl_iterator iter)
{
return iterator(iter, boost::mem_fn(&impl_value_type::second));
}
const_iterator const_transform(impl_const_iterator iter)
{
return const_iterator(iter, boost::mem_fn(&impl_value_type::second));
}
impl_map_type mMap;
};

View File

@ -34,15 +34,6 @@
class LLView;
// sort functor for typeid maps
struct LLCompareTypeID
{
bool operator()(const std::type_info* lhs, const std::type_info* rhs) const
{
return lhs->before(*rhs);
}
};
// lookup widget constructor funcs by widget name
template <typename DERIVED_TYPE>
class LLChildRegistry : public LLRegistrySingleton<std::string, LLWidgetCreatorFunc, DERIVED_TYPE>