diff options
Diffstat (limited to 'indra/llcommon')
| -rw-r--r-- | indra/llcommon/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | indra/llcommon/indra_constants.h | 1 | ||||
| -rw-r--r-- | indra/llcommon/llhandle.h | 217 | ||||
| -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/llcommon/llversionviewer.h | 2 | 
8 files changed, 357 insertions, 102 deletions
| diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index dd7b8c6eb8..36a8319189 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -174,6 +174,7 @@ set(llcommon_HEADER_FILES      llfoldertype.h      llformat.h      llframetimer.h +    llhandle.h      llhash.h      llheartbeat.h      llhttpstatuscodes.h diff --git a/indra/llcommon/indra_constants.h b/indra/llcommon/indra_constants.h index 0745696ef3..0da83720bd 100644 --- a/indra/llcommon/indra_constants.h +++ b/indra/llcommon/indra_constants.h @@ -62,6 +62,7 @@ enum LAND_STAT_FLAGS  	STAT_FILTER_BY_PARCEL	= 0x00000001,  	STAT_FILTER_BY_OWNER	= 0x00000002,  	STAT_FILTER_BY_OBJECT	= 0x00000004, +	STAT_FILTER_BY_PARCEL_NAME	= 0x00000008,  	STAT_REQUEST_LAST_ENTRY	= 0x80000000,  }; diff --git a/indra/llcommon/llhandle.h b/indra/llcommon/llhandle.h new file mode 100644 index 0000000000..6af5e198d6 --- /dev/null +++ b/indra/llcommon/llhandle.h @@ -0,0 +1,217 @@ +/**  +* @file llhandle.h +* @brief "Handle" to an object (usually a floater) whose lifetime you don't +* control. +* +* $LicenseInfo:firstyear=2001&license=viewerlgpl$ +* Second Life Viewer Source Code +* Copyright (C) 2010, Linden Research, Inc. +*  +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Lesser General Public +* License as published by the Free Software Foundation; +* version 2.1 of the License only. +*  +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +* Lesser General Public License for more details. +*  +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA +*  +* Linden Research, Inc., 945 Battery Street, San Francisco, CA  94111  USA +* $/LicenseInfo$ +*/ +#ifndef LLHANDLE_H +#define LLHANDLE_H + +#include "llpointer.h" +#include <boost/type_traits/is_convertible.hpp> +#include <boost/utility/enable_if.hpp> + +/** + * Helper object for LLHandle. Don't instantiate these directly, used + * exclusively by LLHandle. + */ +class LLTombStone : public LLRefCount +{ +public: +	LLTombStone(void* target = NULL) : mTarget(target) {} + +	void setTarget(void* target) { mTarget = target; } +	void* getTarget() const { return mTarget; } +private: +	mutable void* mTarget; +}; + +/** + *	LLHandles are used to refer to objects whose lifetime you do not control or influence.   + *	Calling get() on a handle will return a pointer to the referenced object or NULL,  + *	if the object no longer exists.  Note that during the lifetime of the returned pointer,  + *	you are assuming that the object will not be deleted by any action you perform,  + *	or any other thread, as normal when using pointers, so avoid using that pointer outside of + *	the local code block. + *  + *  https://wiki.lindenlab.com/mediawiki/index.php?title=LLHandle&oldid=79669 + * + * The implementation is like some "weak pointer" implementations. When we + * can't control the lifespan of the referenced object of interest, we can + * still instantiate a proxy object whose lifespan we DO control, and store in + * the proxy object a dumb pointer to the actual target. Then we just have to + * ensure that on destruction of the target object, the proxy's dumb pointer + * is set NULL. + * + * LLTombStone is our proxy object. LLHandle contains an LLPointer to the + * LLTombStone, so every copy of an LLHandle increments the LLTombStone's ref + * count as usual. + * + * One copy of the LLHandle, specifically the LLRootHandle, must be stored in + * the referenced object. Destroying the LLRootHandle is what NULLs the + * proxy's target pointer. + * + * Minor optimization: we want LLHandle's mTombStone to always be a valid + * LLPointer, saving some conditionals in dereferencing. That's the + * getDefaultTombStone() mechanism. The default LLTombStone object's target + * pointer is always NULL, so it's semantically identical to allowing + * mTombStone to be invalid. + */ +template <typename T> +class LLHandle +{ +	template <typename U> friend class LLHandle; +	template <typename U> friend class LLHandleProvider; +public: +	LLHandle() : mTombStone(getDefaultTombStone()) {} + +	template<typename U> +	LLHandle(const LLHandle<U>& other, typename boost::enable_if< typename boost::is_convertible<U*, T*> >::type* dummy = 0) +	: mTombStone(other.mTombStone) +	{} + +	bool isDead() const  +	{  +		return mTombStone->getTarget() == NULL;  +	} + +	void markDead()  +	{  +		mTombStone = getDefaultTombStone(); +	} + +	T* get() const +	{ +		return reinterpret_cast<T*>(mTombStone->getTarget()); +	} + +	friend bool operator== (const LLHandle<T>& lhs, const LLHandle<T>& rhs) +	{ +		return lhs.mTombStone == rhs.mTombStone; +	} +	friend bool operator!= (const LLHandle<T>& lhs, const LLHandle<T>& rhs) +	{ +		return !(lhs == rhs); +	} +	friend bool	operator< (const LLHandle<T>& lhs, const LLHandle<T>& rhs) +	{ +		return lhs.mTombStone < rhs.mTombStone; +	} +	friend bool	operator> (const LLHandle<T>& lhs, const LLHandle<T>& rhs) +	{ +		return lhs.mTombStone > rhs.mTombStone; +	} + +protected: +	LLPointer<LLTombStone> mTombStone; + +private: +	typedef T* pointer_t; +	static LLPointer<LLTombStone>& getDefaultTombStone() +	{ +		static LLPointer<LLTombStone> sDefaultTombStone = new LLTombStone; +		return sDefaultTombStone; +	} +}; + +/** + * LLRootHandle isa LLHandle which must be stored in the referenced object. + * You can either store it directly and explicitly bind(this), or derive from + * LLHandleProvider (q.v.) which automates that for you. The essential point + * is that destroying the LLRootHandle (as a consequence of destroying the + * referenced object) calls unbind(), setting the LLTombStone's target pointer + * NULL. + */ +template <typename T> +class LLRootHandle : public LLHandle<T> +{ +public: +	typedef LLRootHandle<T> self_t; +	typedef LLHandle<T> base_t; + +	LLRootHandle(T* object) { bind(object); } +	LLRootHandle() {}; +	~LLRootHandle() { unbind(); } + +	// this is redundant, since an LLRootHandle *is* an LLHandle +	//LLHandle<T> getHandle() { return LLHandle<T>(*this); } + +	void bind(T* object)  +	{  +		// unbind existing tombstone +		if (LLHandle<T>::mTombStone.notNull()) +		{ +			if (LLHandle<T>::mTombStone->getTarget() == (void*)object) return; +			LLHandle<T>::mTombStone->setTarget(NULL); +		} +		// tombstone reference counted, so no paired delete +		LLHandle<T>::mTombStone = new LLTombStone((void*)object); +	} + +	void unbind()  +	{ +		LLHandle<T>::mTombStone->setTarget(NULL); +	} + +	//don't allow copying of root handles, since there should only be one +private: +	LLRootHandle(const LLRootHandle& other) {}; +}; + +/** + * Use this as a mixin for simple classes that need handles and when you don't + * want handles at multiple points of the inheritance hierarchy + */ +template <typename T> +class LLHandleProvider +{ +public: +	LLHandle<T> getHandle() const +	{  +		// perform lazy binding to avoid small tombstone allocations for handle +		// providers whose handles are never referenced +		mHandle.bind(static_cast<T*>(const_cast<LLHandleProvider<T>* >(this)));  +		return mHandle;  +	} + +protected: +	typedef LLHandle<T> handle_type_t; +	LLHandleProvider()  +	{ +		// provided here to enforce T deriving from LLHandleProvider<T> +	}  + +	template <typename U> +	LLHandle<U> getDerivedHandle(typename boost::enable_if< typename boost::is_convertible<U*, T*> >::type* dummy = 0) const +	{ +		LLHandle<U> downcast_handle; +		downcast_handle.mTombStone = getHandle().mTombStone; +		return downcast_handle; +	} + + +private: +	mutable LLRootHandle<T> mHandle; +}; + +#endif 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/llcommon/llversionviewer.h b/indra/llcommon/llversionviewer.h index bcc661a920..b12aa8826a 100644 --- a/indra/llcommon/llversionviewer.h +++ b/indra/llcommon/llversionviewer.h @@ -29,7 +29,7 @@  const S32 LL_VERSION_MAJOR = 3;  const S32 LL_VERSION_MINOR = 4; -const S32 LL_VERSION_PATCH = 1; +const S32 LL_VERSION_PATCH = 2;  const S32 LL_VERSION_BUILD = 0;  const char * const LL_CHANNEL = "Second Life Developer"; | 
