diff options
| -rw-r--r-- | .hgtags | 1 | ||||
| -rw-r--r-- | indra/llcommon/llinitparam.h | 16 | ||||
| -rw-r--r-- | indra/llcommon/llregistry.h | 30 | ||||
| -rw-r--r-- | indra/llcommon/llstl.h | 51 | ||||
| -rw-r--r-- | indra/llcommon/lltypeinfolookup.h | 141 | ||||
| -rw-r--r-- | indra/llui/lluictrlfactory.h | 14 | ||||
| -rw-r--r-- | indra/newview/llnamelistctrl.cpp | 21 | ||||
| -rw-r--r-- | indra/newview/llnamelistctrl.h | 41 | 
8 files changed, 171 insertions, 144 deletions
| @@ -349,3 +349,4 @@ ab2ffc547c8a8950ff187c4f6c95e5334fab597b 3.3.4-beta5  28e100d0379a2b0710c57647a28fc5239d3d7b99 3.3.4-release  a8b3eca451a9eaab59987efb0ab1c4217e3f2dcc DRTVWR-182  1f27cdfdc54246484f8afbbe42ce48e954175cbd 3.4.0-beta1 +81f6b745ef27f5915fd07f988fdec9944f2bb73e DRTVWR-186 diff --git a/indra/llcommon/llinitparam.h b/indra/llcommon/llinitparam.h index 99983a19cb..9a6d1eff5c 100644 --- a/indra/llcommon/llinitparam.h +++ b/indra/llcommon/llinitparam.h @@ -35,7 +35,7 @@  #include <boost/shared_ptr.hpp>  #include "llerror.h" -#include "lltypeinfolookup.h" +#include "llstl.h"  namespace LLInitParam  { @@ -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; @@ -228,9 +220,9 @@ namespace LLInitParam  		typedef bool (*parser_write_func_t)(Parser& parser, const void*, name_stack_t&);  		typedef boost::function<void (name_stack_t&, S32, S32, const possible_values_t*)>	parser_inspect_func_t; -		typedef LLTypeInfoLookup<parser_read_func_t>		parser_read_func_map_t; -		typedef LLTypeInfoLookup<parser_write_func_t>		parser_write_func_map_t; -		typedef LLTypeInfoLookup<parser_inspect_func_t>		parser_inspect_func_map_t; +		typedef std::map<const std::type_info*, parser_read_func_t>		parser_read_func_map_t; +		typedef std::map<const std::type_info*, parser_write_func_t>	parser_write_func_map_t; +		typedef std::map<const std::type_info*, parser_inspect_func_t>	parser_inspect_func_map_t;  		Parser(parser_read_func_map_t& read_map, parser_write_func_map_t& write_map, parser_inspect_func_map_t& inspect_map)  		:	mParseSilently(false), diff --git a/indra/llcommon/llregistry.h b/indra/llcommon/llregistry.h index 36d7f7a44c..853c427a13 100644 --- a/indra/llcommon/llregistry.h +++ b/indra/llcommon/llregistry.h @@ -31,30 +31,16 @@  #include <boost/type_traits.hpp>  #include "llsingleton.h" -#include "lltypeinfolookup.h" +#include "llstl.h"  template <typename T> -class LLRegistryDefaultComparator +struct LLRegistryDefaultComparator  { -	bool operator()(const T& lhs, const T& rhs) { return lhs < rhs; } -}; - -template <typename KEY, typename VALUE> -struct LLRegistryMapSelector -{ -    typedef std::map<KEY, VALUE> type; -}; - -template <typename VALUE> -struct LLRegistryMapSelector<std::type_info*, VALUE> -{ -    typedef LLTypeInfoLookup<VALUE> type; -}; - -template <typename VALUE> -struct LLRegistryMapSelector<const std::type_info*, VALUE> -{ -    typedef LLTypeInfoLookup<VALUE> type; +	bool operator()(const T& lhs, const T& rhs) const +	{ +		using std::less; +		return less<T>()(lhs, rhs); +	}  };  template <typename KEY, typename VALUE, typename COMPARATOR = LLRegistryDefaultComparator<KEY> > @@ -72,7 +58,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)  		{ diff --git a/indra/llcommon/llstl.h b/indra/llcommon/llstl.h index 8ad12c9a03..d3941e1bc9 100644 --- a/indra/llcommon/llstl.h +++ b/indra/llcommon/llstl.h @@ -33,6 +33,7 @@  #include <vector>  #include <set>  #include <deque> +#include <typeinfo>  // Use to compare the first element only of a pair  // e.g. typedef std::set<std::pair<int, Data*>, compare_pair<int, Data*> > some_pair_set_t;  @@ -470,4 +471,54 @@ llbind2nd(const _Operation& __oper, const _Tp& __x)    return llbinder2nd<_Operation>(__oper, _Arg2_type(__x));  } +/** + * Compare std::type_info* pointers a la std::less. We break this out as a + * separate function for use in two different std::less specializations. + */ +inline +bool before(const std::type_info* lhs, const std::type_info* rhs) +{ +#if LL_LINUX && defined(__GNUC__) && ((__GNUC__ < 4) || (__GNUC__ == 4 && __GNUC_MINOR__ < 4)) +    // If we're building on Linux with gcc, and it's either gcc 3.x or +    // 4.{0,1,2,3}, then we have to use a workaround. Note that we use gcc on +    // Mac too, and some people build with gcc on Windows (cygwin or mingw). +    // On Linux, different load modules may produce different type_info* +    // pointers for the same type. Have to compare name strings to get good +    // results. +    return strcmp(lhs->name(), rhs->name()) < 0; +#else  // not Linux, or gcc 4.4+ +    // Just use before(), as we normally would +    return lhs->before(*rhs); +#endif +} + +/** + * Specialize std::less<std::type_info*> to use std::type_info::before(). + * See MAINT-1175. It is NEVER a good idea to directly compare std::type_info* + * because, on Linux, you might get different std::type_info* pointers for the + * same type (from different load modules)! + */ +namespace std +{ +	template <> +	struct less<const std::type_info*>: +		public std::binary_function<const std::type_info*, const std::type_info*, bool> +	{ +		bool operator()(const std::type_info* lhs, const std::type_info* rhs) const +		{ +			return before(lhs, rhs); +		} +	}; + +	template <> +	struct less<std::type_info*>: +		public std::binary_function<std::type_info*, std::type_info*, bool> +	{ +		bool operator()(std::type_info* lhs, std::type_info* rhs) const +		{ +			return before(lhs, rhs); +		} +	}; +} // std +  #endif // LL_LLSTL_H diff --git a/indra/llcommon/lltypeinfolookup.h b/indra/llcommon/lltypeinfolookup.h index 7510cc12ed..0b6862444e 100644 --- a/indra/llcommon/lltypeinfolookup.h +++ b/indra/llcommon/lltypeinfolookup.h @@ -12,10 +12,50 @@  #if ! defined(LL_LLTYPEINFOLOOKUP_H)  #define LL_LLTYPEINFOLOOKUP_H -#include "llsortedvector.h" +#include <boost/unordered_map.hpp> +#include <boost/functional/hash.hpp> +#include <boost/optional.hpp> +#include <functional>               // std::binary_function  #include <typeinfo>  /** + * 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   * consider std::map<std::type_info*, VALUE>. We have several such data   * structures in the viewer. The trouble with them is that at least on Linux, @@ -23,88 +63,55 @@   * different load modules will produce different std::type_info*.   * LLTypeInfoLookup contains a workaround to address this issue.   * - * Specifically, when we don't find the passed std::type_info*, - * LLTypeInfoLookup performs a linear search over registered entries to - * compare name() strings. Presuming that this succeeds, we cache the new - * (previously unrecognized) std::type_info* to speed future lookups. - * - * This worst-case fallback search (linear search with string comparison) - * should only happen the first time we look up a given type from a particular - * load module other than the one from which we initially registered types. - * (However, a lookup which wouldn't succeed anyway will always have - * worst-case performance.) This class is probably best used with less than a - * few dozen different types. + * 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  { +    // Use this for our underlying implementation: lookup by +    // 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 LLSortedVector<const std::type_info*, VALUE> vector_type; -    typedef typename vector_type::key_type key_type; -    typedef typename vector_type::mapped_type mapped_type; -    typedef typename vector_type::value_type value_type; -    typedef typename vector_type::iterator iterator; -    typedef typename vector_type::const_iterator const_iterator; +    typedef VALUE value_type;      LLTypeInfoLookup() {} -    iterator begin() { return mVector.begin(); } -    iterator end()   { return mVector.end(); } -    const_iterator begin() const { return mVector.begin(); } -    const_iterator end()   const { return mVector.end(); } -    bool empty() const { return mVector.empty(); } -    std::size_t size() const { return mVector.size(); } - -    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) -    { -        return mVector.insert(pair); -    } +    bool empty() const { return mMap.empty(); } +    std::size_t size() const { return mMap.size(); } -    // const find() forwards to non-const find(): this can alter mVector! -    const_iterator find(const std::type_info* key) const +    template <typename KEY> +    bool insert(const value_type& value)      { -        return const_cast<self*>(this)->find(key); +        // 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;      } -    // non-const find() caches previously-unknown type_info* to speed future -    // lookups. -    iterator find(const std::type_info* key) +    template <typename KEY> +    boost::optional<value_type> find() const      { -        iterator found = mVector.find(key); -        if (found != mVector.end()) -        { -            // If LLSortedVector::find() found, great, we're done. -            return found; -        } -        // Here we didn't find the passed type_info*. On Linux, though, even -        // for the same type, typeid(sametype) produces a different type_info* -        // when used in different load modules. So the fact that we didn't -        // find the type_info* we seek doesn't mean this type isn't -        // registered. Scan for matching name() string. -        for (typename vector_type::iterator ti(mVector.begin()), tend(mVector.end()); -             ti != tend; ++ti) -        { -            if (std::string(ti->first->name()) == key->name()) -            { -                // This unrecognized 'key' is for the same type as ti->first. -                // To speed future lookups, insert a new entry that lets us -                // look up ti->second using this same 'key'. -                return insert(key, ti->second).first; -            } -        } -        // We simply have never seen a type with this type_info* from any load -        // module. -        return mVector.end(); +        // 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: -    vector_type mVector; +    impl_map_type mMap;  };  #endif /* ! defined(LL_LLTYPEINFOLOOKUP_H) */ diff --git a/indra/llui/lluictrlfactory.h b/indra/llui/lluictrlfactory.h index d612ad5005..4e54354731 100644 --- a/indra/llui/lluictrlfactory.h +++ b/indra/llui/lluictrlfactory.h @@ -31,18 +31,10 @@  #include "llinitparam.h"  #include "llregistry.h"  #include "llxuiparser.h" +#include "llstl.h"  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> @@ -71,14 +63,14 @@ protected:  // lookup widget name by type  class LLWidgetNameRegistry  -:	public LLRegistrySingleton<const std::type_info*, std::string, LLWidgetNameRegistry , LLCompareTypeID> +:	public LLRegistrySingleton<const std::type_info*, std::string, LLWidgetNameRegistry>  {};  // lookup function for generating empty param block by widget type  // this is used for schema generation  //typedef const LLInitParam::BaseBlock& (*empty_param_block_func_t)();  //class LLDefaultParamBlockRegistry -//:	public LLRegistrySingleton<const std::type_info*, empty_param_block_func_t, LLDefaultParamBlockRegistry, LLCompareTypeID> +//:	public LLRegistrySingleton<const std::type_info*, empty_param_block_func_t, LLDefaultParamBlockRegistry>  //{};  extern LLFastTimer::DeclareTimer FTM_WIDGET_SETUP; diff --git a/indra/newview/llnamelistctrl.cpp b/indra/newview/llnamelistctrl.cpp index 11b057eb0d..472c26e22d 100644 --- a/indra/newview/llnamelistctrl.cpp +++ b/indra/newview/llnamelistctrl.cpp @@ -336,7 +336,7 @@ LLScrollListItem* LLNameListCtrl::addNameItemRow(  				// ...schedule a callback  				LLAvatarNameCache::get(id,  					boost::bind(&LLNameListCtrl::onAvatarNameCache, -						this, _1, _2)); +						this, _1, _2, item->getHandle()));  			}  			break;  		} @@ -392,7 +392,8 @@ void LLNameListCtrl::removeNameItem(const LLUUID& agent_id)  }  void LLNameListCtrl::onAvatarNameCache(const LLUUID& agent_id, -									   const LLAvatarName& av_name) +									   const LLAvatarName& av_name, +									   LLHandle<LLNameListItem> item)  {  	std::string name;  	if (mShortNames) @@ -400,18 +401,14 @@ void LLNameListCtrl::onAvatarNameCache(const LLUUID& agent_id,  	else  		name = av_name.getCompleteName(); -	item_list::iterator iter; -	for (iter = getItemList().begin(); iter != getItemList().end(); ++iter) +	LLNameListItem* list_item = item.get(); +	if (list_item && list_item->getUUID() == agent_id)  	{ -		LLScrollListItem* item = *iter; -		if (item->getUUID() == agent_id) +		LLScrollListCell* cell = list_item->getColumn(mNameColumnIndex); +		if (cell)  		{ -			LLScrollListCell* cell = item->getColumn(mNameColumnIndex); -			if (cell) -			{ -				cell->setValue(name); -				setNeedsSort(); -			} +			cell->setValue(name); +			setNeedsSort();  		}  	} diff --git a/indra/newview/llnamelistctrl.h b/indra/newview/llnamelistctrl.h index 77c21f92e2..ba85e77c65 100644 --- a/indra/newview/llnamelistctrl.h +++ b/indra/newview/llnamelistctrl.h @@ -33,6 +33,26 @@  class LLAvatarName; +/** + * LLNameListCtrl item + * + * We don't use LLScrollListItem to be able to override getUUID(), which is needed + * because the name list item value is not simply an UUID but a map (uuid, is_group). + */ +class LLNameListItem : public LLScrollListItem, public LLHandleProvider<LLNameListItem> +{ +public: +	LLUUID	getUUID() const		{ return getValue()["uuid"].asUUID(); } +protected: +	friend class LLNameListCtrl; + +	LLNameListItem( const LLScrollListItem::Params& p ) +	:	LLScrollListItem(p) +	{ +	} +}; + +  class LLNameListCtrl  :	public LLScrollListCtrl, public LLInstanceTracker<LLNameListCtrl>  { @@ -117,7 +137,7 @@ public:  	/*virtual*/ void	mouseOverHighlightNthItem( S32 index );  private:  	void showInspector(const LLUUID& avatar_id, bool is_group); -	void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name); +	void onAvatarNameCache(const LLUUID& agent_id, const LLAvatarName& av_name, LLHandle<LLNameListItem> item);  private:  	S32    			mNameColumnIndex; @@ -126,24 +146,5 @@ private:  	bool			mShortNames;  // display name only, no SLID  }; -/** - * LLNameListCtrl item - * - * We don't use LLScrollListItem to be able to override getUUID(), which is needed - * because the name list item value is not simply an UUID but a map (uuid, is_group). - */ -class LLNameListItem : public LLScrollListItem -{ -public: -	LLUUID	getUUID() const		{ return getValue()["uuid"].asUUID(); } - -protected: -	friend class LLNameListCtrl; - -	LLNameListItem( const LLScrollListItem::Params& p ) -	:	LLScrollListItem(p) -	{ -	} -};  #endif | 
