summaryrefslogtreecommitdiff
path: root/indra
diff options
context:
space:
mode:
authorNat Goodspeed <nat@lindenlab.com>2012-07-11 08:20:14 -0400
committerNat Goodspeed <nat@lindenlab.com>2012-07-11 08:20:14 -0400
commit578d70dec0a01b5ed7b461c38503c082ac1a3608 (patch)
treecc044993b989c727597d57e42af14f13e6783b2f /indra
parent18bd525d00ee3ce16164900293ee6ea8c2204589 (diff)
MAINT-1175: Change LLTypeInfoLookup API for future optimizations.
Per discussion with Richard, accept the type key for insert() and find() as a template parameter rather than as std::type_info*. This permits (e.g.) some sort of compile-time prehashing for common types, without changing the API. Eliminate iterators from the API altogether, thus avoiding costs associated with transform_iterator. Fix existing references in llinitparam.h.
Diffstat (limited to 'indra')
-rw-r--r--indra/llcommon/llinitparam.h24
-rw-r--r--indra/llcommon/lltypeinfolookup.h90
2 files changed, 38 insertions, 76 deletions
diff --git a/indra/llcommon/llinitparam.h b/indra/llcommon/llinitparam.h
index 99983a19cb..c0170e533b 100644
--- a/indra/llcommon/llinitparam.h
+++ b/indra/llcommon/llinitparam.h
@@ -242,20 +242,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 +263,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 +281,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;
diff --git a/indra/llcommon/lltypeinfolookup.h b/indra/llcommon/lltypeinfolookup.h
index 679cc51f1d..5267e3d2fb 100644
--- a/indra/llcommon/lltypeinfolookup.h
+++ b/indra/llcommon/lltypeinfolookup.h
@@ -13,11 +13,8 @@
#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/optional.hpp>
#include <typeinfo>
-#include <map>
/**
* LLTypeInfoLookup is specifically designed for use cases for which you might
@@ -26,87 +23,52 @@
* 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.
+ typedef boost::unordered_map<const char*, VALUE> 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);
- }
-
- iterator find(const std::type_info* key)
- {
- return transform(mMap.find(key->name()));
+ // 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;
}
- const_iterator find(const std::type_info* key) const
+ template <typename KEY>
+ boost::optional<value_type> find() 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;
};