1. simon_linden
  2. viewer-rabbit

Commits

nat_linden  committed ed03a29

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.

  • Participants
  • Parent commits a25bfa8
  • Branches default

Comments (0)

Files changed (2)

File indra/llcommon/llinitparam.h

View file
 
 		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;
 		}
 		// 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;
 		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;

File indra/llcommon/lltypeinfolookup.h

View file
 #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
  * 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)
+    template <typename KEY>
+    bool insert(const value_type& value)
     {
-        return insert(value_type(key, value));
+        // Obtain and store the std::type_info::name() string as the key.
+        // 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;
     }
 
-    std::pair<iterator, bool> insert(const value_type& pair)
+    template <typename KEY>
+    boost::optional<value_type> find() const
     {
-        // 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()));
-    }
-
-    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;
 };