diff options
| author | Oz Linden <oz@lindenlab.com> | 2013-01-17 13:54:39 -0500 | 
|---|---|---|
| committer | Oz Linden <oz@lindenlab.com> | 2013-01-17 13:54:39 -0500 | 
| commit | 841dc5da2ef9626fa4ab9255681d217df62a6b0b (patch) | |
| tree | 2c5bacebcb27b78d318b6e162334488f6e515974 /indra/llcommon | |
| parent | b7f8a2479249646c7fb38ead195d5197ab733c94 (diff) | |
| parent | d16757545c91d4f7dac3c52a311ad0f0239052e1 (diff) | |
merge up to 3.4.4
Diffstat (limited to 'indra/llcommon')
| -rw-r--r-- | indra/llcommon/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | indra/llcommon/fix_macros.h | 25 | ||||
| -rw-r--r-- | indra/llcommon/indra_constants.h | 1 | ||||
| -rw-r--r-- | indra/llcommon/llapr.h | 2 | ||||
| -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/llsdserialize.cpp | 5 | ||||
| -rw-r--r-- | indra/llcommon/llstl.h | 51 | ||||
| -rw-r--r-- | indra/llcommon/llstring.cpp | 3 | ||||
| -rw-r--r-- | indra/llcommon/llsys.cpp | 34 | ||||
| -rw-r--r-- | indra/llcommon/llthread.cpp | 7 | ||||
| -rw-r--r-- | indra/llcommon/llthread.h | 5 | ||||
| -rw-r--r-- | indra/llcommon/lltypeinfolookup.h | 141 | ||||
| -rw-r--r-- | indra/llcommon/lluri.cpp | 36 | ||||
| -rw-r--r-- | indra/llcommon/llversionviewer.h | 2 | ||||
| -rw-r--r-- | indra/llcommon/tests/bitpack_test.cpp | 1 | ||||
| -rw-r--r-- | indra/llcommon/tests/lluri_test.cpp | 94 | ||||
| -rw-r--r-- | indra/llcommon/tests/reflection_test.cpp | 2 | 
19 files changed, 513 insertions, 161 deletions
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index dd7b8c6eb8..66e2bc9095 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -116,6 +116,7 @@ set(llcommon_HEADER_FILES      bitpack.h      ctype_workaround.h      doublelinkedlist.h +    fix_macros.h      imageids.h      indra_constants.h      linden_common.h @@ -174,6 +175,7 @@ set(llcommon_HEADER_FILES      llfoldertype.h      llformat.h      llframetimer.h +    llhandle.h      llhash.h      llheartbeat.h      llhttpstatuscodes.h diff --git a/indra/llcommon/fix_macros.h b/indra/llcommon/fix_macros.h new file mode 100644 index 0000000000..ef959decff --- /dev/null +++ b/indra/llcommon/fix_macros.h @@ -0,0 +1,25 @@ +/** + * @file   fix_macros.h + * @author Nat Goodspeed + * @date   2012-11-16 + * @brief  The Mac system headers seem to #define macros with obnoxiously + *         generic names, preventing any library from using those names. We've + *         had to fix these in so many places that it's worth making a header + *         file to handle it. + *  + * $LicenseInfo:firstyear=2012&license=viewerlgpl$ + * Copyright (c) 2012, Linden Research, Inc. + * $/LicenseInfo$ + */ + +// DON'T use an #include guard: every time we encounter this header, #undef +// these macros all over again. + +// who injects MACROS with such generic names?! Grr. +#ifdef equivalent +#undef equivalent +#endif  + +#ifdef check +#undef check +#endif 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/llapr.h b/indra/llcommon/llapr.h index af33ce666f..034546c3f3 100644 --- a/indra/llcommon/llapr.h +++ b/indra/llcommon/llapr.h @@ -168,7 +168,7 @@ public:  	void operator -=(Type x) { apr_atomic_sub32(&mData, apr_uint32_t(x)); }  	void operator +=(Type x) { apr_atomic_add32(&mData, apr_uint32_t(x)); }  	Type operator ++(int) { return apr_atomic_inc32(&mData); } // Type++ -	Type operator --(int) { return apr_atomic_dec32(&mData); } // Type-- +	Type operator --(int) { return apr_atomic_dec32(&mData); } // approximately --Type (0 if final is 0, non-zero otherwise)  private:  	apr_uint32_t mData; 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/llsdserialize.cpp b/indra/llcommon/llsdserialize.cpp index 7f4f670ed0..6b549e4b6f 100644 --- a/indra/llcommon/llsdserialize.cpp +++ b/indra/llcommon/llsdserialize.cpp @@ -1451,9 +1451,12 @@ S32 LLSDBinaryFormatter::format(const LLSD& data, std::ostream& ostr, U32 option  	}  	case LLSD::TypeUUID: +	{  		ostr.put('u'); -		ostr.write((const char*)(&(data.asUUID().mData)), UUID_BYTES); +		LLSD::UUID value = data.asUUID(); +		ostr.write((const char*)(&value.mData), UUID_BYTES);  		break; +	}  	case LLSD::TypeString:  		ostr.put('s'); 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/llstring.cpp b/indra/llcommon/llstring.cpp index fa0eb9f72c..0c32679744 100644 --- a/indra/llcommon/llstring.cpp +++ b/indra/llcommon/llstring.cpp @@ -47,7 +47,8 @@ std::string ll_safe_string(const char* in)  std::string ll_safe_string(const char* in, S32 maxlen)  { -	if(in) return std::string(in, maxlen); +	if(in && maxlen > 0 ) return std::string(in, maxlen); +  	return std::string();  } diff --git a/indra/llcommon/llsys.cpp b/indra/llcommon/llsys.cpp index 6073bcd0a6..c96f2191f3 100644 --- a/indra/llcommon/llsys.cpp +++ b/indra/llcommon/llsys.cpp @@ -944,13 +944,15 @@ LLSD LLMemoryInfo::loadStatsMap()  	state.dwLength = sizeof(state);  	GlobalMemoryStatusEx(&state); -	stats.add("Percent Memory use", state.dwMemoryLoad); -	stats.add("Total Physical KB",  state.ullTotalPhys/1024); -	stats.add("Avail Physical KB",  state.ullAvailPhys/1024); -	stats.add("Total page KB",      state.ullTotalPageFile/1024); -	stats.add("Avail page KB",      state.ullAvailPageFile/1024); -	stats.add("Total Virtual KB",   state.ullTotalVirtual/1024); -	stats.add("Avail Virtual KB",   state.ullAvailVirtual/1024); +	DWORDLONG div = 1024; + +	stats.add("Percent Memory use", state.dwMemoryLoad/div); +	stats.add("Total Physical KB",  state.ullTotalPhys/div); +	stats.add("Avail Physical KB",  state.ullAvailPhys/div); +	stats.add("Total page KB",      state.ullTotalPageFile/div); +	stats.add("Avail page KB",      state.ullAvailPageFile/div); +	stats.add("Total Virtual KB",   state.ullTotalVirtual/div); +	stats.add("Avail Virtual KB",   state.ullAvailVirtual/div);  	PERFORMANCE_INFORMATION perf;  	perf.cb = sizeof(perf); @@ -982,15 +984,15 @@ LLSD LLMemoryInfo::loadStatsMap()  	GetProcessMemoryInfo(GetCurrentProcess(), PPROCESS_MEMORY_COUNTERS(&pmem), sizeof(pmem));  	stats.add("Page Fault Count",              pmem.PageFaultCount); -	stats.add("PeakWorkingSetSize KB",         pmem.PeakWorkingSetSize/1024); -	stats.add("WorkingSetSize KB",             pmem.WorkingSetSize/1024); -	stats.add("QutaPeakPagedPoolUsage KB",     pmem.QuotaPeakPagedPoolUsage/1024); -	stats.add("QuotaPagedPoolUsage KB",        pmem.QuotaPagedPoolUsage/1024); -	stats.add("QuotaPeakNonPagedPoolUsage KB", pmem.QuotaPeakNonPagedPoolUsage/1024); -	stats.add("QuotaNonPagedPoolUsage KB",     pmem.QuotaNonPagedPoolUsage/1024); -	stats.add("PagefileUsage KB",              pmem.PagefileUsage/1024); -	stats.add("PeakPagefileUsage KB",          pmem.PeakPagefileUsage/1024); -	stats.add("PrivateUsage KB",               pmem.PrivateUsage/1024); +	stats.add("PeakWorkingSetSize KB",         pmem.PeakWorkingSetSize/div); +	stats.add("WorkingSetSize KB",             pmem.WorkingSetSize/div); +	stats.add("QutaPeakPagedPoolUsage KB",     pmem.QuotaPeakPagedPoolUsage/div); +	stats.add("QuotaPagedPoolUsage KB",        pmem.QuotaPagedPoolUsage/div); +	stats.add("QuotaPeakNonPagedPoolUsage KB", pmem.QuotaPeakNonPagedPoolUsage/div); +	stats.add("QuotaNonPagedPoolUsage KB",     pmem.QuotaNonPagedPoolUsage/div); +	stats.add("PagefileUsage KB",              pmem.PagefileUsage/div); +	stats.add("PeakPagefileUsage KB",          pmem.PeakPagefileUsage/div); +	stats.add("PrivateUsage KB",               pmem.PrivateUsage/div);  #elif LL_DARWIN diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp index c2fbb544a8..1d56a52c32 100644 --- a/indra/llcommon/llthread.cpp +++ b/indra/llcommon/llthread.cpp @@ -71,6 +71,13 @@ LL_COMMON_API void assert_main_thread()  	}  } +void LLThread::registerThreadID() +{ +#if !LL_DARWIN +	sThreadID = ++sIDIter; +#endif +} +  //  // Handed to the APR thread creation function  // diff --git a/indra/llcommon/llthread.h b/indra/llcommon/llthread.h index 115bf47553..5c8bbca2ca 100644 --- a/indra/llcommon/llthread.h +++ b/indra/llcommon/llthread.h @@ -88,6 +88,11 @@ public:  	U32 getID() const { return mID; } +	// Called by threads *not* created via LLThread to register some +	// internal state used by LLMutex.  You must call this once early +	// in the running thread to prevent collisions with the main thread. +	static void registerThreadID(); +	  private:  	BOOL				mPaused; 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/lluri.cpp b/indra/llcommon/lluri.cpp index b39ea0c6f2..21456a599b 100644 --- a/indra/llcommon/lluri.cpp +++ b/indra/llcommon/lluri.cpp @@ -37,6 +37,8 @@  // system includes  #include <boost/tokenizer.hpp> +#include <boost/algorithm/string/find_iterator.hpp> +#include <boost/algorithm/string/finder.hpp>  void encode_character(std::ostream& ostr, std::string::value_type val)  { @@ -317,7 +319,7 @@ LLURI LLURI::buildHTTP(const std::string& prefix,  					   const LLSD& path)  {  	LLURI result; -	 +  	// TODO: deal with '/' '?' '#' in host_port  	if (prefix.find("://") != prefix.npos)  	{ @@ -342,15 +344,41 @@ LLURI LLURI::buildHTTP(const std::string& prefix,  			result.mEscapedPath += "/" + escapePathComponent(it->asString());  		}  	} -	else if(path.isString()) +	else if (path.isString())  	{ -		result.mEscapedPath += "/" + escapePathComponent(path.asString()); +		std::string pathstr(path); +		// Trailing slash is significant in HTTP land. If caller specified, +		// make a point of preserving. +		std::string last_slash; +		std::string::size_type len(pathstr.length()); +		if (len && pathstr[len-1] == '/') +		{ +			last_slash = "/"; +		} + +		// Escape every individual path component, recombining with slashes. +		for (boost::split_iterator<std::string::const_iterator> +				 ti(pathstr, boost::first_finder("/")), tend; +			 ti != tend; ++ti) +		{ +			// Eliminate a leading slash or duplicate slashes anywhere. (Extra +			// slashes show up here as empty components.) This test also +			// eliminates a trailing slash, hence last_slash above. +			if (! ti->empty()) +			{ +				result.mEscapedPath +					+= "/" + escapePathComponent(std::string(ti->begin(), ti->end())); +			} +		} + +		// Reinstate trailing slash, if any. +		result.mEscapedPath += last_slash;  	}   	else if(path.isUndefined())  	{  	  // do nothing  	} -    else +	else  	{  	  llwarns << "Valid path arguments to buildHTTP are array, string, or undef, you passed type"   			  << path.type() << llendl; diff --git a/indra/llcommon/llversionviewer.h b/indra/llcommon/llversionviewer.h index bcc661a920..8585af0a29 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 = 4;  const S32 LL_VERSION_BUILD = 0;  const char * const LL_CHANNEL = "Second Life Developer"; diff --git a/indra/llcommon/tests/bitpack_test.cpp b/indra/llcommon/tests/bitpack_test.cpp index 05289881d0..4c3bc674af 100644 --- a/indra/llcommon/tests/bitpack_test.cpp +++ b/indra/llcommon/tests/bitpack_test.cpp @@ -95,6 +95,7 @@ namespace tut  		ensure("bitPack: individual unpack: 5", unpackbuffer[0] == (U8) str[5]);  		unpack_bufsize = bitunpack.bitUnpack(unpackbuffer, 8*4); // Life  		ensure_memory_matches("bitPack: 4 bytes unpack:", unpackbuffer, 4, str+6, 4); +		ensure("keep compiler quiet", unpack_bufsize == unpack_bufsize);  	}  	// U32 packing diff --git a/indra/llcommon/tests/lluri_test.cpp b/indra/llcommon/tests/lluri_test.cpp index f6d4221256..4c64f15ca7 100644 --- a/indra/llcommon/tests/lluri_test.cpp +++ b/indra/llcommon/tests/lluri_test.cpp @@ -58,12 +58,12 @@ namespace tut  			ensure_equals("escape/unescape escaped", uri_esc_2, uri_esc_1);  		}  	}; -	 +  	typedef test_group<URITestData>	URITestGroup;  	typedef URITestGroup::object	URITestObject;  	URITestGroup uriTestGroup("LLURI"); -	 +  	template<> template<>  	void URITestObject::test<1>()  	{ @@ -89,14 +89,14 @@ namespace tut  	template<> template<>  	void URITestObject::test<2>()  	{ -		// empty string +		set_test_name("empty string");  		checkParts(LLURI(""), "", "", "", "");  	} -	 +  	template<> template<>  	void URITestObject::test<3>()  	{ -		// no scheme +		set_test_name("no scheme");  		checkParts(LLURI("foo"), "", "foo", "", "");  		checkParts(LLURI("foo%3A"), "", "foo:", "", "");  	} @@ -104,7 +104,7 @@ namespace tut  	template<> template<>  	void URITestObject::test<4>()  	{ -		// scheme w/o paths +		set_test_name("scheme w/o paths");  		checkParts(LLURI("mailto:zero@ll.com"),  			"mailto", "zero@ll.com", "", "");  		checkParts(LLURI("silly://abc/def?foo"), @@ -114,16 +114,16 @@ namespace tut  	template<> template<>  	void URITestObject::test<5>()  	{ -		// authority section +		set_test_name("authority section");  		checkParts(LLURI("http:///"),  			"http", "///", "", "/"); -			 +  		checkParts(LLURI("http://abc"),  			"http", "//abc", "abc", ""); -			 +  		checkParts(LLURI("http://a%2Fb/cd"),  			"http", "//a/b/cd", "a/b", "/cd"); -			 +  		checkParts(LLURI("http://host?"),  			"http", "//host?", "host", "");  	} @@ -131,13 +131,13 @@ namespace tut  	template<> template<>  	void URITestObject::test<6>()  	{		 -		// path section +		set_test_name("path section");  		checkParts(LLURI("http://host/a/b/"),  				"http", "//host/a/b/", "host", "/a/b/"); -				 +  		checkParts(LLURI("http://host/a%3Fb/"),  				"http", "//host/a?b/", "host", "/a?b/"); -				 +  		checkParts(LLURI("http://host/a:b/"),  				"http", "//host/a:b/", "host", "/a:b/");  	} @@ -145,16 +145,16 @@ namespace tut  	template<> template<>  	void URITestObject::test<7>()  	{		 -		// query string +		set_test_name("query string");  		checkParts(LLURI("http://host/?"),  				"http", "//host/?", "host", "/", ""); -				 +  		checkParts(LLURI("http://host/?x"),  				"http", "//host/?x", "host", "/", "x"); -				 +  		checkParts(LLURI("http://host/??"),  				"http", "//host/??", "host", "/", "?"); -				 +  		checkParts(LLURI("http://host/?%3F"),  				"http", "//host/??", "host", "/", "?");  	} @@ -167,19 +167,44 @@ namespace tut  		path.append("123");  		checkParts(LLURI::buildHTTP("host", path),  			"http", "//host/x/123", "host", "/x/123"); -		 +  		LLSD query;  		query["123"] = "12";  		query["abcd"] = "abc";  		checkParts(LLURI::buildHTTP("host", path, query),  			"http", "//host/x/123?123=12&abcd=abc",  			"host", "/x/123", "123=12&abcd=abc"); + +		ensure_equals(LLURI::buildHTTP("host", "").asString(), +					  "http://host"); +		ensure_equals(LLURI::buildHTTP("host", "/").asString(), +					  "http://host/"); +		ensure_equals(LLURI::buildHTTP("host", "//").asString(), +					  "http://host/"); +		ensure_equals(LLURI::buildHTTP("host", "dir name").asString(), +					  "http://host/dir%20name"); +		ensure_equals(LLURI::buildHTTP("host", "dir name/").asString(), +					  "http://host/dir%20name/"); +		ensure_equals(LLURI::buildHTTP("host", "/dir name").asString(), +					  "http://host/dir%20name"); +		ensure_equals(LLURI::buildHTTP("host", "/dir name/").asString(), +					  "http://host/dir%20name/"); +		ensure_equals(LLURI::buildHTTP("host", "dir name/subdir name").asString(), +					  "http://host/dir%20name/subdir%20name"); +		ensure_equals(LLURI::buildHTTP("host", "dir name/subdir name/").asString(), +					  "http://host/dir%20name/subdir%20name/"); +		ensure_equals(LLURI::buildHTTP("host", "/dir name/subdir name").asString(), +					  "http://host/dir%20name/subdir%20name"); +		ensure_equals(LLURI::buildHTTP("host", "/dir name/subdir name/").asString(), +					  "http://host/dir%20name/subdir%20name/"); +		ensure_equals(LLURI::buildHTTP("host", "//dir name//subdir name//").asString(), +					  "http://host/dir%20name/subdir%20name/");  	}  	template<> template<>  	void URITestObject::test<9>()  	{ -		// test unescaped path components +		set_test_name("test unescaped path components");  		LLSD path;  		path.append("x@*//*$&^");  		path.append("123"); @@ -190,7 +215,7 @@ namespace tut  	template<> template<>  	void URITestObject::test<10>()  	{ -		// test unescaped query components +		set_test_name("test unescaped query components");  		LLSD path;  		path.append("x");  		path.append("123"); @@ -205,7 +230,7 @@ namespace tut  	template<> template<>  	void URITestObject::test<11>()  	{ -		// test unescaped host components +		set_test_name("test unescaped host components");  		LLSD path;  		path.append("x");  		path.append("123"); @@ -216,16 +241,16 @@ namespace tut  			"http", "//hi123*33--}{:portstuffs/x/123?123=12&abcd=abc",  			"hi123*33--}{:portstuffs", "/x/123", "123=12&abcd=abc");  	} -	 +  	template<> template<>  	void URITestObject::test<12>()  	{ -		// test funky host_port values that are actually prefixes -		 +		set_test_name("test funky host_port values that are actually prefixes"); +  		checkParts(LLURI::buildHTTP("http://example.com:8080", LLSD()),  			"http", "//example.com:8080",  			"example.com:8080", ""); -			 +  		checkParts(LLURI::buildHTTP("http://example.com:8080/", LLSD()),  			"http", "//example.com:8080/",  			"example.com:8080", "/"); @@ -242,7 +267,7 @@ namespace tut  			"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"  			"0123456789"  			"-._~"; -		// test escape +		set_test_name("test escape");  		ensure_equals("escaping", LLURI::escape("abcdefg", "abcdef"), "abcdef%67");  		ensure_equals("escaping", LLURI::escape("|/&\\+-_!@", ""), "%7C%2F%26%5C%2B%2D%5F%21%40");  		ensure_equals("escaping as query variable",  @@ -259,13 +284,12 @@ namespace tut  		cedilla.push_back( (char)0xA7 );  		ensure_equals("escape UTF8", LLURI::escape( cedilla, unreserved), "%C3%A7");  	} -	 +  	template<> template<>  	void URITestObject::test<14>()  	{ -		// make sure escape and unescape of empty strings return empty -		// strings. +		set_test_name("make sure escape and unescape of empty strings return empty strings.");  		std::string uri_esc(LLURI::escape(""));  		ensure("escape string empty", uri_esc.empty());  		std::string uri_raw(LLURI::unescape("")); @@ -275,7 +299,7 @@ namespace tut  	template<> template<>  	void URITestObject::test<15>()  	{ -		// do some round-trip tests +		set_test_name("do some round-trip tests");  		escapeRoundTrip("http://secondlife.com");  		escapeRoundTrip("http://secondlife.com/url with spaces");  		escapeRoundTrip("http://bad[domain]name.com/"); @@ -286,7 +310,7 @@ namespace tut  	template<> template<>  	void URITestObject::test<16>()  	{ -		// Test the default escaping +		set_test_name("Test the default escaping");  		// yes -- this mangles the url. This is expected behavior  		std::string simple("http://secondlife.com");  		ensure_equals( @@ -302,7 +326,7 @@ namespace tut  	template<> template<>  	void URITestObject::test<17>()  	{ -		// do some round-trip tests with very long strings. +		set_test_name("do some round-trip tests with very long strings.");  		escapeRoundTrip("Welcome to Second Life.We hope you'll have a richly rewarding experience, filled with creativity, self expression and fun.The goals of the Community Standards are simple: treat each other with respect and without harassment, adhere to local standards as indicated by simulator ratings, and refrain from any hate activity which slurs a real-world individual or real-world community. Behavioral Guidelines - The Big Six");  		escapeRoundTrip(  			"'asset_data':b(12100){'task_id':ucc706f2d-0b68-68f8-11a4-f1043ff35ca0}\n{\n\tname\tObject|\n\tpermissions 0\n\t{\n\t\tbase_mask\t7fffffff\n\t\towner_mask\t7fffffff\n\t\tgroup_mask\t00000000\n\t\teveryone_mask\t00000000\n\t\tnext_owner_mask\t7fffffff\n\t\tcreator_id\t13fd9595-a47b-4d64-a5fb-6da645f038e0\n\t\towner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tlast_owner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tgroup_id\t00000000-0000-0000-0000-000000000000\n\t}\n\tlocal_id\t217444921\n\ttotal_crc\t323\n\ttype\t2\n\ttask_valid\t2\n\ttravel_access\t13\n\tdisplayopts\t2\n\tdisplaytype\tv\n\tpos\t-0.368634403\t0.00781063363\t-0.569040775\n\toldpos\t150.117996\t25.8658009\t8.19664001\n\trotation\t-0.06293071806430816650390625\t-0.6995697021484375\t-0.7002241611480712890625\t0.1277817934751510620117188\n\tchildpos\t-0.00499999989\t-0.0359999985\t0.307999998\n\tchildrot\t-0.515492737293243408203125\t-0.46601200103759765625\t0.529055416584014892578125\t0.4870323240756988525390625\n\tscale" @@ -322,7 +346,7 @@ namespace tut  			"D STRING RW SV 20f36c3a-b44b-9bc7-87f3-018bfdfc8cda\n\tscratchpad\t0\n\t{\n\t\n\t}\n\tsale_info\t0\n\t{\n\t\tsale_type\tnot\n\t\tsale_price\t10\n\t}\n\torig_asset_id\t8747acbc-d391-1e59-69f1-41d06830e6c0\n\torig_item_id\t20f36c3a-b44b-9bc7-87f3-018bfdfc8cda\n\tfrom_task_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\tcorrect_family_id\t00000000-0000-0000-0000-000000000000\n\thas_rezzed\t0\n\tpre_link_base_mask\t7fffffff\n\tlinked \tlinked\n\tdefault_pay_price\t-2\t1\t5\t10\t20\n}\n");  	} -	  +  	template<> template<>  	void URITestObject::test<18>()  	{ @@ -335,7 +359,7 @@ namespace tut  		ensure_equals("pathmap",	u.pathArray()[1].asString(),	"login");  		ensure_equals("query",		u.query(),		"first_name=Testert4&last_name=Tester&web_login_key=test");  		ensure_equals("query map element", u.queryMap()["last_name"].asString(), "Tester"); -		 +  		u = LLURI("secondlife://Da Boom/128/128/128");  		// if secondlife is the scheme, LLURI should parse /128/128/128 as path, with Da Boom as authority  		ensure_equals("scheme",		u.scheme(),		"secondlife"); @@ -350,7 +374,7 @@ namespace tut  	template<> template<>  	void URITestObject::test<19>()  	{ -		// Parse about: schemes +		set_test_name("Parse about: schemes");  		LLURI u("about:blank?redirect-http-hack=secondlife%3A%2F%2F%2Fapp%2Flogin%3Ffirst_name%3DCallum%26last_name%3DLinden%26location%3Dspecify%26grid%3Dvaak%26region%3D%2FMorris%2F128%2F128%26web_login_key%3Defaa4795-c2aa-4c58-8966-763c27931e78");  		ensure_equals("scheme",		u.scheme(),		"about");  		ensure_equals("authority",	u.authority(),	""); diff --git a/indra/llcommon/tests/reflection_test.cpp b/indra/llcommon/tests/reflection_test.cpp index 59491cd1fe..8980ebb1f1 100644 --- a/indra/llcommon/tests/reflection_test.cpp +++ b/indra/llcommon/tests/reflection_test.cpp @@ -207,7 +207,7 @@ namespace tut  			const LLReflective* reflective = property->get(aggregated_data); // Wrong reflective type, should throw exception.  			// useless op to get rid of compiler warning. -			reflective = NULL; +			reflective = reflective;  		}  		catch(...)  		{  | 
