diff options
Diffstat (limited to 'indra/llcommon')
25 files changed, 4492 insertions, 4231 deletions
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index e7aaf3c984..f785698612 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -50,6 +50,7 @@ set(llcommon_SOURCE_FILES      llfile.cpp      llfindlocale.cpp      llfixedbuffer.cpp +    llfoldertype.cpp      llformat.cpp      llframetimer.cpp      llheartbeat.cpp @@ -150,6 +151,7 @@ set(llcommon_HEADER_FILES      llfile.h      llfindlocale.h      llfixedbuffer.h +    llfoldertype.h      llformat.h      llframetimer.h      llhash.h diff --git a/indra/llcommon/llallocator.h b/indra/llcommon/llallocator.h index 0d6f18c5d4..50129b4526 100644 --- a/indra/llcommon/llallocator.h +++ b/indra/llcommon/llallocator.h @@ -1,63 +1,63 @@ -/** 
 - * @file llallocator.h
 - * @brief Declaration of the LLAllocator class.
 - *
 - * $LicenseInfo:firstyear=2009&license=viewergpl$
 - * 
 - * Copyright (c) 2009-2009, Linden Research, Inc.
 - * 
 - * Second Life Viewer Source Code
 - * The source code in this file ("Source Code") is provided by Linden Lab
 - * to you under the terms of the GNU General Public License, version 2.0
 - * ("GPL"), unless you have obtained a separate licensing agreement
 - * ("Other License"), formally executed by you and Linden Lab.  Terms of
 - * the GPL can be found in doc/GPL-license.txt in this distribution, or
 - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
 - * 
 - * There are special exceptions to the terms and conditions of the GPL as
 - * it is applied to this Source Code. View the full text of the exception
 - * in the file doc/FLOSS-exception.txt in this software distribution, or
 - * online at
 - * http://secondlifegrid.net/programs/open_source/licensing/flossexception
 - * 
 - * By copying, modifying or distributing this software, you acknowledge
 - * that you have read and understood your obligations described above,
 - * and agree to abide by those obligations.
 - * 
 - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
 - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
 - * COMPLETENESS OR PERFORMANCE.
 - * $/LicenseInfo$
 - */
 -
 -#ifndef LL_LLALLOCATOR_H
 -#define LL_LLALLOCATOR_H
 -
 -#include <string>
 -
 -#include "llmemtype.h"
 -#include "llallocator_heap_profile.h"
 -
 -class LL_COMMON_API LLAllocator {
 -    friend class LLMemoryView;
 -    friend class LLMemType;
 -
 -private:
 -	static void pushMemType(S32 type);
 -	static S32 popMemType();
 -
 -public:
 -    void setProfilingEnabled(bool should_enable);
 -
 -    static bool isProfiling();
 -
 -    LLAllocatorHeapProfile const & getProfile();
 -
 -private:
 -    std::string getRawProfile();
 -
 -private:
 -    LLAllocatorHeapProfile mProf;
 -};
 -
 -#endif // LL_LLALLOCATOR_H
 +/**  + * @file llallocator.h + * @brief Declaration of the LLAllocator class. + * + * $LicenseInfo:firstyear=2009&license=viewergpl$ + *  + * Copyright (c) 2009-2009, Linden Research, Inc. + *  + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab.  Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + *  + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + *  + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + *  + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLALLOCATOR_H +#define LL_LLALLOCATOR_H + +#include <string> + +#include "llmemtype.h" +#include "llallocator_heap_profile.h" + +class LL_COMMON_API LLAllocator { +    friend class LLMemoryView; +    friend class LLMemType; + +private: +	static void pushMemType(S32 type); +	static S32 popMemType(); + +public: +    void setProfilingEnabled(bool should_enable); + +    static bool isProfiling(); + +    LLAllocatorHeapProfile const & getProfile(); + +private: +    std::string getRawProfile(); + +private: +    LLAllocatorHeapProfile mProf; +}; + +#endif // LL_LLALLOCATOR_H diff --git a/indra/llcommon/llapr.cpp b/indra/llcommon/llapr.cpp index 669afc5330..ed70b1d9f2 100644 --- a/indra/llcommon/llapr.cpp +++ b/indra/llcommon/llapr.cpp @@ -57,7 +57,7 @@ void ll_init_apr()  	if(!LLAPRFile::sAPRFilePoolp)  	{ -		LLAPRFile::sAPRFilePoolp = new LLVolatileAPRPool() ; +		LLAPRFile::sAPRFilePoolp = new LLVolatileAPRPool(FALSE) ;  	}  } @@ -99,13 +99,12 @@ void ll_cleanup_apr()  //  //LLAPRPool  // -LLAPRPool::LLAPRPool(apr_pool_t *parent, apr_size_t size, BOOL releasePoolFlag)  -{ -	mParent = parent ; -	mReleasePoolFlag = releasePoolFlag ; -	mMaxSize = size ; -	mPool = NULL ; - +LLAPRPool::LLAPRPool(apr_pool_t *parent, apr_size_t size, BOOL releasePoolFlag) 	 +	: mParent(parent), +	mReleasePoolFlag(releasePoolFlag), +	mMaxSize(size), +	mPool(NULL) +{	  	createAPRPool() ;  } @@ -148,31 +147,65 @@ void LLAPRPool::releaseAPRPool()  	}  } +//virtual  apr_pool_t* LLAPRPool::getAPRPool()  +{	 +	return mPool ;  +} + +LLVolatileAPRPool::LLVolatileAPRPool(BOOL is_local, apr_pool_t *parent, apr_size_t size, BOOL releasePoolFlag)  +				  : LLAPRPool(parent, size, releasePoolFlag), +				  mNumActiveRef(0), +				  mNumTotalRef(0), +				  mMutexPool(NULL), +				  mMutexp(NULL)  { -	if(!mPool) +	//create mutex +	if(!is_local) //not a local apr_pool, that is: shared by multiple threads.  	{ -		createAPRPool() ; +		apr_pool_create(&mMutexPool, NULL); // Create a pool for mutex +		apr_thread_mutex_create(&mMutexp, APR_THREAD_MUTEX_UNNESTED, mMutexPool);  	} -	 -	return mPool ;   } -LLVolatileAPRPool::LLVolatileAPRPool(apr_pool_t *parent, apr_size_t size, BOOL releasePoolFlag)  -				  : LLAPRPool(parent, size, releasePoolFlag) + +LLVolatileAPRPool::~LLVolatileAPRPool()  { -	mNumActiveRef = 0 ; -	mNumTotalRef = 0 ; +	//delete mutex +	if(mMutexp) +	{ +		apr_thread_mutex_destroy(mMutexp); +		apr_pool_destroy(mMutexPool); +	}  } -apr_pool_t* LLVolatileAPRPool::getVolatileAPRPool()  +// +//define this virtual function to avoid any mistakenly calling LLAPRPool::getAPRPool(). +// +//virtual  +apr_pool_t* LLVolatileAPRPool::getAPRPool()   { +	return LLVolatileAPRPool::getVolatileAPRPool() ; +} + +apr_pool_t* LLVolatileAPRPool::getVolatileAPRPool()  +{	 +	LLScopedLock lock(mMutexp) ; +  	mNumTotalRef++ ;  	mNumActiveRef++ ; -	return getAPRPool() ; + +	if(!mPool) +	{ +		createAPRPool() ; +	} +	 +	return mPool ;  }  void LLVolatileAPRPool::clearVolatileAPRPool()   { +	LLScopedLock lock(mMutexp) ; +  	if(mNumActiveRef > 0)  	{  		mNumActiveRef--; @@ -251,10 +284,9 @@ void LLScopedLock::unlock()  bool ll_apr_warn_status(apr_status_t status)  {  	if(APR_SUCCESS == status) return false; -#ifndef LL_WINDOWS  	char buf[MAX_STRING];	/* Flawfinder: ignore */ -	LL_WARNS_ONCE("APR") << "APR: " << apr_strerror(status, buf, MAX_STRING) << LL_ENDL; -#endif +	apr_strerror(status, buf, MAX_STRING); +	LL_WARNS("APR") << "APR: " << buf << LL_ENDL;  	return true;  } @@ -268,10 +300,18 @@ void ll_apr_assert_status(apr_status_t status)  // LLAPRFile functions  //  LLAPRFile::LLAPRFile() +	: mFile(NULL), +	  mCurrentFilePoolp(NULL) +{ +} + +LLAPRFile::LLAPRFile(const std::string& filename, apr_int32_t flags, LLVolatileAPRPool* pool) +	: mFile(NULL), +	  mCurrentFilePoolp(NULL)  { -	mFile = NULL ; -	mCurrentFilePoolp = NULL ; +	open(filename, flags, pool);  } +  LLAPRFile::~LLAPRFile()  {  	close() ; @@ -295,11 +335,40 @@ apr_status_t LLAPRFile::close()  	return ret ;  } -apr_status_t LLAPRFile::open(LLVolatileAPRPool* pool, const std::string& filename, apr_int32_t flags, S32* sizep) +apr_status_t LLAPRFile::open(const std::string& filename, apr_int32_t flags, LLVolatileAPRPool* pool, S32* sizep)  {  	apr_status_t s ; -	s = open(filename, flags, pool ? pool->getVolatileAPRPool() : NULL, sizep) ; + +	//check if already open some file +	llassert_always(!mFile) ; +	llassert_always(!mCurrentFilePoolp) ; +	apr_pool_t* apr_pool = pool ? pool->getVolatileAPRPool() : NULL ; +	s = apr_file_open(&mFile, filename.c_str(), flags, APR_OS_DEFAULT, getAPRFilePool(apr_pool)); + +	if (s != APR_SUCCESS || !mFile) +	{ +		mFile = NULL ; +		 +		if (sizep) +		{ +			*sizep = 0; +		} +	} +	else if (sizep) +	{ +		S32 file_size = 0; +		apr_off_t offset = 0; +		if (apr_file_seek(mFile, APR_END, &offset) == APR_SUCCESS) +		{ +			llassert_always(offset <= 0x7fffffff); +			file_size = (S32)offset; +			offset = 0; +			apr_file_seek(mFile, APR_SET, &offset); +		} +		*sizep = file_size; +	} +  	if(!mCurrentFilePoolp)  	{  		mCurrentFilePoolp = pool ; @@ -312,40 +381,25 @@ apr_status_t LLAPRFile::open(LLVolatileAPRPool* pool, const std::string& filenam  	return s ;  } -apr_status_t LLAPRFile::open(const std::string& filename, apr_int32_t flags, apr_pool_t* pool, S32* sizep) + +//use gAPRPoolp. +apr_status_t LLAPRFile::open(const std::string& filename, apr_int32_t flags, BOOL use_global_pool)  {  	apr_status_t s;  	//check if already open some file  	llassert_always(!mFile) ;  	llassert_always(!mCurrentFilePoolp) ; +	llassert_always(use_global_pool) ; //be aware of using gAPRPoolp. -	s = apr_file_open(&mFile, filename.c_str(), flags, APR_OS_DEFAULT, getAPRFilePool(pool)); +	s = apr_file_open(&mFile, filename.c_str(), flags, APR_OS_DEFAULT, gAPRPoolp);  	if (s != APR_SUCCESS || !mFile)  	{  		mFile = NULL ;  		close() ; -		if (sizep) -		{ -			*sizep = 0; -		}  		return s;  	} -	if (sizep) -	{ -		S32 file_size = 0; -		apr_off_t offset = 0; -		if (apr_file_seek(mFile, APR_END, &offset) == APR_SUCCESS) -		{ -			llassert_always(offset <= 0x7fffffff); -			file_size = (S32)offset; -			offset = 0; -			apr_file_seek(mFile, APR_SET, &offset); -		} -		*sizep = file_size; -	} -  	return s;  } @@ -369,6 +423,7 @@ S32 LLAPRFile::read(void *buf, S32 nbytes)  	apr_status_t s = apr_file_read(mFile, buf, &sz);  	if (s != APR_SUCCESS)  	{ +		ll_apr_warn_status(s);  		return 0;  	}  	else @@ -386,6 +441,7 @@ S32 LLAPRFile::write(const void *buf, S32 nbytes)  	apr_status_t s = apr_file_write(mFile, buf, &sz);  	if (s != APR_SUCCESS)  	{ +		ll_apr_warn_status(s);  		return 0;  	}  	else @@ -434,6 +490,8 @@ apr_file_t* LLAPRFile::open(const std::string& filename, LLVolatileAPRPool* pool  	s = apr_file_open(&file_handle, filename.c_str(), flags, APR_OS_DEFAULT, pool->getVolatileAPRPool());  	if (s != APR_SUCCESS || !file_handle)  	{ +		ll_apr_warn_status(s); +		LL_WARNS("APR") << " Attempting to open filename: " << filename << LL_ENDL;  		file_handle = NULL ;  		close(file_handle, pool) ;  		return NULL; @@ -464,6 +522,7 @@ S32 LLAPRFile::seek(apr_file_t* file_handle, apr_seek_where_t where, S32 offset)  	}  	if (s != APR_SUCCESS)  	{ +		ll_apr_warn_status(s);  		return -1;  	}  	else @@ -501,6 +560,8 @@ S32 LLAPRFile::readEx(const std::string& filename, void *buf, S32 offset, S32 nb  		apr_status_t s = apr_file_read(file_handle, buf, &bytes_read);  		if (s != APR_SUCCESS)  		{ +			LL_WARNS("APR") << " Attempting to read filename: " << filename << LL_ENDL; +			ll_apr_warn_status(s);  			bytes_read = 0;  		}  		else @@ -549,6 +610,8 @@ S32 LLAPRFile::writeEx(const std::string& filename, void *buf, S32 offset, S32 n  		apr_status_t s = apr_file_write(file_handle, buf, &bytes_written);  		if (s != APR_SUCCESS)  		{ +			LL_WARNS("APR") << " Attempting to write filename: " << filename << LL_ENDL; +			ll_apr_warn_status(s);  			bytes_written = 0;  		}  		else @@ -575,8 +638,8 @@ bool LLAPRFile::remove(const std::string& filename, LLVolatileAPRPool* pool)  	if (s != APR_SUCCESS)  	{ -		LL_DEBUGS("APR") << "LLAPRFile::remove failed on file: " << filename << LL_ENDL;  		ll_apr_warn_status(s); +		LL_WARNS("APR") << " Attempting to remove filename: " << filename << LL_ENDL;  		return false;  	}  	return true; @@ -593,8 +656,8 @@ bool LLAPRFile::rename(const std::string& filename, const std::string& newname,  	if (s != APR_SUCCESS)  	{ -		LL_DEBUGS("APR") << "LLAPRFile::rename failed on file: " << filename << LL_ENDL;  		ll_apr_warn_status(s); +		LL_WARNS("APR") << " Attempting to rename filename: " << filename << LL_ENDL;  		return false;  	}  	return true; @@ -667,8 +730,8 @@ bool LLAPRFile::makeDir(const std::string& dirname, LLVolatileAPRPool* pool)  	if (s != APR_SUCCESS)  	{ -		LL_DEBUGS("APR") << "LLAPRFile::makeDir failed on file: " << dirname << LL_ENDL;  		ll_apr_warn_status(s); +		LL_WARNS("APR") << " Attempting to make directory: " << dirname << LL_ENDL;  		return false;  	}  	return true; @@ -685,8 +748,8 @@ bool LLAPRFile::removeDir(const std::string& dirname, LLVolatileAPRPool* pool)  	if (s != APR_SUCCESS)  	{ -		LL_DEBUGS("APR") << "LLAPRFile::removeDir failed on file: " << dirname << LL_ENDL;  		ll_apr_warn_status(s); +		LL_WARNS("APR") << " Attempting to remove directory: " << dirname << LL_ENDL;  		return false;  	}  	return true; diff --git a/indra/llcommon/llapr.h b/indra/llcommon/llapr.h index 0898aeec47..b08bb617c5 100644 --- a/indra/llcommon/llapr.h +++ b/indra/llcommon/llapr.h @@ -1,259 +1,265 @@ -/** 
 - * @file llapr.h
 - * @author Phoenix
 - * @date 2004-11-28
 - * @brief Helper functions for using the apache portable runtime library.
 - *
 - * $LicenseInfo:firstyear=2004&license=viewergpl$
 - * 
 - * Copyright (c) 2004-2009, Linden Research, Inc.
 - * 
 - * Second Life Viewer Source Code
 - * The source code in this file ("Source Code") is provided by Linden Lab
 - * to you under the terms of the GNU General Public License, version 2.0
 - * ("GPL"), unless you have obtained a separate licensing agreement
 - * ("Other License"), formally executed by you and Linden Lab.  Terms of
 - * the GPL can be found in doc/GPL-license.txt in this distribution, or
 - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
 - * 
 - * There are special exceptions to the terms and conditions of the GPL as
 - * it is applied to this Source Code. View the full text of the exception
 - * in the file doc/FLOSS-exception.txt in this software distribution, or
 - * online at
 - * http://secondlifegrid.net/programs/open_source/licensing/flossexception
 - * 
 - * By copying, modifying or distributing this software, you acknowledge
 - * that you have read and understood your obligations described above,
 - * and agree to abide by those obligations.
 - * 
 - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
 - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
 - * COMPLETENESS OR PERFORMANCE.
 - * $/LicenseInfo$
 - */
 -
 -#ifndef LL_LLAPR_H
 -#define LL_LLAPR_H
 -
 -#if LL_LINUX || LL_SOLARIS
 -#include <sys/param.h>  // Need PATH_MAX in APR headers...
 -#endif
 -
 -#include <boost/noncopyable.hpp>
 -
 -#include "apr_thread_proc.h"
 -#include "apr_thread_mutex.h"
 -#include "apr_getopt.h"
 -#include "apr_signal.h"
 -#include "apr_atomic.h"
 -#include "llstring.h"
 -
 -extern LL_COMMON_API apr_thread_mutex_t* gLogMutexp;
 -extern apr_thread_mutex_t* gCallStacksLogMutexp;
 -
 -/** 
 - * @brief initialize the common apr constructs -- apr itself, the
 - * global pool, and a mutex.
 - */
 -void LL_COMMON_API ll_init_apr();
 -
 -/** 
 - * @brief Cleanup those common apr constructs.
 - */
 -void LL_COMMON_API ll_cleanup_apr();
 -
 -//
 -//LL apr_pool
 -//manage apr_pool_t, destroy allocated apr_pool in the destruction function.
 -//
 -class LL_COMMON_API LLAPRPool
 -{
 -public:
 -	LLAPRPool(apr_pool_t *parent = NULL, apr_size_t size = 0, BOOL releasePoolFlag = TRUE) ;
 -	~LLAPRPool() ;
 -
 -	apr_pool_t* getAPRPool() ;
 -	apr_status_t getStatus() {return mStatus ; }
 -
 -protected:
 -	void releaseAPRPool() ;
 -	void createAPRPool() ;
 -
 -protected:
 -	apr_pool_t*  mPool ;              //pointing to an apr_pool
 -	apr_pool_t*  mParent ;			  //parent pool
 -	apr_size_t   mMaxSize ;           //max size of mPool, mPool should return memory to system if allocated memory beyond this limit. However it seems not to work.
 -	apr_status_t mStatus ;            //status when creating the pool
 -	BOOL         mReleasePoolFlag ;   //if set, mPool is destroyed when LLAPRPool is deleted. default value is true.
 -};
 -
 -//
 -//volatile LL apr_pool
 -//which clears memory automatically.
 -//so it can not hold static data or data after memory is cleared
 -//
 -class LL_COMMON_API LLVolatileAPRPool : public LLAPRPool
 -{
 -public:
 -	LLVolatileAPRPool(apr_pool_t *parent = NULL, apr_size_t size = 0, BOOL releasePoolFlag = TRUE);
 -	~LLVolatileAPRPool(){}
 -
 -	apr_pool_t* getVolatileAPRPool() ;
 -	
 -	void        clearVolatileAPRPool() ;
 -
 -	BOOL        isFull() ;
 -	BOOL        isEmpty() {return !mNumActiveRef ;}
 -private:
 -	S32 mNumActiveRef ; //number of active pointers pointing to the apr_pool.
 -	S32 mNumTotalRef ;  //number of total pointers pointing to the apr_pool since last creating.   
 -} ;
 -
 -/** 
 - * @class LLScopedLock
 - * @brief Small class to help lock and unlock mutexes.
 - *
 - * This class is used to have a stack level lock once you already have
 - * an apr mutex handy. The constructor handles the lock, and the
 - * destructor handles the unlock. Instances of this class are
 - * <b>not</b> thread safe.
 - */
 -class LL_COMMON_API LLScopedLock : private boost::noncopyable
 -{
 -public:
 -	/**
 -	 * @brief Constructor which accepts a mutex, and locks it.
 -	 *
 -	 * @param mutex An allocated APR mutex. If you pass in NULL,
 -	 * this wrapper will not lock.
 -	 */
 -	LLScopedLock(apr_thread_mutex_t* mutex);
 -
 -	/**
 -	 * @brief Destructor which unlocks the mutex if still locked.
 -	 */
 -	~LLScopedLock();
 -
 -	/** 
 -	 * @brief Check lock.
 -	 */
 -	bool isLocked() const { return mLocked; }
 -
 -	/** 
 -	 * @brief This method unlocks the mutex.
 -	 */
 -	void unlock();
 -
 -protected:
 -	bool mLocked;
 -	apr_thread_mutex_t* mMutex;
 -};
 -
 -template <typename Type> class LLAtomic32
 -{
 -public:
 -	LLAtomic32<Type>() {};
 -	LLAtomic32<Type>(Type x) {apr_atomic_set32(&mData, apr_uint32_t(x)); };
 -	~LLAtomic32<Type>() {};
 -
 -	operator const Type() { apr_uint32_t data = apr_atomic_read32(&mData); return Type(data); }
 -	Type operator =(const Type& x) { apr_atomic_set32(&mData, apr_uint32_t(x)); return Type(mData); }
 -	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--
 -	
 -private:
 -	apr_uint32_t mData;
 -};
 -
 -typedef LLAtomic32<U32> LLAtomicU32;
 -typedef LLAtomic32<S32> LLAtomicS32;
 -
 -// File IO convenience functions.
 -// Returns NULL if the file fails to openm sets *sizep to file size of not NULL
 -// abbreviated flags
 -#define LL_APR_R (APR_READ) // "r"
 -#define LL_APR_W (APR_CREATE|APR_TRUNCATE|APR_WRITE) // "w"
 -#define LL_APR_RB (APR_READ|APR_BINARY) // "rb"
 -#define LL_APR_WB (APR_CREATE|APR_TRUNCATE|APR_WRITE|APR_BINARY) // "wb"
 -#define LL_APR_RPB (APR_READ|APR_WRITE|APR_BINARY) // "r+b"
 -#define LL_APR_WPB (APR_CREATE|APR_TRUNCATE|APR_READ|APR_WRITE|APR_BINARY) // "w+b"
 -
 -//
 -//apr_file manager
 -//which: 1)only keeps one file open;
 -//       2)closes the open file in the destruction function
 -//       3)informs the apr_pool to clean the memory when the file is closed.
 -//Note: please close an open file at the earliest convenience. 
 -//      especially do not put some time-costly operations between open() and close().
 -//      otherwise it might lock the APRFilePool.
 -//there are two different apr_pools the APRFile can use:
 -//      1, a temperary pool passed to an APRFile function, which is used within this function and only once.
 -//      2, a global pool.
 -//
 -class LL_COMMON_API LLAPRFile
 -{
 -private:
 -	apr_file_t* mFile ;
 -	LLVolatileAPRPool *mCurrentFilePoolp ; //currently in use apr_pool, could be one of them: sAPRFilePoolp, or a temp pool. 
 -
 -public:
 -	LLAPRFile() ;
 -	~LLAPRFile() ;
 -
 -	apr_status_t open(LLVolatileAPRPool* pool, const std::string& filename, apr_int32_t flags, S32* sizep = NULL);
 -	apr_status_t open(const std::string& filename, apr_int32_t flags, apr_pool_t* pool = NULL, S32* sizep = NULL);
 -	apr_status_t close() ;
 -
 -	// Returns actual offset, -1 if seek fails
 -	S32 seek(apr_seek_where_t where, S32 offset);
 -	apr_status_t eof() { return apr_file_eof(mFile);}
 -
 -	// Returns bytes read/written, 0 if read/write fails:
 -	S32 read(void* buf, S32 nbytes);
 -	S32 write(const void* buf, S32 nbytes);
 -	
 -	apr_file_t* getFileHandle() {return mFile;}	
 -
 -private:
 -	apr_pool_t* getAPRFilePool(apr_pool_t* pool) ;
 -
 -//
 -//*******************************************************************************************************************************
 -//static components
 -//
 -public:
 -	static LLVolatileAPRPool *sAPRFilePoolp ; //a global apr_pool for APRFile, which is used only when local pool does not exist.
 -
 -private:
 -	static apr_file_t* open(const std::string& filename, LLVolatileAPRPool* pool, apr_int32_t flags);
 -	static apr_status_t close(apr_file_t* file, LLVolatileAPRPool* pool) ;
 -	static S32 seek(apr_file_t* file, apr_seek_where_t where, S32 offset);
 -public:
 -	// returns false if failure:
 -	static bool remove(const std::string& filename, LLVolatileAPRPool* pool = NULL);
 -	static bool rename(const std::string& filename, const std::string& newname, LLVolatileAPRPool* pool = NULL);
 -	static bool isExist(const std::string& filename, LLVolatileAPRPool* pool = NULL, apr_int32_t flags = APR_READ);
 -	static S32 size(const std::string& filename, LLVolatileAPRPool* pool = NULL);
 -	static bool makeDir(const std::string& dirname, LLVolatileAPRPool* pool = NULL);
 -	static bool removeDir(const std::string& dirname, LLVolatileAPRPool* pool = NULL);
 -
 -	// Returns bytes read/written, 0 if read/write fails:
 -	static S32 readEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool = NULL);	
 -	static S32 writeEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool = NULL);	
 -//*******************************************************************************************************************************
 -};
 -
 -/**
 - * @brief Function which approprately logs error or remains quiet on
 - * APR_SUCCESS.
 - * @return Returns <code>true</code> if status is an error condition.
 - */
 -bool LL_COMMON_API ll_apr_warn_status(apr_status_t status);
 -
 -void LL_COMMON_API ll_apr_assert_status(apr_status_t status);
 -
 -extern "C" LL_COMMON_API apr_pool_t* gAPRPoolp; // Global APR memory pool
 -
 -#endif // LL_LLAPR_H
 +/**  + * @file llapr.h + * @author Phoenix + * @date 2004-11-28 + * @brief Helper functions for using the apache portable runtime library. + * + * $LicenseInfo:firstyear=2004&license=viewergpl$ + *  + * Copyright (c) 2004-2009, Linden Research, Inc. + *  + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab.  Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + *  + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + *  + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + *  + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLAPR_H +#define LL_LLAPR_H + +#if LL_LINUX || LL_SOLARIS +#include <sys/param.h>  // Need PATH_MAX in APR headers... +#endif + +#include <boost/noncopyable.hpp> + +#include "apr_thread_proc.h" +#include "apr_thread_mutex.h" +#include "apr_getopt.h" +#include "apr_signal.h" +#include "apr_atomic.h" +#include "llstring.h" + +extern LL_COMMON_API apr_thread_mutex_t* gLogMutexp; +extern apr_thread_mutex_t* gCallStacksLogMutexp; + +/**  + * @brief initialize the common apr constructs -- apr itself, the + * global pool, and a mutex. + */ +void LL_COMMON_API ll_init_apr(); + +/**  + * @brief Cleanup those common apr constructs. + */ +void LL_COMMON_API ll_cleanup_apr(); + +// +//LL apr_pool +//manage apr_pool_t, destroy allocated apr_pool in the destruction function. +// +class LL_COMMON_API LLAPRPool +{ +public: +	LLAPRPool(apr_pool_t *parent = NULL, apr_size_t size = 0, BOOL releasePoolFlag = TRUE) ; +	virtual ~LLAPRPool() ; + +	virtual apr_pool_t* getAPRPool() ; +	apr_status_t getStatus() {return mStatus ; } + +protected: +	void releaseAPRPool() ; +	void createAPRPool() ; + +protected: +	apr_pool_t*  mPool ;              //pointing to an apr_pool +	apr_pool_t*  mParent ;			  //parent pool +	apr_size_t   mMaxSize ;           //max size of mPool, mPool should return memory to system if allocated memory beyond this limit. However it seems not to work. +	apr_status_t mStatus ;            //status when creating the pool +	BOOL         mReleasePoolFlag ;   //if set, mPool is destroyed when LLAPRPool is deleted. default value is true. +}; + +// +//volatile LL apr_pool +//which clears memory automatically. +//so it can not hold static data or data after memory is cleared +// +class LL_COMMON_API LLVolatileAPRPool : public LLAPRPool +{ +public: +	LLVolatileAPRPool(BOOL is_local = TRUE, apr_pool_t *parent = NULL, apr_size_t size = 0, BOOL releasePoolFlag = TRUE); +	virtual ~LLVolatileAPRPool(); + +	/*virtual*/ apr_pool_t* getAPRPool() ; //define this virtual function to avoid any mistakenly calling LLAPRPool::getAPRPool(). +	apr_pool_t* getVolatileAPRPool() ;	 +	void        clearVolatileAPRPool() ; + +	BOOL        isFull() ; +	 +private: +	S32 mNumActiveRef ; //number of active pointers pointing to the apr_pool. +	S32 mNumTotalRef ;  //number of total pointers pointing to the apr_pool since last creating.   + +	apr_thread_mutex_t *mMutexp; +	apr_pool_t         *mMutexPool; +} ; + +/**  + * @class LLScopedLock + * @brief Small class to help lock and unlock mutexes. + * + * This class is used to have a stack level lock once you already have + * an apr mutex handy. The constructor handles the lock, and the + * destructor handles the unlock. Instances of this class are + * <b>not</b> thread safe. + */ +class LL_COMMON_API LLScopedLock : private boost::noncopyable +{ +public: +	/** +	 * @brief Constructor which accepts a mutex, and locks it. +	 * +	 * @param mutex An allocated APR mutex. If you pass in NULL, +	 * this wrapper will not lock. +	 */ +	LLScopedLock(apr_thread_mutex_t* mutex); + +	/** +	 * @brief Destructor which unlocks the mutex if still locked. +	 */ +	~LLScopedLock(); + +	/**  +	 * @brief Check lock. +	 */ +	bool isLocked() const { return mLocked; } + +	/**  +	 * @brief This method unlocks the mutex. +	 */ +	void unlock(); + +protected: +	bool mLocked; +	apr_thread_mutex_t* mMutex; +}; + +template <typename Type> class LLAtomic32 +{ +public: +	LLAtomic32<Type>() {}; +	LLAtomic32<Type>(Type x) {apr_atomic_set32(&mData, apr_uint32_t(x)); }; +	~LLAtomic32<Type>() {}; + +	operator const Type() { apr_uint32_t data = apr_atomic_read32(&mData); return Type(data); } +	Type operator =(const Type& x) { apr_atomic_set32(&mData, apr_uint32_t(x)); return Type(mData); } +	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-- +	 +private: +	apr_uint32_t mData; +}; + +typedef LLAtomic32<U32> LLAtomicU32; +typedef LLAtomic32<S32> LLAtomicS32; + +// File IO convenience functions. +// Returns NULL if the file fails to openm sets *sizep to file size of not NULL +// abbreviated flags +#define LL_APR_R (APR_READ) // "r" +#define LL_APR_W (APR_CREATE|APR_TRUNCATE|APR_WRITE) // "w" +#define LL_APR_RB (APR_READ|APR_BINARY) // "rb" +#define LL_APR_WB (APR_CREATE|APR_TRUNCATE|APR_WRITE|APR_BINARY) // "wb" +#define LL_APR_RPB (APR_READ|APR_WRITE|APR_BINARY) // "r+b" +#define LL_APR_WPB (APR_CREATE|APR_TRUNCATE|APR_READ|APR_WRITE|APR_BINARY) // "w+b" + +// +//apr_file manager +//which: 1)only keeps one file open; +//       2)closes the open file in the destruction function +//       3)informs the apr_pool to clean the memory when the file is closed. +//Note: please close an open file at the earliest convenience.  +//      especially do not put some time-costly operations between open() and close(). +//      otherwise it might lock the APRFilePool. +//there are two different apr_pools the APRFile can use: +//      1, a temperary pool passed to an APRFile function, which is used within this function and only once. +//      2, a global pool. +// + +class LL_COMMON_API LLAPRFile : boost::noncopyable +{ +	// make this non copyable since a copy closes the file +private: +	apr_file_t* mFile ; +	LLVolatileAPRPool *mCurrentFilePoolp ; //currently in use apr_pool, could be one of them: sAPRFilePoolp, or a temp pool.  + +public: +	LLAPRFile() ; +	LLAPRFile(const std::string& filename, apr_int32_t flags, LLVolatileAPRPool* pool = NULL); +	~LLAPRFile() ; +	 +	apr_status_t open(const std::string& filename, apr_int32_t flags, LLVolatileAPRPool* pool = NULL, S32* sizep = NULL); +	apr_status_t open(const std::string& filename, apr_int32_t flags, BOOL use_global_pool); //use gAPRPoolp. +	apr_status_t close() ; + +	// Returns actual offset, -1 if seek fails +	S32 seek(apr_seek_where_t where, S32 offset); +	apr_status_t eof() { return apr_file_eof(mFile);} + +	// Returns bytes read/written, 0 if read/write fails: +	S32 read(void* buf, S32 nbytes); +	S32 write(const void* buf, S32 nbytes); +	 +	apr_file_t* getFileHandle() {return mFile;}	 + +private: +	apr_pool_t* getAPRFilePool(apr_pool_t* pool) ;	 +	 +// +//******************************************************************************************************************************* +//static components +// +public: +	static LLVolatileAPRPool *sAPRFilePoolp ; //a global apr_pool for APRFile, which is used only when local pool does not exist. + +private: +	static apr_file_t* open(const std::string& filename, LLVolatileAPRPool* pool, apr_int32_t flags); +	static apr_status_t close(apr_file_t* file, LLVolatileAPRPool* pool) ; +	static S32 seek(apr_file_t* file, apr_seek_where_t where, S32 offset); +public: +	// returns false if failure: +	static bool remove(const std::string& filename, LLVolatileAPRPool* pool = NULL); +	static bool rename(const std::string& filename, const std::string& newname, LLVolatileAPRPool* pool = NULL); +	static bool isExist(const std::string& filename, LLVolatileAPRPool* pool = NULL, apr_int32_t flags = APR_READ); +	static S32 size(const std::string& filename, LLVolatileAPRPool* pool = NULL); +	static bool makeDir(const std::string& dirname, LLVolatileAPRPool* pool = NULL); +	static bool removeDir(const std::string& dirname, LLVolatileAPRPool* pool = NULL); + +	// Returns bytes read/written, 0 if read/write fails: +	static S32 readEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool = NULL);	 +	static S32 writeEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool = NULL);	 +//******************************************************************************************************************************* +}; + +/** + * @brief Function which approprately logs error or remains quiet on + * APR_SUCCESS. + * @return Returns <code>true</code> if status is an error condition. + */ +bool LL_COMMON_API ll_apr_warn_status(apr_status_t status); + +void LL_COMMON_API ll_apr_assert_status(apr_status_t status); + +extern "C" LL_COMMON_API apr_pool_t* gAPRPoolp; // Global APR memory pool + +#endif // LL_LLAPR_H diff --git a/indra/llcommon/llassettype.cpp b/indra/llcommon/llassettype.cpp index b2a92861cc..6d5b12d840 100644 --- a/indra/llcommon/llassettype.cpp +++ b/indra/llcommon/llassettype.cpp @@ -43,30 +43,21 @@  struct AssetEntry : public LLDictionaryEntry  {  	AssetEntry(const char *desc_name, -			   const char *type_name, // 8 character limit! -			   const char *human_name, // for decoding to human readable form; put any and as many printable characters you want in each one -			   const char *category_name, // used by llinventorymodel when creating new categories -			   EDragAndDropType dad_type, -			   bool can_link, // can you create a link to this type? -			   bool is_protected) // can the viewer change categories of this type? +			   const char *type_name, 	// 8 character limit! +			   const char *human_name, 	// for decoding to human readable form; put any and as many printable characters you want in each one +			   bool can_link) 			// can you create a link to this type?  		:  		LLDictionaryEntry(desc_name),  		mTypeName(type_name),  		mHumanName(human_name), -		mCategoryName(category_name), -		mDadType(dad_type), -		mCanLink(can_link), -		mIsProtected(is_protected) +		mCanLink(can_link)  	{  		llassert(strlen(mTypeName) <= 8);  	}  	const char *mTypeName;  	const char *mHumanName; -	const char *mCategoryName; -	EDragAndDropType mDadType;  	bool mCanLink; -	bool mIsProtected;  };  class LLAssetDictionary : public LLSingleton<LLAssetDictionary>, @@ -78,48 +69,32 @@ public:  LLAssetDictionary::LLAssetDictionary()  { -	//       												   DESCRIPTION			TYPE NAME	HUMAN NAME			CATEGORY NAME 		DRAG&DROP		CAN LINK?	PROTECTED? -	//      												  |--------------------|-----------|-------------------|-------------------|---------------|-----------|-----------| -	addEntry(LLAssetType::AT_TEXTURE, 			new AssetEntry("TEXTURE",			"texture",	"texture",			"Textures", 		DAD_TEXTURE,	TRUE,		TRUE)); -	addEntry(LLAssetType::AT_SOUND, 			new AssetEntry("SOUND",				"sound",	"sound",			"Sounds", 			DAD_SOUND,		TRUE,		TRUE)); -	addEntry(LLAssetType::AT_CALLINGCARD, 		new AssetEntry("CALLINGCARD",		"callcard",	"calling card",		"Calling Cards", 	DAD_CALLINGCARD, TRUE,		TRUE)); -	addEntry(LLAssetType::AT_LANDMARK, 			new AssetEntry("LANDMARK",			"landmark",	"landmark",			"Landmarks", 		DAD_LANDMARK,	TRUE,		TRUE)); -	addEntry(LLAssetType::AT_SCRIPT, 			new AssetEntry("SCRIPT",			"script",	"legacy script",	"Scripts", 			DAD_NONE,		TRUE,		TRUE)); -	addEntry(LLAssetType::AT_CLOTHING, 			new AssetEntry("CLOTHING",			"clothing",	"clothing",			"Clothing", 		DAD_CLOTHING,	TRUE,		TRUE)); -	addEntry(LLAssetType::AT_OBJECT, 			new AssetEntry("OBJECT",			"object",	"object",			"Objects", 			DAD_OBJECT,		TRUE,		TRUE)); -	addEntry(LLAssetType::AT_NOTECARD, 			new AssetEntry("NOTECARD",			"notecard",	"note card",		"Notecards", 		DAD_NOTECARD,	TRUE,		TRUE)); -	addEntry(LLAssetType::AT_CATEGORY, 			new AssetEntry("CATEGORY",			"category",	"folder",			"New Folder", 		DAD_CATEGORY,	TRUE,		TRUE)); -	addEntry(LLAssetType::AT_ROOT_CATEGORY, 	new AssetEntry("ROOT_CATEGORY",		"root",		"root",				"Inventory", 		DAD_ROOT_CATEGORY, TRUE,	TRUE)); -	addEntry(LLAssetType::AT_LSL_TEXT, 			new AssetEntry("LSL_TEXT",			"lsltext",	"lsl2 script",		"Scripts", 			DAD_SCRIPT,		TRUE,		TRUE)); -	addEntry(LLAssetType::AT_LSL_BYTECODE, 		new AssetEntry("LSL_BYTECODE",		"lslbyte",	"lsl bytecode",		"Scripts", 			DAD_NONE,		TRUE,		TRUE)); -	addEntry(LLAssetType::AT_TEXTURE_TGA, 		new AssetEntry("TEXTURE_TGA",		"txtr_tga",	"tga texture",		"Uncompressed Images", DAD_NONE,	TRUE,		TRUE)); -	addEntry(LLAssetType::AT_BODYPART, 			new AssetEntry("BODYPART",			"bodypart",	"body part",		"Body Parts", 		DAD_BODYPART,	TRUE,		TRUE)); -	addEntry(LLAssetType::AT_TRASH, 			new AssetEntry("TRASH",				"trash",	"trash",			"Trash", 			DAD_NONE,		FALSE,		TRUE)); -	addEntry(LLAssetType::AT_SNAPSHOT_CATEGORY, new AssetEntry("SNAPSHOT_CATEGORY", "snapshot",	"snapshot",			"Photo Album", 		DAD_NONE,		FALSE,		TRUE)); -	addEntry(LLAssetType::AT_LOST_AND_FOUND, 	new AssetEntry("LOST_AND_FOUND", 	"lstndfnd",	"lost and found",	"Lost And Found", 	DAD_NONE,		FALSE,		TRUE)); -	addEntry(LLAssetType::AT_SOUND_WAV, 		new AssetEntry("SOUND_WAV",			"snd_wav",	"sound",			"Uncompressed SoundS", DAD_NONE,	TRUE,		TRUE)); -	addEntry(LLAssetType::AT_IMAGE_TGA, 		new AssetEntry("IMAGE_TGA",			"img_tga",	"targa image",		"Uncompressed Images", DAD_NONE,	TRUE,		TRUE)); -	addEntry(LLAssetType::AT_IMAGE_JPEG, 		new AssetEntry("IMAGE_JPEG",		"jpeg",		"jpeg image",		"Uncompressed Images", DAD_NONE,	TRUE,		TRUE)); -	addEntry(LLAssetType::AT_ANIMATION, 		new AssetEntry("ANIMATION",			"animatn",	"animation",		"Animations", 		DAD_ANIMATION,	TRUE,		TRUE)); -	addEntry(LLAssetType::AT_GESTURE, 			new AssetEntry("GESTURE",			"gesture",	"gesture",			"Gestures", 		DAD_GESTURE,	TRUE,		TRUE)); -	addEntry(LLAssetType::AT_SIMSTATE, 			new AssetEntry("SIMSTATE",			"simstate",	"simstate",			"New Folder", 		DAD_NONE,		FALSE,		TRUE)); -	addEntry(LLAssetType::AT_FAVORITE, 			new AssetEntry("FAVORITE",			"favorite",	"favorite",			"favorite", 		DAD_NONE,		FALSE,		TRUE)); - -	addEntry(LLAssetType::AT_LINK, 				new AssetEntry("LINK",				"link",		"symbolic link",	"Link", 			DAD_LINK,		FALSE,		TRUE)); -	addEntry(LLAssetType::AT_LINK_FOLDER, 		new AssetEntry("FOLDER_LINK",		"link_f", 	"symbolic folder link", "New Folder", 	DAD_LINK,		FALSE,		TRUE)); - -	for (S32 ensemble_num = S32(LLAssetType::AT_FOLDER_ENSEMBLE_START);  -		 ensemble_num <= S32(LLAssetType::AT_FOLDER_ENSEMBLE_END);  -		 ensemble_num++) -	{ -		addEntry(LLAssetType::EType(ensemble_num), new AssetEntry("ENSEMBLE",		"ensemble", "ensemble", 		"New Folder", 		DAD_CATEGORY,	FALSE,		FALSE));  -	} - -	addEntry(LLAssetType::AT_CURRENT_OUTFIT, 	new AssetEntry("CURRENT",			"current",	"current outfit",	"Current Look", 	DAD_CATEGORY,	FALSE,		TRUE)); -	addEntry(LLAssetType::AT_OUTFIT, 			new AssetEntry("OUTFIT",			"outfit",	"outfit",			"New Look", 		DAD_CATEGORY,	FALSE,		FALSE)); -	addEntry(LLAssetType::AT_MY_OUTFITS, 		new AssetEntry("MY_OUTFITS",		"my_otfts",	"my outfits",		"My Looks", 		DAD_CATEGORY,	FALSE,		TRUE)); -		  -	addEntry(LLAssetType::AT_NONE, 				new AssetEntry("NONE",				"-1",		NULL,		  		"New Folder", 		DAD_NONE,		FALSE,		FALSE)); +	//       												   DESCRIPTION			TYPE NAME	HUMAN NAME			CAN LINK?	 +	//      												  |--------------------|-----------|-------------------|-----------| +	addEntry(LLAssetType::AT_TEXTURE, 			new AssetEntry("TEXTURE",			"texture",	"texture",			FALSE)); +	addEntry(LLAssetType::AT_SOUND, 			new AssetEntry("SOUND",				"sound",	"sound",			FALSE)); +	addEntry(LLAssetType::AT_CALLINGCARD, 		new AssetEntry("CALLINGCARD",		"callcard",	"calling card",		FALSE)); +	addEntry(LLAssetType::AT_LANDMARK, 			new AssetEntry("LANDMARK",			"landmark",	"landmark",			FALSE)); +	addEntry(LLAssetType::AT_SCRIPT, 			new AssetEntry("SCRIPT",			"script",	"legacy script",	FALSE)); +	addEntry(LLAssetType::AT_CLOTHING, 			new AssetEntry("CLOTHING",			"clothing",	"clothing",			TRUE)); +	addEntry(LLAssetType::AT_OBJECT, 			new AssetEntry("OBJECT",			"object",	"object",			TRUE)); +	addEntry(LLAssetType::AT_NOTECARD, 			new AssetEntry("NOTECARD",			"notecard",	"note card",		FALSE)); +	addEntry(LLAssetType::AT_CATEGORY, 			new AssetEntry("CATEGORY",			"category",	"folder",			TRUE)); +	addEntry(LLAssetType::AT_LSL_TEXT, 			new AssetEntry("LSL_TEXT",			"lsltext",	"lsl2 script",		FALSE)); +	addEntry(LLAssetType::AT_LSL_BYTECODE, 		new AssetEntry("LSL_BYTECODE",		"lslbyte",	"lsl bytecode",		FALSE)); +	addEntry(LLAssetType::AT_TEXTURE_TGA, 		new AssetEntry("TEXTURE_TGA",		"txtr_tga",	"tga texture",		FALSE)); +	addEntry(LLAssetType::AT_BODYPART, 			new AssetEntry("BODYPART",			"bodypart",	"body part",		TRUE)); +	addEntry(LLAssetType::AT_SOUND_WAV, 		new AssetEntry("SOUND_WAV",			"snd_wav",	"sound",			FALSE)); +	addEntry(LLAssetType::AT_IMAGE_TGA, 		new AssetEntry("IMAGE_TGA",			"img_tga",	"targa image",		FALSE)); +	addEntry(LLAssetType::AT_IMAGE_JPEG, 		new AssetEntry("IMAGE_JPEG",		"jpeg",		"jpeg image",		FALSE)); +	addEntry(LLAssetType::AT_ANIMATION, 		new AssetEntry("ANIMATION",			"animatn",	"animation",		FALSE)); +	addEntry(LLAssetType::AT_GESTURE, 			new AssetEntry("GESTURE",			"gesture",	"gesture",			TRUE)); +	addEntry(LLAssetType::AT_SIMSTATE, 			new AssetEntry("SIMSTATE",			"simstate",	"simstate",			FALSE)); + +	addEntry(LLAssetType::AT_LINK, 				new AssetEntry("LINK",				"link",		"symbolic link",	FALSE)); +	addEntry(LLAssetType::AT_LINK_FOLDER, 		new AssetEntry("FOLDER_LINK",		"link_f", 	"symbolic folder link", FALSE)); + +	addEntry(LLAssetType::AT_NONE, 				new AssetEntry("NONE",				"-1",		NULL,		  		FALSE));  };  // static @@ -140,8 +115,7 @@ const std::string &LLAssetType::getDesc(LLAssetType::EType asset_type)  	}  	else  	{ -		static const std::string error_string = "BAD TYPE"; -		return error_string; +		return badLookup();  	}  } @@ -156,7 +130,7 @@ const char *LLAssetType::lookup(LLAssetType::EType asset_type)  	}  	else  	{ -		return "-1"; +		return badLookup().c_str();  	}  } @@ -166,6 +140,7 @@ LLAssetType::EType LLAssetType::lookup(const char* name)  	return lookup(ll_safe_string(name));  } +// static  LLAssetType::EType LLAssetType::lookup(const std::string& type_name)  {  	const LLAssetDictionary *dict = LLAssetDictionary::getInstance(); @@ -193,7 +168,7 @@ const char *LLAssetType::lookupHumanReadable(LLAssetType::EType asset_type)  	}  	else  	{ -		return NULL; +		return badLookup().c_str();  	}  } @@ -203,6 +178,7 @@ LLAssetType::EType LLAssetType::lookupHumanReadable(const char* name)  	return lookupHumanReadable(ll_safe_string(name));  } +// static  LLAssetType::EType LLAssetType::lookupHumanReadable(const std::string& readable_name)  {  	const LLAssetDictionary *dict = LLAssetDictionary::getInstance(); @@ -220,32 +196,6 @@ LLAssetType::EType LLAssetType::lookupHumanReadable(const std::string& readable_  }  // static -const char *LLAssetType::lookupCategoryName(LLAssetType::EType asset_type) -{ -	const LLAssetDictionary *dict = LLAssetDictionary::getInstance(); -	const AssetEntry *entry = dict->lookup(asset_type); -	if (entry) -	{ -		return entry->mCategoryName; -	} -	else -	{ -		return "New Folder"; -	} -} - -// static -EDragAndDropType LLAssetType::lookupDragAndDropType(EType asset_type) -{ -	const LLAssetDictionary *dict = LLAssetDictionary::getInstance(); -	const AssetEntry *entry = dict->lookup(asset_type); -	if (entry) -		return entry->mDadType; -	else -		return DAD_NONE; -} - -// static  bool LLAssetType::lookupCanLink(EType asset_type)  {  	const LLAssetDictionary *dict = LLAssetDictionary::getInstance(); @@ -269,37 +219,9 @@ bool LLAssetType::lookupIsLinkType(EType asset_type)  }  // static -// Only ensembles and plain folders aren't protected.  "Protected" means -// you can't change certain properties such as their type. -bool LLAssetType::lookupIsProtectedCategoryType(EType asset_type) +const std::string &LLAssetType::badLookup()  { -	const LLAssetDictionary *dict = LLAssetDictionary::getInstance(); -	const AssetEntry *entry = dict->lookup(asset_type); -	if (entry) -	{ -		return entry->mIsProtected; -	} -	return true; -} +	static const std::string sBadLookup = "llassettype_bad_lookup"; +	return sBadLookup; -// static -bool LLAssetType::lookupIsEnsembleCategoryType(EType asset_type) -{ -	return (asset_type >= AT_FOLDER_ENSEMBLE_START && -			asset_type <= AT_FOLDER_ENSEMBLE_END); -} - - -// static. Generate a good default description -void LLAssetType::generateDescriptionFor(LLAssetType::EType asset_type, -										 std::string& description) -{ -	const S32 BUF_SIZE = 30; -	char time_str[BUF_SIZE];	/* Flawfinder: ignore */ -	time_t now; -	time(&now); -	memset(time_str, '\0', BUF_SIZE); -	strftime(time_str, BUF_SIZE - 1, "%Y-%m-%d %H:%M:%S ", localtime(&now)); -	description.assign(time_str); -	description.append(LLAssetType::lookupHumanReadable(asset_type));  } diff --git a/indra/llcommon/llassettype.h b/indra/llcommon/llassettype.h index 33705cd2b1..ec2290d30e 100644 --- a/indra/llcommon/llassettype.h +++ b/indra/llcommon/llassettype.h @@ -1,205 +1,161 @@ -/** 
 - * @file llassettype.h
 - * @brief Declaration of LLAssetType.
 - *
 - * $LicenseInfo:firstyear=2001&license=viewergpl$
 - * 
 - * Copyright (c) 2001-2009, Linden Research, Inc.
 - * 
 - * Second Life Viewer Source Code
 - * The source code in this file ("Source Code") is provided by Linden Lab
 - * to you under the terms of the GNU General Public License, version 2.0
 - * ("GPL"), unless you have obtained a separate licensing agreement
 - * ("Other License"), formally executed by you and Linden Lab.  Terms of
 - * the GPL can be found in doc/GPL-license.txt in this distribution, or
 - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
 - * 
 - * There are special exceptions to the terms and conditions of the GPL as
 - * it is applied to this Source Code. View the full text of the exception
 - * in the file doc/FLOSS-exception.txt in this software distribution, or
 - * online at
 - * http://secondlifegrid.net/programs/open_source/licensing/flossexception
 - * 
 - * By copying, modifying or distributing this software, you acknowledge
 - * that you have read and understood your obligations described above,
 - * and agree to abide by those obligations.
 - * 
 - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
 - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
 - * COMPLETENESS OR PERFORMANCE.
 - * $/LicenseInfo$
 - */
 -
 -#ifndef LL_LLASSETTYPE_H
 -#define LL_LLASSETTYPE_H
 -
 -#include <string>
 -
 -#include "stdenums.h" 	// for EDragAndDropType
 -
 -class LL_COMMON_API LLAssetType
 -{
 -public:
 -	enum EType
 -	{
 -		AT_TEXTURE = 0,
 -			// Used for painting the faces of geometry.
 -			// Stored in typical j2c stream format.
 -
 -		AT_SOUND = 1, 
 -			// Used to fill the aural spectrum.
 -
 -		AT_CALLINGCARD = 2,
 -		    // Links instant message access to the user on the card.
 -			// : E.G. A card for yourself, for linden support, for
 -			// : the guy you were talking to in the coliseum.
 -
 -		AT_LANDMARK = 3,
 -			// Links to places in the world with location and a screen shot or image saved.
 -			// : E.G. Home, linden headquarters, the coliseum, destinations where 
 -			// : we want to increase traffic.
 -
 -		AT_SCRIPT = 4,
 -			// Valid scripts that can be attached to an object.
 -			// : E.G. Open a door, jump into the air.
 -
 -		AT_CLOTHING = 5,
 -			// A collection of textures and parameters that can be worn by an avatar.
 -
 -		AT_OBJECT = 6,
 -			// Any combination of textures, sounds, and scripts that are
 -			// associated with a fixed piece of geometry.
 -			// : E.G. A hot tub, a house with working door.
 -
 -		AT_NOTECARD = 7,
 -			// Just text.
 -
 -		AT_CATEGORY = 8,
 -			// Holds a collection of inventory items.
 -			// It's treated as an item in the inventory and therefore needs a type.
 -
 -		AT_ROOT_CATEGORY = 9,
 -			// A user's root inventory category.
 -			// We decided to expose it visually, so it seems logical to fold
 -			// it into the asset types.
 -
 -		AT_LSL_TEXT = 10,
 -		AT_LSL_BYTECODE = 11,
 -			// The LSL is the scripting language. 
 -			// We've split it into a text and bytecode representation.
 -		
 -		AT_TEXTURE_TGA = 12,
 -			// Uncompressed TGA texture.
 -
 -		AT_BODYPART = 13,
 -			// A collection of textures and parameters that can be worn by an avatar.
 -
 -		AT_TRASH = 14,
 -			// Only to be used as a marker for a category preferred type. 
 -			// Using this, we can throw things in the trash before completely deleting.
 -
 -		AT_SNAPSHOT_CATEGORY = 15,
 -			// A marker for a folder meant for snapshots. 
 -			// No actual assets will be snapshots, though if there were, you
 -			// could interpret them as textures.
 -
 -		AT_LOST_AND_FOUND = 16,
 -			// Used to stuff lost&found items into.
 -
 -		AT_SOUND_WAV = 17,
 -			// Uncompressed sound.
 -
 -		AT_IMAGE_TGA = 18,
 -			// Uncompressed image, non-square.
 -			// Not appropriate for use as a texture.
 -
 -		AT_IMAGE_JPEG = 19,
 -			// Compressed image, non-square.
 -			// Not appropriate for use as a texture.
 -
 -		AT_ANIMATION = 20,
 -			// Animation.
 -
 -		AT_GESTURE = 21,
 -			// Gesture, sequence of animations, sounds, chat, wait steps.
 -
 -		AT_SIMSTATE = 22,
 -			// Simstate file.
 -
 -		AT_FAVORITE = 23,
 -			// favorite items
 -
 -		AT_LINK = 24,
 -			// Inventory symbolic link
 -
 -		AT_LINK_FOLDER = 25,
 -			// Inventory folder link
 -
 -		AT_FOLDER_ENSEMBLE_START = 26,
 -		AT_FOLDER_ENSEMBLE_END = 45,
 -			// This range is reserved for special clothing folder types.
 -
 -		AT_CURRENT_OUTFIT = 46,
 -			// Current outfit
 -
 -		AT_OUTFIT = 47,
 -			// Predefined outfit ("look")
 -
 -		AT_MY_OUTFITS = 48,
 -			// Folder that holds your outfits.
 -
 -		
 -		AT_COUNT = 49,
 -
 -			// +*********************************************************+
 -			// |  TO ADD AN ELEMENT TO THIS ENUM:                        |
 -			// +*********************************************************+
 -			// | 1. INSERT BEFORE AT_COUNT                               |
 -			// | 2. INCREMENT AT_COUNT BY 1                              |
 -			// | 3. ADD TO LLAssetDictionary in LLAssetType.cpp          |
 -			// | 3. ADD TO DEFAULT_ASSET_FOR_INV in LLInventoryType.cpp  |
 -			// +*********************************************************+
 -
 -		AT_NONE = -1
 -	};
 -
 -	// machine transation between type and strings
 -	static EType 				lookup(const char* name); // safe conversion to std::string, *TODO: deprecate
 -	static EType 				lookup(const std::string& type_name);
 -	static const char*			lookup(EType asset_type);
 -
 -	// translation from a type to a human readable form.
 -	static EType 				lookupHumanReadable(const char* desc_name); // safe conversion to std::string, *TODO: deprecate
 -	static EType 				lookupHumanReadable(const std::string& readable_name);
 -	static const char*			lookupHumanReadable(EType asset_type);
 -
 -	// Generate a good default description. You may want to add a verb
 -	// or agent name after this depending on your application.
 -	static void 				generateDescriptionFor(LLAssetType::EType asset_type,
 -													   std::string& description);
 -
 -	static EType 				getType(const std::string& desc_name);
 -	static const std::string&	getDesc(EType asset_type);
 -	static EDragAndDropType   	lookupDragAndDropType(EType asset_type);
 -
 -	static bool 				lookupCanLink(EType asset_type);
 -	static bool 				lookupIsLinkType(EType asset_type);
 -
 -	static const char*  		lookupCategoryName(EType asset_type);
 -	static bool 				lookupIsProtectedCategoryType(EType asset_type);
 -	static bool 				lookupIsEnsembleCategoryType(EType asset_type);
 -
 -	/* TODO: Change return types from "const char *" to "const std::string &".
 -	This is fairly straightforward, but requires changing some calls to use .c_str().
 -	e.g.:
 -	-	fprintf(fp, "\t\ttype\t%s\n", LLAssetType::lookup(mType));
 -	+	fprintf(fp, "\t\ttype\t%s\n", LLAssetType::lookup(mType).c_str());
 -	*/
 -	
 -private:
 -	// don't instantiate or derive one of these objects
 -	LLAssetType( void ) {}
 -	~LLAssetType( void ) {}
 -};
 -
 -#endif // LL_LLASSETTYPE_H
 +/**  + * @file llassettype.h + * @brief Declaration of LLAssetType. + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + *  + * Copyright (c) 2001-2009, Linden Research, Inc. + *  + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab.  Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + *  + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + *  + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + *  + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLASSETTYPE_H +#define LL_LLASSETTYPE_H + +#include <string> + +#include "stdenums.h" 	// for EDragAndDropType + +class LL_COMMON_API LLAssetType +{ +public: +	enum EType +	{ +		AT_TEXTURE = 0, +			// Used for painting the faces of geometry. +			// Stored in typical j2c stream format. + +		AT_SOUND = 1,  +			// Used to fill the aural spectrum. + +		AT_CALLINGCARD = 2, +		    // Links instant message access to the user on the card. +			// : E.G. A card for yourself, for linden support, for +			// : the guy you were talking to in the coliseum. + +		AT_LANDMARK = 3, +			// Links to places in the world with location and a screen shot or image saved. +			// : E.G. Home, linden headquarters, the coliseum, destinations where  +			// : we want to increase traffic. + +		AT_SCRIPT = 4, +			// Valid scripts that can be attached to an object. +			// : E.G. Open a door, jump into the air. + +		AT_CLOTHING = 5, +			// A collection of textures and parameters that can be worn by an avatar. + +		AT_OBJECT = 6, +			// Any combination of textures, sounds, and scripts that are +			// associated with a fixed piece of geometry. +			// : E.G. A hot tub, a house with working door. + +		AT_NOTECARD = 7, +			// Just text. + +		AT_CATEGORY = 8, +			// Holds a collection of inventory items. +			// It's treated as an item in the inventory and therefore needs a type. + +		AT_ROOT_CATEGORY = 9, +			// A user's root inventory category. +			// We decided to expose it visually, so it seems logical to fold +			// it into the asset types. + +		AT_LSL_TEXT = 10, +		AT_LSL_BYTECODE = 11, +			// The LSL is the scripting language.  +			// We've split it into a text and bytecode representation. +		 +		AT_TEXTURE_TGA = 12, +			// Uncompressed TGA texture. + +		AT_BODYPART = 13, +			// A collection of textures and parameters that can be worn by an avatar. + +		AT_SOUND_WAV = 17, +			// Uncompressed sound. + +		AT_IMAGE_TGA = 18, +			// Uncompressed image, non-square. +			// Not appropriate for use as a texture. + +		AT_IMAGE_JPEG = 19, +			// Compressed image, non-square. +			// Not appropriate for use as a texture. + +		AT_ANIMATION = 20, +			// Animation. + +		AT_GESTURE = 21, +			// Gesture, sequence of animations, sounds, chat, wait steps. + +		AT_SIMSTATE = 22, +			// Simstate file. + +		AT_LINK = 24, +			// Inventory symbolic link + +		AT_LINK_FOLDER = 25, +			// Inventory folder link +		 +		AT_COUNT = 26, + +			// +*********************************************************+ +			// |  TO ADD AN ELEMENT TO THIS ENUM:                        | +			// +*********************************************************+ +			// | 1. INSERT BEFORE AT_COUNT                               | +			// | 2. INCREMENT AT_COUNT BY 1                              | +			// | 3. ADD TO LLAssetType.cpp                               | +			// | 4. ADD TO LLViewerAssetType.cpp                         | +			// | 5. ADD TO DEFAULT_ASSET_FOR_INV in LLInventoryType.cpp  | +			// +*********************************************************+ + +		AT_NONE = -1 +	}; + +	// machine transation between type and strings +	static EType 				lookup(const char* name); // safe conversion to std::string, *TODO: deprecate +	static EType 				lookup(const std::string& type_name); +	static const char*			lookup(EType asset_type); + +	// translation from a type to a human readable form. +	static EType 				lookupHumanReadable(const char* desc_name); // safe conversion to std::string, *TODO: deprecate +	static EType 				lookupHumanReadable(const std::string& readable_name); +	static const char*			lookupHumanReadable(EType asset_type); + +	static EType 				getType(const std::string& desc_name); +	static const std::string&	getDesc(EType asset_type); + +	static bool 				lookupCanLink(EType asset_type); +	static bool 				lookupIsLinkType(EType asset_type); + +	static const std::string&	badLookup(); // error string when a lookup fails + +protected: +	LLAssetType() {} +	~LLAssetType() {} +}; + +#endif // LL_LLASSETTYPE_H diff --git a/indra/llcommon/llcoros.h b/indra/llcommon/llcoros.h index 6c5fa5af6d..141b0df43c 100644 --- a/indra/llcommon/llcoros.h +++ b/indra/llcommon/llcoros.h @@ -1,149 +1,149 @@ -/**
 - * @file   llcoros.h
 - * @author Nat Goodspeed
 - * @date   2009-06-02
 - * @brief  Manage running boost::coroutine instances
 - * 
 - * $LicenseInfo:firstyear=2009&license=viewergpl$
 - * Copyright (c) 2009, Linden Research, Inc.
 - * $/LicenseInfo$
 - */
 -
 -#if ! defined(LL_LLCOROS_H)
 -#define LL_LLCOROS_H
 -
 -#include <boost/coroutine/coroutine.hpp>
 -#include "llsingleton.h"
 -#include <boost/ptr_container/ptr_map.hpp>
 -#include <string>
 -#include <boost/preprocessor/repetition/enum_params.hpp>
 -#include <boost/preprocessor/repetition/enum_binary_params.hpp>
 -#include <boost/preprocessor/iteration/local.hpp>
 -#include <stdexcept>
 -
 -/**
 - * Registry of named Boost.Coroutine instances
 - *
 - * The Boost.Coroutine library supports the general case of a coroutine
 - * accepting arbitrary parameters and yielding multiple (sets of) results. For
 - * such use cases, it's natural for the invoking code to retain the coroutine
 - * instance: the consumer repeatedly calls into the coroutine, perhaps passing
 - * new parameter values, prompting it to yield its next result.
 - *
 - * Our typical coroutine usage is different, though. For us, coroutines
 - * provide an alternative to the @c Responder pattern. Our typical coroutine
 - * has @c void return, invoked in fire-and-forget mode: the handler for some
 - * user gesture launches the coroutine and promptly returns to the main loop.
 - * The coroutine initiates some action that will take multiple frames (e.g. a
 - * capability request), waits for its result, processes it and silently steals
 - * away.
 - *
 - * This usage poses two (related) problems:
 - *
 - * # Who should own the coroutine instance? If it's simply local to the
 - *   handler code that launches it, return from the handler will destroy the
 - *   coroutine object, terminating the coroutine.
 - * # Once the coroutine terminates, in whatever way, who's responsible for
 - *   cleaning up the coroutine object?
 - *
 - * LLCoros is a Singleton collection of currently-active coroutine instances.
 - * Each has a name. You ask LLCoros to launch a new coroutine with a suggested
 - * name prefix; from your prefix it generates a distinct name, registers the
 - * new coroutine and returns the actual name.
 - *
 - * The name can be used to kill off the coroutine prematurely, if needed. It
 - * can also provide diagnostic info: we can look up the name of the
 - * currently-running coroutine.
 - *
 - * Finally, the next frame ("mainloop" event) after the coroutine terminates,
 - * LLCoros will notice its demise and destroy it.
 - */
 -class LL_COMMON_API LLCoros: public LLSingleton<LLCoros>
 -{
 -public:
 -    /// Canonical boost::coroutines::coroutine signature we use
 -    typedef boost::coroutines::coroutine<void()> coro;
 -    /// Canonical 'self' type
 -    typedef coro::self self;
 -
 -    /**
 -     * Create and start running a new coroutine with specified name. The name
 -     * string you pass is a suggestion; it will be tweaked for uniqueness. The
 -     * actual name is returned to you.
 -     *
 -     * Usage looks like this, for (e.g.) two coroutine parameters:
 -     * @code
 -     * class MyClass
 -     * {
 -     * public:
 -     *     ...
 -     *     // Do NOT NOT NOT accept reference params other than 'self'!
 -     *     // Pass by value only!
 -     *     void myCoroutineMethod(LLCoros::self& self, std::string, LLSD);
 -     *     ...
 -     * };
 -     * ...
 -     * std::string name = LLCoros::instance().launch(
 -     *    "mycoro", boost::bind(&MyClass::myCoroutineMethod, this, _1,
 -     *                          "somestring", LLSD(17));
 -     * @endcode
 -     *
 -     * Your function/method must accept LLCoros::self& as its first parameter.
 -     * It can accept any other parameters you want -- but ONLY BY VALUE!
 -     * Other reference parameters are a BAD IDEA! You Have Been Warned. See
 -     * DEV-32777 comments for an explanation.
 -     *
 -     * Pass a callable that accepts the single LLCoros::self& parameter. It
 -     * may work to pass a free function whose only parameter is 'self'; for
 -     * all other cases use boost::bind(). Of course, for a non-static class
 -     * method, the first parameter must be the class instance. Use the
 -     * placeholder _1 for the 'self' parameter. Any other parameters should be
 -     * passed via the bind() expression.
 -     *
 -     * launch() tweaks the suggested name so it won't collide with any
 -     * existing coroutine instance, creates the coroutine instance, registers
 -     * it with the tweaked name and runs it until its first wait. At that
 -     * point it returns the tweaked name.
 -     */
 -    template <typename CALLABLE>
 -    std::string launch(const std::string& prefix, const CALLABLE& callable)
 -    {
 -        return launchImpl(prefix, new coro(callable));
 -    }
 -
 -    /**
 -     * Abort a running coroutine by name. Normally, when a coroutine either
 -     * runs to completion or terminates with an exception, LLCoros quietly
 -     * cleans it up. This is for use only when you must explicitly interrupt
 -     * one prematurely. Returns @c true if the specified name was found and
 -     * still running at the time.
 -     */
 -    bool kill(const std::string& name);
 -
 -    /**
 -     * From within a coroutine, pass its @c self object to look up the
 -     * (tweaked) name string by which this coroutine is registered. Returns
 -     * the empty string if not found (e.g. if the coroutine was launched by
 -     * hand rather than using LLCoros::launch()).
 -     */
 -    template <typename COROUTINE_SELF>
 -    std::string getName(const COROUTINE_SELF& self) const
 -    {
 -        return getNameByID(self.get_id());
 -    }
 -
 -    /// getName() by self.get_id()
 -    std::string getNameByID(const void* self_id) const;
 -
 -private:
 -    friend class LLSingleton<LLCoros>;
 -    LLCoros();
 -    std::string launchImpl(const std::string& prefix, coro* newCoro);
 -    std::string generateDistinctName(const std::string& prefix) const;
 -    bool cleanup(const LLSD&);
 -
 -    typedef boost::ptr_map<std::string, coro> CoroMap;
 -    CoroMap mCoros;
 -};
 -
 -#endif /* ! defined(LL_LLCOROS_H) */
 +/** + * @file   llcoros.h + * @author Nat Goodspeed + * @date   2009-06-02 + * @brief  Manage running boost::coroutine instances + *  + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * Copyright (c) 2009, Linden Research, Inc. + * $/LicenseInfo$ + */ + +#if ! defined(LL_LLCOROS_H) +#define LL_LLCOROS_H + +#include <boost/coroutine/coroutine.hpp> +#include "llsingleton.h" +#include <boost/ptr_container/ptr_map.hpp> +#include <string> +#include <boost/preprocessor/repetition/enum_params.hpp> +#include <boost/preprocessor/repetition/enum_binary_params.hpp> +#include <boost/preprocessor/iteration/local.hpp> +#include <stdexcept> + +/** + * Registry of named Boost.Coroutine instances + * + * The Boost.Coroutine library supports the general case of a coroutine + * accepting arbitrary parameters and yielding multiple (sets of) results. For + * such use cases, it's natural for the invoking code to retain the coroutine + * instance: the consumer repeatedly calls into the coroutine, perhaps passing + * new parameter values, prompting it to yield its next result. + * + * Our typical coroutine usage is different, though. For us, coroutines + * provide an alternative to the @c Responder pattern. Our typical coroutine + * has @c void return, invoked in fire-and-forget mode: the handler for some + * user gesture launches the coroutine and promptly returns to the main loop. + * The coroutine initiates some action that will take multiple frames (e.g. a + * capability request), waits for its result, processes it and silently steals + * away. + * + * This usage poses two (related) problems: + * + * # Who should own the coroutine instance? If it's simply local to the + *   handler code that launches it, return from the handler will destroy the + *   coroutine object, terminating the coroutine. + * # Once the coroutine terminates, in whatever way, who's responsible for + *   cleaning up the coroutine object? + * + * LLCoros is a Singleton collection of currently-active coroutine instances. + * Each has a name. You ask LLCoros to launch a new coroutine with a suggested + * name prefix; from your prefix it generates a distinct name, registers the + * new coroutine and returns the actual name. + * + * The name can be used to kill off the coroutine prematurely, if needed. It + * can also provide diagnostic info: we can look up the name of the + * currently-running coroutine. + * + * Finally, the next frame ("mainloop" event) after the coroutine terminates, + * LLCoros will notice its demise and destroy it. + */ +class LL_COMMON_API LLCoros: public LLSingleton<LLCoros> +{ +public: +    /// Canonical boost::coroutines::coroutine signature we use +    typedef boost::coroutines::coroutine<void()> coro; +    /// Canonical 'self' type +    typedef coro::self self; + +    /** +     * Create and start running a new coroutine with specified name. The name +     * string you pass is a suggestion; it will be tweaked for uniqueness. The +     * actual name is returned to you. +     * +     * Usage looks like this, for (e.g.) two coroutine parameters: +     * @code +     * class MyClass +     * { +     * public: +     *     ... +     *     // Do NOT NOT NOT accept reference params other than 'self'! +     *     // Pass by value only! +     *     void myCoroutineMethod(LLCoros::self& self, std::string, LLSD); +     *     ... +     * }; +     * ... +     * std::string name = LLCoros::instance().launch( +     *    "mycoro", boost::bind(&MyClass::myCoroutineMethod, this, _1, +     *                          "somestring", LLSD(17)); +     * @endcode +     * +     * Your function/method must accept LLCoros::self& as its first parameter. +     * It can accept any other parameters you want -- but ONLY BY VALUE! +     * Other reference parameters are a BAD IDEA! You Have Been Warned. See +     * DEV-32777 comments for an explanation. +     * +     * Pass a callable that accepts the single LLCoros::self& parameter. It +     * may work to pass a free function whose only parameter is 'self'; for +     * all other cases use boost::bind(). Of course, for a non-static class +     * method, the first parameter must be the class instance. Use the +     * placeholder _1 for the 'self' parameter. Any other parameters should be +     * passed via the bind() expression. +     * +     * launch() tweaks the suggested name so it won't collide with any +     * existing coroutine instance, creates the coroutine instance, registers +     * it with the tweaked name and runs it until its first wait. At that +     * point it returns the tweaked name. +     */ +    template <typename CALLABLE> +    std::string launch(const std::string& prefix, const CALLABLE& callable) +    { +        return launchImpl(prefix, new coro(callable)); +    } + +    /** +     * Abort a running coroutine by name. Normally, when a coroutine either +     * runs to completion or terminates with an exception, LLCoros quietly +     * cleans it up. This is for use only when you must explicitly interrupt +     * one prematurely. Returns @c true if the specified name was found and +     * still running at the time. +     */ +    bool kill(const std::string& name); + +    /** +     * From within a coroutine, pass its @c self object to look up the +     * (tweaked) name string by which this coroutine is registered. Returns +     * the empty string if not found (e.g. if the coroutine was launched by +     * hand rather than using LLCoros::launch()). +     */ +    template <typename COROUTINE_SELF> +    std::string getName(const COROUTINE_SELF& self) const +    { +        return getNameByID(self.get_id()); +    } + +    /// getName() by self.get_id() +    std::string getNameByID(const void* self_id) const; + +private: +    friend class LLSingleton<LLCoros>; +    LLCoros(); +    std::string launchImpl(const std::string& prefix, coro* newCoro); +    std::string generateDistinctName(const std::string& prefix) const; +    bool cleanup(const LLSD&); + +    typedef boost::ptr_map<std::string, coro> CoroMap; +    CoroMap mCoros; +}; + +#endif /* ! defined(LL_LLCOROS_H) */ diff --git a/indra/llcommon/lleventdispatcher.h b/indra/llcommon/lleventdispatcher.h index 671f2a4d1c..5a86b90bff 100644 --- a/indra/llcommon/lleventdispatcher.h +++ b/indra/llcommon/lleventdispatcher.h @@ -1,130 +1,130 @@ -/**
 - * @file   lleventdispatcher.h
 - * @author Nat Goodspeed
 - * @date   2009-06-18
 - * @brief  Central mechanism for dispatching events by string name. This is
 - *         useful when you have a single LLEventPump listener on which you can
 - *         request different operations, vs. instantiating a different
 - *         LLEventPump for each such operation.
 - * 
 - * $LicenseInfo:firstyear=2009&license=viewergpl$
 - * Copyright (c) 2009, Linden Research, Inc.
 - * $/LicenseInfo$
 - */
 -
 -#if ! defined(LL_LLEVENTDISPATCHER_H)
 -#define LL_LLEVENTDISPATCHER_H
 -
 -#include <string>
 -#include <map>
 -#include <boost/function.hpp>
 -#include <boost/bind.hpp>
 -#include <typeinfo>
 -#include "llevents.h"
 -
 -class LLSD;
 -
 -/**
 - * Given an LLSD map, examine a string-valued key and call a corresponding
 - * callable. This class is designed to be contained by an LLEventPump
 - * listener class that will register some of its own methods, though any
 - * callable can be used.
 - */
 -class LL_COMMON_API LLEventDispatcher
 -{
 -public:
 -    LLEventDispatcher(const std::string& desc, const std::string& key);
 -    virtual ~LLEventDispatcher();
 -
 -    /// Accept any C++ callable, typically a boost::bind() expression
 -    typedef boost::function<void(const LLSD&)> Callable;
 -
 -    /**
 -     * Register a @a callable by @a name. The optional @a required parameter
 -     * is used to validate the structure of each incoming event (see
 -     * llsd_matches()).
 -     */
 -    void add(const std::string& name, const Callable& callable, const LLSD& required=LLSD());
 -
 -    /**
 -     * Special case: a subclass of this class can pass an unbound member
 -     * function pointer without explicitly specifying the
 -     * <tt>boost::bind()</tt> expression.
 -     */
 -    template <class CLASS>
 -    void add(const std::string& name, void (CLASS::*method)(const LLSD&),
 -             const LLSD& required=LLSD())
 -    {
 -        addMethod<CLASS>(name, method, required);
 -    }
 -
 -    /// Overload for both const and non-const methods
 -    template <class CLASS>
 -    void add(const std::string& name, void (CLASS::*method)(const LLSD&) const,
 -             const LLSD& required=LLSD())
 -    {
 -        addMethod<CLASS>(name, method, required);
 -    }
 -
 -    /// Unregister a callable
 -    bool remove(const std::string& name);
 -
 -    /// Call a registered callable with an explicitly-specified name. If no
 -    /// such callable exists, die with LL_ERRS. If the @a event fails to match
 -    /// the @a required prototype specified at add() time, die with LL_ERRS.
 -    void operator()(const std::string& name, const LLSD& event) const;
 -
 -    /// Extract the @a key value from the incoming @a event, and call the
 -    /// callable whose name is specified by that map @a key. If no such
 -    /// callable exists, die with LL_ERRS. If the @a event fails to match the
 -    /// @a required prototype specified at add() time, die with LL_ERRS.
 -    void operator()(const LLSD& event) const;
 -
 -    /// Fetch the Callable for the specified name. If no such name was
 -    /// registered, return an empty() Callable.
 -    Callable get(const std::string& name) const;
 -
 -private:
 -    template <class CLASS, typename METHOD>
 -    void addMethod(const std::string& name, const METHOD& method, const LLSD& required)
 -    {
 -        CLASS* downcast = dynamic_cast<CLASS*>(this);
 -        if (! downcast)
 -        {
 -            addFail(name, typeid(CLASS).name());
 -        }
 -        else
 -        {
 -            add(name, boost::bind(method, downcast, _1), required);
 -        }
 -    }
 -    void addFail(const std::string& name, const std::string& classname) const;
 -    /// try to dispatch, return @c true if success
 -    bool attemptCall(const std::string& name, const LLSD& event) const;
 -
 -    std::string mDesc, mKey;
 -    typedef std::map<std::string, std::pair<Callable, LLSD> > DispatchMap;
 -    DispatchMap mDispatch;
 -};
 -
 -/**
 - * Bundle an LLEventPump and a listener with an LLEventDispatcher. A class
 - * that contains (or derives from) LLDispatchListener need only specify the
 - * LLEventPump name and dispatch key, and add() its methods. Incoming events
 - * will automatically be dispatched.
 - */
 -class LL_COMMON_API LLDispatchListener: public LLEventDispatcher
 -{
 -public:
 -    LLDispatchListener(const std::string& pumpname, const std::string& key);
 -
 -    std::string getPumpName() const { return mPump.getName(); }
 -
 -private:
 -    bool process(const LLSD& event);
 -
 -    LLEventStream mPump;
 -    LLTempBoundListener mBoundListener;
 -};
 -
 -#endif /* ! defined(LL_LLEVENTDISPATCHER_H) */
 +/** + * @file   lleventdispatcher.h + * @author Nat Goodspeed + * @date   2009-06-18 + * @brief  Central mechanism for dispatching events by string name. This is + *         useful when you have a single LLEventPump listener on which you can + *         request different operations, vs. instantiating a different + *         LLEventPump for each such operation. + *  + * $LicenseInfo:firstyear=2009&license=viewergpl$ + * Copyright (c) 2009, Linden Research, Inc. + * $/LicenseInfo$ + */ + +#if ! defined(LL_LLEVENTDISPATCHER_H) +#define LL_LLEVENTDISPATCHER_H + +#include <string> +#include <map> +#include <boost/function.hpp> +#include <boost/bind.hpp> +#include <typeinfo> +#include "llevents.h" + +class LLSD; + +/** + * Given an LLSD map, examine a string-valued key and call a corresponding + * callable. This class is designed to be contained by an LLEventPump + * listener class that will register some of its own methods, though any + * callable can be used. + */ +class LL_COMMON_API LLEventDispatcher +{ +public: +    LLEventDispatcher(const std::string& desc, const std::string& key); +    virtual ~LLEventDispatcher(); + +    /// Accept any C++ callable, typically a boost::bind() expression +    typedef boost::function<void(const LLSD&)> Callable; + +    /** +     * Register a @a callable by @a name. The optional @a required parameter +     * is used to validate the structure of each incoming event (see +     * llsd_matches()). +     */ +    void add(const std::string& name, const Callable& callable, const LLSD& required=LLSD()); + +    /** +     * Special case: a subclass of this class can pass an unbound member +     * function pointer without explicitly specifying the +     * <tt>boost::bind()</tt> expression. +     */ +    template <class CLASS> +    void add(const std::string& name, void (CLASS::*method)(const LLSD&), +             const LLSD& required=LLSD()) +    { +        addMethod<CLASS>(name, method, required); +    } + +    /// Overload for both const and non-const methods +    template <class CLASS> +    void add(const std::string& name, void (CLASS::*method)(const LLSD&) const, +             const LLSD& required=LLSD()) +    { +        addMethod<CLASS>(name, method, required); +    } + +    /// Unregister a callable +    bool remove(const std::string& name); + +    /// Call a registered callable with an explicitly-specified name. If no +    /// such callable exists, die with LL_ERRS. If the @a event fails to match +    /// the @a required prototype specified at add() time, die with LL_ERRS. +    void operator()(const std::string& name, const LLSD& event) const; + +    /// Extract the @a key value from the incoming @a event, and call the +    /// callable whose name is specified by that map @a key. If no such +    /// callable exists, die with LL_ERRS. If the @a event fails to match the +    /// @a required prototype specified at add() time, die with LL_ERRS. +    void operator()(const LLSD& event) const; + +    /// Fetch the Callable for the specified name. If no such name was +    /// registered, return an empty() Callable. +    Callable get(const std::string& name) const; + +private: +    template <class CLASS, typename METHOD> +    void addMethod(const std::string& name, const METHOD& method, const LLSD& required) +    { +        CLASS* downcast = dynamic_cast<CLASS*>(this); +        if (! downcast) +        { +            addFail(name, typeid(CLASS).name()); +        } +        else +        { +            add(name, boost::bind(method, downcast, _1), required); +        } +    } +    void addFail(const std::string& name, const std::string& classname) const; +    /// try to dispatch, return @c true if success +    bool attemptCall(const std::string& name, const LLSD& event) const; + +    std::string mDesc, mKey; +    typedef std::map<std::string, std::pair<Callable, LLSD> > DispatchMap; +    DispatchMap mDispatch; +}; + +/** + * Bundle an LLEventPump and a listener with an LLEventDispatcher. A class + * that contains (or derives from) LLDispatchListener need only specify the + * LLEventPump name and dispatch key, and add() its methods. Incoming events + * will automatically be dispatched. + */ +class LL_COMMON_API LLDispatchListener: public LLEventDispatcher +{ +public: +    LLDispatchListener(const std::string& pumpname, const std::string& key); + +    std::string getPumpName() const { return mPump.getName(); } + +private: +    bool process(const LLSD& event); + +    LLEventStream mPump; +    LLTempBoundListener mBoundListener; +}; + +#endif /* ! defined(LL_LLEVENTDISPATCHER_H) */ diff --git a/indra/llcommon/llevents.h b/indra/llcommon/llevents.h index 64e5cb5da7..192d79b27d 100644 --- a/indra/llcommon/llevents.h +++ b/indra/llcommon/llevents.h @@ -1,943 +1,943 @@ -/**
 - * @file   llevents.h
 - * @author Kent Quirk, Nat Goodspeed
 - * @date   2008-09-11
 - * @brief  This is an implementation of the event system described at
 - *         https://wiki.lindenlab.com/wiki/Viewer:Messaging/Event_System,
 - *         originally introduced in llnotifications.h. It has nothing
 - *         whatsoever to do with the older system in llevent.h.
 - * 
 - * $LicenseInfo:firstyear=2008&license=viewergpl$
 - * Copyright (c) 2008, Linden Research, Inc.
 - * $/LicenseInfo$
 - */
 -
 -#if ! defined(LL_LLEVENTS_H)
 -#define LL_LLEVENTS_H
 -
 -#include <string>
 -#include <map>
 -#include <set>
 -#include <vector>
 -#include <deque>
 -#include <stdexcept>
 -#if LL_WINDOWS
 -	#pragma warning (push)
 -	#pragma warning (disable : 4263) // boost::signals2::expired_slot::what() has const mismatch
 -	#pragma warning (disable : 4264) 
 -#endif
 -#include <boost/signals2.hpp>
 -#if LL_WINDOWS
 -	#pragma warning (pop)
 -#endif
 -
 -#include <boost/bind.hpp>
 -#include <boost/shared_ptr.hpp>
 -#include <boost/enable_shared_from_this.hpp>
 -#include <boost/utility.hpp>        // noncopyable
 -#include <boost/optional/optional.hpp>
 -#include <boost/visit_each.hpp>
 -#include <boost/ref.hpp>            // reference_wrapper
 -#include <boost/type_traits/is_pointer.hpp>
 -#include <boost/function.hpp>
 -#include <boost/static_assert.hpp>
 -#include "llsd.h"
 -#include "llsingleton.h"
 -#include "lldependencies.h"
 -
 -// override this to allow binding free functions with more parameters
 -#ifndef LLEVENTS_LISTENER_ARITY
 -#define LLEVENTS_LISTENER_ARITY 10
 -#endif
 -
 -// hack for testing
 -#ifndef testable
 -#define testable private
 -#endif
 -
 -/*****************************************************************************
 -*   Signal and handler declarations
 -*   Using a single handler signature means that we can have a common handler
 -*   type, rather than needing a distinct one for each different handler.
 -*****************************************************************************/
 -
 -/**
 - * A boost::signals Combiner that stops the first time a handler returns true
 - * We need this because we want to have our handlers return bool, so that
 - * we have the option to cause a handler to stop further processing. The
 - * default handler fails when the signal returns a value but has no slots.
 - */
 -struct LLStopWhenHandled
 -{
 -    typedef bool result_type;
 -
 -    template<typename InputIterator>
 -    result_type operator()(InputIterator first, InputIterator last) const
 -    {
 -        for (InputIterator si = first; si != last; ++si)
 -		{
 -            if (*si)
 -			{
 -                return true;
 -			}
 -		}
 -        return false;
 -    }
 -};
 -
 -/**
 - * We want to have a standard signature for all signals; this way,
 - * we can easily document a protocol for communicating across
 - * dlls and into scripting languages someday.
 - *
 - * We want to return a bool to indicate whether the signal has been
 - * handled and should NOT be passed on to other listeners.
 - * Return true to stop further handling of the signal, and false
 - * to continue.
 - *
 - * We take an LLSD because this way the contents of the signal
 - * are independent of the API used to communicate it.
 - * It is const ref because then there's low cost to pass it;
 - * if you only need to inspect it, it's very cheap.
 - *
 - * @internal
 - * The @c float template parameter indicates that we will internally use @c
 - * float to indicate relative listener order on a given LLStandardSignal.
 - * Don't worry, the @c float values are strictly internal! They are not part
 - * of the interface, for the excellent reason that requiring the caller to
 - * specify a numeric key to establish order means that the caller must know
 - * the universe of possible values. We use LLDependencies for that instead.
 - */
 -typedef boost::signals2::signal<bool(const LLSD&), LLStopWhenHandled, float>  LLStandardSignal;
 -/// Methods that forward listeners (e.g. constructed with
 -/// <tt>boost::bind()</tt>) should accept (const LLEventListener&)
 -typedef LLStandardSignal::slot_type LLEventListener;
 -/// Result of registering a listener, supports <tt>connected()</tt>,
 -/// <tt>disconnect()</tt> and <tt>blocked()</tt>
 -typedef boost::signals2::connection LLBoundListener;
 -/// Storing an LLBoundListener in LLTempBoundListener will disconnect the
 -/// referenced listener when the LLTempBoundListener instance is destroyed.
 -typedef boost::signals2::scoped_connection LLTempBoundListener;
 -
 -/**
 - * A common idiom for event-based code is to accept either a callable --
 - * directly called on completion -- or the string name of an LLEventPump on
 - * which to post the completion event. Specifying a parameter as <tt>const
 - * LLListenerOrPumpName&</tt> allows either.
 - *
 - * Calling a validly-constructed LLListenerOrPumpName, passing the LLSD
 - * 'event' object, either calls the callable or posts the event to the named
 - * LLEventPump.
 - *
 - * A default-constructed LLListenerOrPumpName is 'empty'. (This is useful as
 - * the default value of an optional method parameter.) Calling it throws
 - * LLListenerOrPumpName::Empty. Test for this condition beforehand using
 - * either <tt>if (param)</tt> or <tt>if (! param)</tt>.
 - */
 -class LL_COMMON_API LLListenerOrPumpName
 -{
 -public:
 -    /// passing string name of LLEventPump
 -    LLListenerOrPumpName(const std::string& pumpname);
 -    /// passing string literal (overload so compiler isn't forced to infer
 -    /// double conversion)
 -    LLListenerOrPumpName(const char* pumpname);
 -    /// passing listener -- the "anything else" catch-all case. The type of an
 -    /// object constructed by boost::bind() isn't intended to be written out.
 -    /// Normally we'd just accept 'const LLEventListener&', but that would
 -    /// require double implicit conversion: boost::bind() object to
 -    /// LLEventListener, LLEventListener to LLListenerOrPumpName. So use a
 -    /// template to forward anything.
 -    template<typename T>
 -    LLListenerOrPumpName(const T& listener): mListener(listener) {}
 -
 -    /// for omitted method parameter: uninitialized mListener
 -    LLListenerOrPumpName() {}
 -
 -    /// test for validity
 -    operator bool() const { return bool(mListener); }
 -    bool operator! () const { return ! mListener; }
 -
 -    /// explicit accessor
 -    const LLEventListener& getListener() const { return *mListener; }
 -
 -    /// implicit conversion to LLEventListener
 -    operator LLEventListener() const { return *mListener; }
 -
 -    /// allow calling directly
 -    bool operator()(const LLSD& event) const;
 -
 -    /// exception if you try to call when empty
 -    struct Empty: public std::runtime_error
 -    {
 -        Empty(const std::string& what):
 -            std::runtime_error(std::string("LLListenerOrPumpName::Empty: ") + what) {}
 -    };
 -
 -private:
 -    boost::optional<LLEventListener> mListener;
 -};
 -
 -/*****************************************************************************
 -*   LLEventPumps
 -*****************************************************************************/
 -class LLEventPump;
 -
 -/**
 - * LLEventPumps is a Singleton manager through which one typically accesses
 - * this subsystem.
 - */
 -class LL_COMMON_API LLEventPumps: public LLSingleton<LLEventPumps>
 -{
 -    friend class LLSingleton<LLEventPumps>;
 -public:
 -    /**
 -     * Find or create an LLEventPump instance with a specific name. We return
 -     * a reference so there's no question about ownership. obtain() @em finds
 -     * an instance without conferring @em ownership.
 -     */
 -    LLEventPump& obtain(const std::string& name);
 -    /**
 -     * Flush all known LLEventPump instances
 -     */
 -    void flush();
 -
 -    /**
 -     * Reset all known LLEventPump instances
 -     * workaround for DEV-35406 crash on shutdown
 -     */
 -    void reset();
 -
 -private:
 -    friend class LLEventPump;
 -    /**
 -     * Register a new LLEventPump instance (internal)
 -     */
 -    std::string registerNew(const LLEventPump&, const std::string& name, bool tweak);
 -    /**
 -     * Unregister a doomed LLEventPump instance (internal)
 -     */
 -    void unregister(const LLEventPump&);
 -
 -private:
 -    LLEventPumps();
 -    ~LLEventPumps();
 -
 -testable:
 -    // Map of all known LLEventPump instances, whether or not we instantiated
 -    // them. We store a plain old LLEventPump* because this map doesn't claim
 -    // ownership of the instances. Though the common usage pattern is to
 -    // request an instance using obtain(), it's fair to instantiate an
 -    // LLEventPump subclass statically, as a class member, on the stack or on
 -    // the heap. In such cases, the instantiating party is responsible for its
 -    // lifespan.
 -    typedef std::map<std::string, LLEventPump*> PumpMap;
 -    PumpMap mPumpMap;
 -    // Set of all LLEventPumps we instantiated. Membership in this set means
 -    // we claim ownership, and will delete them when this LLEventPumps is
 -    // destroyed.
 -    typedef std::set<LLEventPump*> PumpSet;
 -    PumpSet mOurPumps;
 -    // LLEventPump names that should be instantiated as LLEventQueue rather
 -    // than as LLEventStream
 -    typedef std::set<std::string> PumpNames;
 -    PumpNames mQueueNames;
 -};
 -
 -/*****************************************************************************
 -*   details
 -*****************************************************************************/
 -namespace LLEventDetail
 -{
 -    /// Any callable capable of connecting an LLEventListener to an
 -    /// LLStandardSignal to produce an LLBoundListener can be mapped to this
 -    /// signature.
 -    typedef boost::function<LLBoundListener(const LLEventListener&)> ConnectFunc;
 -
 -    /**
 -     * Utility template function to use Visitor appropriately
 -     *
 -     * @param listener Callable to connect, typically a boost::bind()
 -     * expression. This will be visited by Visitor using boost::visit_each().
 -     * @param connect_func Callable that will connect() @a listener to an
 -     * LLStandardSignal, returning LLBoundListener.
 -     */
 -    template <typename LISTENER>
 -    LLBoundListener visit_and_connect(const LISTENER& listener,
 -                                      const ConnectFunc& connect_func);
 -} // namespace LLEventDetail
 -
 -/*****************************************************************************
 -*   LLEventTrackable
 -*****************************************************************************/
 -/**
 - * LLEventTrackable wraps boost::signals2::trackable, which resembles
 - * boost::trackable. Derive your listener class from LLEventTrackable instead,
 - * and use something like
 - * <tt>LLEventPump::listen(boost::bind(&YourTrackableSubclass::method,
 - * instance, _1))</tt>. This will implicitly disconnect when the object
 - * referenced by @c instance is destroyed.
 - *
 - * @note
 - * LLEventTrackable doesn't address a couple of cases:
 - * * Object destroyed during call
 - *   - You enter a slot call in thread A.
 - *   - Thread B destroys the object, which of course disconnects it from any
 - *     future slot calls.
 - *   - Thread A's call uses 'this', which now refers to a defunct object.
 - *     Undefined behavior results.
 - * * Call during destruction
 - *   - @c MySubclass is derived from LLEventTrackable.
 - *   - @c MySubclass registers one of its own methods using
 - *     <tt>LLEventPump::listen()</tt>.
 - *   - The @c MySubclass object begins destruction. <tt>~MySubclass()</tt>
 - *     runs, destroying state specific to the subclass. (For instance, a
 - *     <tt>Foo*</tt> data member is <tt>delete</tt>d but not zeroed.)
 - *   - The listening method will not be disconnected until
 - *     <tt>~LLEventTrackable()</tt> runs.
 - *   - Before we get there, another thread posts data to the @c LLEventPump
 - *     instance, calling the @c MySubclass method.
 - *   - The method in question relies on valid @c MySubclass state. (For
 - *     instance, it attempts to dereference the <tt>Foo*</tt> pointer that was
 - *     <tt>delete</tt>d but not zeroed.)
 - *   - Undefined behavior results.
 - * If you suspect you may encounter any such scenario, you're better off
 - * managing the lifespan of your object with <tt>boost::shared_ptr</tt>.
 - * Passing <tt>LLEventPump::listen()</tt> a <tt>boost::bind()</tt> expression
 - * involving a <tt>boost::weak_ptr<Foo></tt> is recognized specially, engaging
 - * thread-safe Boost.Signals2 machinery.
 - */
 -typedef boost::signals2::trackable LLEventTrackable;
 -
 -/*****************************************************************************
 -*   LLEventPump
 -*****************************************************************************/
 -/**
 - * LLEventPump is the base class interface through which we access the
 - * concrete subclasses LLEventStream and LLEventQueue.
 - *
 - * @NOTE
 - * LLEventPump derives from LLEventTrackable so that when you "chain"
 - * LLEventPump instances together, they will automatically disconnect on
 - * destruction. Please see LLEventTrackable documentation for situations in
 - * which this may be perilous across threads.
 - */
 -class LL_COMMON_API LLEventPump: public LLEventTrackable
 -{
 -public:
 -    /**
 -     * Exception thrown by LLEventPump(). You are trying to instantiate an
 -     * LLEventPump (subclass) using the same name as some other instance, and
 -     * you didn't pass <tt>tweak=true</tt> to permit it to generate a unique
 -     * variant.
 -     */
 -    struct DupPumpName: public std::runtime_error
 -    {
 -        DupPumpName(const std::string& what):
 -            std::runtime_error(std::string("DupPumpName: ") + what) {}
 -    };
 -
 -    /**
 -     * Instantiate an LLEventPump (subclass) with the string name by which it
 -     * can be found using LLEventPumps::obtain().
 -     *
 -     * If you pass (or default) @a tweak to @c false, then a duplicate name
 -     * will throw DupPumpName. This won't happen if LLEventPumps::obtain()
 -     * instantiates the LLEventPump, because obtain() uses find-or-create
 -     * logic. It can only happen if you instantiate an LLEventPump in your own
 -     * code -- and a collision with the name of some other LLEventPump is
 -     * likely to cause much more subtle problems!
 -     *
 -     * When you hand-instantiate an LLEventPump, consider passing @a tweak as
 -     * @c true. This directs LLEventPump() to append a suffix to the passed @a
 -     * name to make it unique. You can retrieve the adjusted name by calling
 -     * getName() on your new instance.
 -     */
 -    LLEventPump(const std::string& name, bool tweak=false);
 -    virtual ~LLEventPump();
 -
 -    /// group exceptions thrown by listen(). We use exceptions because these
 -    /// particular errors are likely to be coding errors, found and fixed by
 -    /// the developer even before preliminary checkin.
 -    struct ListenError: public std::runtime_error
 -    {
 -        ListenError(const std::string& what): std::runtime_error(what) {}
 -    };
 -    /**
 -     * exception thrown by listen(). You are attempting to register a
 -     * listener on this LLEventPump using the same listener name as an
 -     * already-registered listener.
 -     */
 -    struct DupListenerName: public ListenError
 -    {
 -        DupListenerName(const std::string& what):
 -            ListenError(std::string("DupListenerName: ") + what)
 -        {}
 -    };
 -    /**
 -     * exception thrown by listen(). The order dependencies specified for your
 -     * listener are incompatible with existing listeners.
 -     *
 -     * Consider listener "a" which specifies before "b" and "b" which
 -     * specifies before "c". You are now attempting to register "c" before
 -     * "a". There is no order that can satisfy all constraints.
 -     */
 -    struct Cycle: public ListenError
 -    {
 -        Cycle(const std::string& what): ListenError(std::string("Cycle: ") + what) {}
 -    };
 -    /**
 -     * exception thrown by listen(). This one means that your new listener
 -     * would force a change to the order of previously-registered listeners,
 -     * and we don't have a good way to implement that.
 -     *
 -     * Consider listeners "some", "other" and "third". "some" and "other" are
 -     * registered earlier without specifying relative order, so "other"
 -     * happens to be first. Now you attempt to register "third" after "some"
 -     * and before "other". Whoops, that would require swapping "some" and
 -     * "other", which we can't do. Instead we throw this exception.
 -     *
 -     * It may not be possible to change the registration order so we already
 -     * know "third"s order requirement by the time we register the second of
 -     * "some" and "other". A solution would be to specify that "some" must
 -     * come before "other", or equivalently that "other" must come after
 -     * "some".
 -     */
 -    struct OrderChange: public ListenError
 -    {
 -        OrderChange(const std::string& what): ListenError(std::string("OrderChange: ") + what) {}
 -    };
 -
 -    /// used by listen()
 -    typedef std::vector<std::string> NameList;
 -    /// convenience placeholder for when you explicitly want to pass an empty
 -    /// NameList
 -    const static NameList empty;
 -
 -    /// Get this LLEventPump's name
 -    std::string getName() const { return mName; }
 -
 -    /**
 -     * Register a new listener with a unique name. Specify an optional list
 -     * of other listener names after which this one must be called, likewise
 -     * an optional list of other listener names before which this one must be
 -     * called. The other listeners mentioned need not yet be registered
 -     * themselves. listen() can throw any ListenError; see ListenError
 -     * subclasses.
 -     *
 -     * The listener name must be unique among active listeners for this
 -     * LLEventPump, else you get DupListenerName. If you don't care to invent
 -     * a name yourself, use inventName(). (I was tempted to recognize e.g. ""
 -     * and internally generate a distinct name for that case. But that would
 -     * handle badly the scenario in which you want to add, remove, re-add,
 -     * etc. the same listener: each new listen() call would necessarily
 -     * perform a new dependency sort. Assuming you specify the same
 -     * after/before lists each time, using inventName() when you first
 -     * instantiate your listener, then passing the same name on each listen()
 -     * call, allows us to optimize away the second and subsequent dependency
 -     * sorts.
 -     *
 -     * If (as is typical) you pass a <tt>boost::bind()</tt> expression as @a
 -     * listener, listen() will inspect the components of that expression. If a
 -     * bound object matches any of several cases, the connection will
 -     * automatically be disconnected when that object is destroyed.
 -     *
 -     * * You bind a <tt>boost::weak_ptr</tt>.
 -     * * Binding a <tt>boost::shared_ptr</tt> that way would ensure that the
 -     *   referenced object would @em never be destroyed, since the @c
 -     *   shared_ptr stored in the LLEventPump would remain an outstanding
 -     *   reference. Use the weaken() function to convert your @c shared_ptr to
 -     *   @c weak_ptr. Because this is easy to forget, binding a @c shared_ptr
 -     *   will produce a compile error (@c BOOST_STATIC_ASSERT failure).
 -     * * You bind a simple pointer or reference to an object derived from
 -     *   <tt>boost::enable_shared_from_this</tt>. (UNDER CONSTRUCTION)
 -     * * You bind a simple pointer or reference to an object derived from
 -     *   LLEventTrackable. Unlike the cases described above, though, this is
 -     *   vulnerable to a couple of cross-thread race conditions, as described
 -     *   in the LLEventTrackable documentation.
 -     */
 -    template <typename LISTENER>
 -    LLBoundListener listen(const std::string& name, const LISTENER& listener,
 -                           const NameList& after=NameList(),
 -                           const NameList& before=NameList())
 -    {
 -        // Examine listener, using our listen_impl() method to make the
 -        // actual connection.
 -        // This is why listen() is a template. Conversion from boost::bind()
 -        // to LLEventListener performs type erasure, so it's important to look
 -        // at the boost::bind object itself before that happens.
 -        return LLEventDetail::visit_and_connect(listener,
 -                                                boost::bind(&LLEventPump::listen_impl,
 -                                                            this,
 -                                                            name,
 -                                                            _1,
 -                                                            after,
 -                                                            before));
 -    }
 -
 -    /// Get the LLBoundListener associated with the passed name (dummy
 -    /// LLBoundListener if not found)
 -    virtual LLBoundListener getListener(const std::string& name) const;
 -    /**
 -     * Instantiate one of these to block an existing connection:
 -     * @code
 -     * { // in some local scope
 -     *     LLEventPump::Blocker block(someLLBoundListener);
 -     *     // code that needs the connection blocked
 -     * } // unblock the connection again
 -     * @endcode
 -     */
 -    typedef boost::signals2::shared_connection_block Blocker;
 -    /// Unregister a listener by name. Prefer this to
 -    /// <tt>getListener(name).disconnect()</tt> because stopListening() also
 -    /// forgets this name.
 -    virtual void stopListening(const std::string& name);
 -    /// Post an event to all listeners. The @c bool return is only meaningful
 -    /// if the underlying leaf class is LLEventStream -- beware of relying on
 -    /// it too much! Truthfully, we return @c bool mostly to permit chaining
 -    /// one LLEventPump as a listener on another.
 -    virtual bool post(const LLSD&) = 0;
 -    /// Enable/disable: while disabled, silently ignore all post() calls
 -    virtual void enable(bool enabled=true) { mEnabled = enabled; }
 -    /// query
 -    virtual bool enabled() const { return mEnabled; }
 -
 -    /// Generate a distinct name for a listener -- see listen()
 -    static std::string inventName(const std::string& pfx="listener");
 -
 -private:
 -    friend class LLEventPumps;
 -    /// flush queued events
 -    virtual void flush() {}
 -
 -    virtual void reset();
 -
 -private:
 -    virtual LLBoundListener listen_impl(const std::string& name, const LLEventListener&,
 -                                        const NameList& after,
 -                                        const NameList& before);
 -    std::string mName;
 -
 -protected:
 -    /// implement the dispatching
 -    boost::scoped_ptr<LLStandardSignal> mSignal;
 -
 -    /// valve open?
 -    bool mEnabled;
 -    /// Map of named listeners. This tracks the listeners that actually exist
 -    /// at this moment. When we stopListening(), we discard the entry from
 -    /// this map.
 -    typedef std::map<std::string, boost::signals2::connection> ConnectionMap;
 -    ConnectionMap mConnections;
 -    typedef LLDependencies<std::string, float> DependencyMap;
 -    /// Dependencies between listeners. For each listener, track the float
 -    /// used to establish its place in mSignal's order. This caches all the
 -    /// listeners that have ever registered; stopListening() does not discard
 -    /// the entry from this map. This is to avoid a new dependency sort if the
 -    /// same listener with the same dependencies keeps hopping on and off this
 -    /// LLEventPump.
 -    DependencyMap mDeps;
 -};
 -
 -/*****************************************************************************
 -*   LLEventStream
 -*****************************************************************************/
 -/**
 - * LLEventStream is a thin wrapper around LLStandardSignal. Posting an
 - * event immediately calls all registered listeners.
 - */
 -class LL_COMMON_API LLEventStream: public LLEventPump
 -{
 -public:
 -    LLEventStream(const std::string& name, bool tweak=false): LLEventPump(name, tweak) {}
 -    virtual ~LLEventStream() {}
 -
 -    /// Post an event to all listeners
 -    virtual bool post(const LLSD& event);
 -};
 -
 -/*****************************************************************************
 -*   LLEventQueue
 -*****************************************************************************/
 -/**
 - * LLEventQueue isa LLEventPump whose post() method defers calling registered
 - * listeners until flush() is called.
 - */
 -class LL_COMMON_API LLEventQueue: public LLEventPump
 -{
 -public:
 -    LLEventQueue(const std::string& name, bool tweak=false): LLEventPump(name, tweak) {}
 -    virtual ~LLEventQueue() {}
 -
 -    /// Post an event to all listeners
 -    virtual bool post(const LLSD& event);
 -
 -private:
 -    /// flush queued events
 -    virtual void flush();
 -
 -private:
 -    typedef std::deque<LLSD> EventQueue;
 -    EventQueue mEventQueue;
 -};
 -
 -/*****************************************************************************
 -*   LLReqID
 -*****************************************************************************/
 -/**
 - * This class helps the implementer of a given event API to honor the
 - * ["reqid"] convention. By this convention, each event API stamps into its
 - * response LLSD a ["reqid"] key whose value echoes the ["reqid"] value, if
 - * any, from the corresponding request.
 - *
 - * This supports an (atypical, but occasionally necessary) use case in which
 - * two or more asynchronous requests are multiplexed onto the same ["reply"]
 - * LLEventPump. Since the response events could arrive in arbitrary order, the
 - * caller must be able to demux them. It does so by matching the ["reqid"]
 - * value in each response with the ["reqid"] value in the corresponding
 - * request.
 - *
 - * It is the caller's responsibility to ensure distinct ["reqid"] values for
 - * that case. Though LLSD::UUID is guaranteed to work, it might be overkill:
 - * the "namespace" of unique ["reqid"] values is simply the set of requests
 - * specifying the same ["reply"] LLEventPump name.
 - *
 - * Making a given event API echo the request's ["reqid"] into the response is
 - * nearly trivial. This helper is mostly for mnemonic purposes, to serve as a
 - * place to put these comments. We hope that each time a coder implements a
 - * new event API based on some existing one, s/he will say, "Huh, what's an
 - * LLReqID?" and look up this material.
 - *
 - * The hardest part about the convention is deciding where to store the
 - * ["reqid"] value. Ironically, LLReqID can't help with that: you must store
 - * an LLReqID instance in whatever storage will persist until the reply is
 - * sent. For example, if the request ultimately ends up using a Responder
 - * subclass, storing an LLReqID instance in the Responder works.
 - *
 - * @note
 - * The @em implementer of an event API must honor the ["reqid"] convention.
 - * However, the @em caller of an event API need only use it if s/he is sharing
 - * the same ["reply"] LLEventPump for two or more asynchronous event API
 - * requests.
 - *
 - * In most cases, it's far easier for the caller to instantiate a local
 - * LLEventStream and pass its name to the event API in question. Then it's
 - * perfectly reasonable not to set a ["reqid"] key in the request, ignoring
 - * the @c isUndefined() ["reqid"] value in the response.
 - */
 -class LL_COMMON_API LLReqID
 -{
 -public:
 -    /**
 -     * If you have the request in hand at the time you instantiate the
 -     * LLReqID, pass that request to extract its ["reqid"].
 - */
 -    LLReqID(const LLSD& request):
 -        mReqid(request["reqid"])
 -    {}
 -    /// If you don't yet have the request, use setFrom() later.
 -    LLReqID() {}
 -
 -    /// Extract and store the ["reqid"] value from an incoming request.
 -    void setFrom(const LLSD& request)
 -    {
 -        mReqid = request["reqid"];
 -    }
 -
 -    /// Set ["reqid"] key into a pending response LLSD object.
 -    void stamp(LLSD& response) const;
 -
 -    /// Make a whole new response LLSD object with our ["reqid"].
 -    LLSD makeResponse() const
 -    {
 -        LLSD response;
 -        stamp(response);
 -        return response;
 -    }
 -
 -    /// Not really sure of a use case for this accessor...
 -    LLSD getReqID() const { return mReqid; }
 -
 -private:
 -    LLSD mReqid;
 -};
 -
 -/*****************************************************************************
 -*   Underpinnings
 -*****************************************************************************/
 -/**
 - * We originally provided a suite of overloaded
 - * LLEventTrackable::listenTo(LLEventPump&, ...) methods that would call
 - * LLEventPump::listen(...) and then pass the returned LLBoundListener to
 - * LLEventTrackable::track(). This was workable but error-prone: the coder
 - * must remember to call listenTo() rather than the more straightforward
 - * listen() method.
 - *
 - * Now we publish only the single canonical listen() method, so there's a
 - * uniform mechanism. Having a single way to do this is good, in that there's
 - * no question in the coder's mind which of several alternatives to choose.
 - *
 - * To support automatic connection management, we use boost::visit_each
 - * (http://www.boost.org/doc/libs/1_37_0/doc/html/boost/visit_each.html) to
 - * inspect each argument of a boost::bind expression. (Although the visit_each
 - * mechanism was first introduced with the original Boost.Signals library, it
 - * was only later documented.)
 - *
 - * Cases:
 - * * At least one of the function's arguments is a boost::weak_ptr<T>. Pass
 - *   the corresponding shared_ptr to slot_type::track(). Ideally that would be
 - *   the object whose method we want to call, but in fact we do the same for
 - *   any weak_ptr we might find among the bound arguments. If we're passing
 - *   our bound method a weak_ptr to some object, wouldn't the destruction of
 - *   that object invalidate the call? So we disconnect automatically when any
 - *   such object is destroyed. This is the mechanism preferred by boost::
 - *   signals2.
 - * * One of the functions's arguments is a boost::shared_ptr<T>. This produces
 - *   a compile error: the bound copy of the shared_ptr stored in the
 - *   boost_bind object stored in the signal object would make the referenced
 - *   T object immortal. We provide a weaken() function. Pass
 - *   weaken(your_shared_ptr) instead. (We can inspect, but not modify, the
 - *   boost::bind object. Otherwise we'd replace the shared_ptr with weak_ptr
 - *   implicitly and just proceed.)
 - * * One of the function's arguments is a plain pointer/reference to an object
 - *   derived from boost::enable_shared_from_this. We assume that this object
 - *   is managed using boost::shared_ptr, so we implicitly extract a shared_ptr
 - *   and track that. (UNDER CONSTRUCTION)
 - * * One of the function's arguments is derived from LLEventTrackable. Pass
 - *   the LLBoundListener to its LLEventTrackable::track(). This is vulnerable
 - *   to a couple different race conditions, as described in LLEventTrackable
 - *   documentation. (NOTE: Now that LLEventTrackable is a typedef for
 - *   boost::signals2::trackable, the Signals2 library handles this itself, so
 - *   our visitor needs no special logic for this case.)
 - * * Any other argument type is irrelevant to automatic connection management.
 - */
 -
 -namespace LLEventDetail
 -{
 -    template <typename F>
 -    const F& unwrap(const F& f) { return f; }
 -
 -    template <typename F>
 -    const F& unwrap(const boost::reference_wrapper<F>& f) { return f.get(); }
 -
 -    // Most of the following is lifted from the Boost.Signals use of
 -    // visit_each.
 -    template<bool Cond> struct truth {};
 -
 -    /**
 -     * boost::visit_each() Visitor, used on a template argument <tt>const F&
 -     * f</tt> as follows (see visit_and_connect()):
 -     * @code
 -     * LLEventListener listener(f);
 -     * Visitor visitor(listener); // bind listener so it can track() shared_ptrs
 -     * using boost::visit_each;   // allow unqualified visit_each() call for ADL
 -     * visit_each(visitor, unwrap(f));
 -     * @endcode
 -     */
 -    class Visitor
 -    {
 -    public:
 -        /**
 -         * Visitor binds a reference to LLEventListener so we can track() any
 -         * shared_ptrs we find in the argument list.
 -         */
 -        Visitor(LLEventListener& listener):
 -            mListener(listener)
 -        {
 -        }
 -
 -        /**
 -         * boost::visit_each() calls this method for each component of a
 -         * boost::bind() expression.
 -         */
 -        template <typename T>
 -        void operator()(const T& t) const
 -        {
 -            decode(t, 0);
 -        }
 -
 -    private:
 -        // decode() decides between a reference wrapper and anything else
 -        // boost::ref() variant
 -        template<typename T>
 -        void decode(const boost::reference_wrapper<T>& t, int) const
 -        {
 -//          add_if_trackable(t.get_pointer());
 -        }
 -
 -        // decode() anything else
 -        template<typename T>
 -        void decode(const T& t, long) const
 -        {
 -            typedef truth<(boost::is_pointer<T>::value)> is_a_pointer;
 -            maybe_get_pointer(t, is_a_pointer());
 -        }
 -
 -        // maybe_get_pointer() decides between a pointer and a non-pointer
 -        // plain pointer variant
 -        template<typename T>
 -        void maybe_get_pointer(const T& t, truth<true>) const
 -        {
 -//          add_if_trackable(t);
 -        }
 -
 -        // shared_ptr variant
 -        template<typename T>
 -        void maybe_get_pointer(const boost::shared_ptr<T>& t, truth<false>) const
 -        {
 -            // If we have a shared_ptr to this object, it doesn't matter
 -            // whether the object is derived from LLEventTrackable, so no
 -            // further analysis of T is needed.
 -//          mListener.track(t);
 -
 -            // Make this case illegal. Passing a bound shared_ptr to
 -            // slot_type::track() is useless, since the bound shared_ptr will
 -            // keep the object alive anyway! Force the coder to cast to weak_ptr.
 -
 -            // Trivial as it is, make the BOOST_STATIC_ASSERT() condition
 -            // dependent on template param so the macro is only evaluated if
 -            // this method is in fact instantiated, as described here:
 -            // http://www.boost.org/doc/libs/1_34_1/doc/html/boost_staticassert.html
 -
 -            // ATTENTION: Don't bind a shared_ptr<anything> using
 -            // LLEventPump::listen(boost::bind()). Doing so captures a copy of
 -            // the shared_ptr, making the referenced object effectively
 -            // immortal. Use the weaken() function, e.g.:
 -            // somepump.listen(boost::bind(...weaken(my_shared_ptr)...));
 -            // This lets us automatically disconnect when the referenced
 -            // object is destroyed.
 -            BOOST_STATIC_ASSERT(sizeof(T) == 0);
 -        }
 -
 -        // weak_ptr variant
 -        template<typename T>
 -        void maybe_get_pointer(const boost::weak_ptr<T>& t, truth<false>) const
 -        {
 -            // If we have a weak_ptr to this object, it doesn't matter
 -            // whether the object is derived from LLEventTrackable, so no
 -            // further analysis of T is needed.
 -            mListener.track(t);
 -//          std::cout << "Found weak_ptr<" << typeid(T).name() << ">!\n";
 -        }
 -
 -#if 0
 -        // reference to anything derived from boost::enable_shared_from_this
 -        template <typename T>
 -        inline void maybe_get_pointer(const boost::enable_shared_from_this<T>& ct,
 -                                      truth<false>) const
 -        {
 -            // Use the slot_type::track(shared_ptr) mechanism. Cast away
 -            // const-ness because (in our code base anyway) it's unusual
 -            // to find shared_ptr<const T>.
 -            boost::enable_shared_from_this<T>&
 -                t(const_cast<boost::enable_shared_from_this<T>&>(ct));
 -            std::cout << "Capturing shared_from_this()" << std::endl;
 -            boost::shared_ptr<T> sp(t.shared_from_this());
 -/*==========================================================================*|
 -            std::cout << "Capturing weak_ptr" << std::endl;
 -            boost::weak_ptr<T> wp(sp);
 -|*==========================================================================*/
 -            std::cout << "Tracking shared__ptr" << std::endl;
 -            mListener.track(sp);
 -        }
 -#endif
 -
 -        // non-pointer variant
 -        template<typename T>
 -        void maybe_get_pointer(const T& t, truth<false>) const
 -        {
 -            // Take the address of this object, because the object itself may be
 -            // trackable
 -//          add_if_trackable(boost::addressof(t));
 -        }
 -
 -/*==========================================================================*|
 -        // add_if_trackable() adds LLEventTrackable objects to mTrackables
 -        inline void add_if_trackable(const LLEventTrackable* t) const
 -        {
 -            if (t)
 -            {
 -            }
 -        }
 -
 -        // pointer to anything not an LLEventTrackable subclass
 -        inline void add_if_trackable(const void*) const
 -        {
 -        }
 -
 -        // pointer to free function
 -        // The following construct uses the preprocessor to generate
 -        // add_if_trackable() overloads accepting pointer-to-function taking
 -        // 0, 1, ..., LLEVENTS_LISTENER_ARITY parameters of arbitrary type.
 -#define BOOST_PP_LOCAL_MACRO(n)                                     \
 -        template <typename R                                        \
 -                  BOOST_PP_COMMA_IF(n)                              \
 -                  BOOST_PP_ENUM_PARAMS(n, typename T)>              \
 -        inline void                                                 \
 -        add_if_trackable(R (*)(BOOST_PP_ENUM_PARAMS(n, T))) const   \
 -        {                                                           \
 -        }
 -#define BOOST_PP_LOCAL_LIMITS (0, LLEVENTS_LISTENER_ARITY)
 -#include BOOST_PP_LOCAL_ITERATE()
 -#undef  BOOST_PP_LOCAL_MACRO
 -#undef  BOOST_PP_LOCAL_LIMITS
 -|*==========================================================================*/
 -
 -        /// Bind a reference to the LLEventListener to call its track() method.
 -        LLEventListener& mListener;
 -    };
 -
 -    /**
 -     * Utility template function to use Visitor appropriately
 -     *
 -     * @param raw_listener Callable to connect, typically a boost::bind()
 -     * expression. This will be visited by Visitor using boost::visit_each().
 -     * @param connect_funct Callable that will connect() @a raw_listener to an
 -     * LLStandardSignal, returning LLBoundListener.
 -     */
 -    template <typename LISTENER>
 -    LLBoundListener visit_and_connect(const LISTENER& raw_listener,
 -                                      const ConnectFunc& connect_func)
 -    {
 -        // Capture the listener
 -        LLEventListener listener(raw_listener);
 -        // Define our Visitor, binding the listener so we can call
 -        // listener.track() if we discover any shared_ptr<Foo>.
 -        LLEventDetail::Visitor visitor(listener);
 -        // Allow unqualified visit_each() call for ADL
 -        using boost::visit_each;
 -        // Visit each component of a boost::bind() expression. Pass
 -        // 'raw_listener', our template argument, rather than 'listener' from
 -        // which type details have been erased. unwrap() comes from
 -        // Boost.Signals, in case we were passed a boost::ref().
 -        visit_each(visitor, LLEventDetail::unwrap(raw_listener));
 -        // Make the connection using passed function. At present, wrapping
 -        // this functionality into this function is a bit silly: we don't
 -        // really need a visit_and_connect() function any more, just a visit()
 -        // function. The definition of this function dates from when, after
 -        // visit_each(), after establishing the connection, we had to
 -        // postprocess the new connection with the visitor object. That's no
 -        // longer necessary.
 -        return connect_func(listener);
 -    }
 -} // namespace LLEventDetail
 -
 -// Somewhat to my surprise, passing boost::bind(...boost::weak_ptr<T>...) to
 -// listen() fails in Boost code trying to instantiate LLEventListener (i.e.
 -// LLStandardSignal::slot_type) because the boost::get_pointer() utility function isn't
 -// specialized for boost::weak_ptr. This remedies that omission.
 -namespace boost
 -{
 -    template <typename T>
 -    T* get_pointer(const weak_ptr<T>& ptr) { return shared_ptr<T>(ptr).get(); }
 -}
 -
 -/// Since we forbid use of listen(boost::bind(...shared_ptr<T>...)), provide an
 -/// easy way to cast to the corresponding weak_ptr.
 -template <typename T>
 -boost::weak_ptr<T> weaken(const boost::shared_ptr<T>& ptr)
 -{
 -    return boost::weak_ptr<T>(ptr);
 -}
 -
 -#endif /* ! defined(LL_LLEVENTS_H) */
 +/** + * @file   llevents.h + * @author Kent Quirk, Nat Goodspeed + * @date   2008-09-11 + * @brief  This is an implementation of the event system described at + *         https://wiki.lindenlab.com/wiki/Viewer:Messaging/Event_System, + *         originally introduced in llnotifications.h. It has nothing + *         whatsoever to do with the older system in llevent.h. + *  + * $LicenseInfo:firstyear=2008&license=viewergpl$ + * Copyright (c) 2008, Linden Research, Inc. + * $/LicenseInfo$ + */ + +#if ! defined(LL_LLEVENTS_H) +#define LL_LLEVENTS_H + +#include <string> +#include <map> +#include <set> +#include <vector> +#include <deque> +#include <stdexcept> +#if LL_WINDOWS +	#pragma warning (push) +	#pragma warning (disable : 4263) // boost::signals2::expired_slot::what() has const mismatch +	#pragma warning (disable : 4264)  +#endif +#include <boost/signals2.hpp> +#if LL_WINDOWS +	#pragma warning (pop) +#endif + +#include <boost/bind.hpp> +#include <boost/shared_ptr.hpp> +#include <boost/enable_shared_from_this.hpp> +#include <boost/utility.hpp>        // noncopyable +#include <boost/optional/optional.hpp> +#include <boost/visit_each.hpp> +#include <boost/ref.hpp>            // reference_wrapper +#include <boost/type_traits/is_pointer.hpp> +#include <boost/function.hpp> +#include <boost/static_assert.hpp> +#include "llsd.h" +#include "llsingleton.h" +#include "lldependencies.h" + +// override this to allow binding free functions with more parameters +#ifndef LLEVENTS_LISTENER_ARITY +#define LLEVENTS_LISTENER_ARITY 10 +#endif + +// hack for testing +#ifndef testable +#define testable private +#endif + +/***************************************************************************** +*   Signal and handler declarations +*   Using a single handler signature means that we can have a common handler +*   type, rather than needing a distinct one for each different handler. +*****************************************************************************/ + +/** + * A boost::signals Combiner that stops the first time a handler returns true + * We need this because we want to have our handlers return bool, so that + * we have the option to cause a handler to stop further processing. The + * default handler fails when the signal returns a value but has no slots. + */ +struct LLStopWhenHandled +{ +    typedef bool result_type; + +    template<typename InputIterator> +    result_type operator()(InputIterator first, InputIterator last) const +    { +        for (InputIterator si = first; si != last; ++si) +		{ +            if (*si) +			{ +                return true; +			} +		} +        return false; +    } +}; + +/** + * We want to have a standard signature for all signals; this way, + * we can easily document a protocol for communicating across + * dlls and into scripting languages someday. + * + * We want to return a bool to indicate whether the signal has been + * handled and should NOT be passed on to other listeners. + * Return true to stop further handling of the signal, and false + * to continue. + * + * We take an LLSD because this way the contents of the signal + * are independent of the API used to communicate it. + * It is const ref because then there's low cost to pass it; + * if you only need to inspect it, it's very cheap. + * + * @internal + * The @c float template parameter indicates that we will internally use @c + * float to indicate relative listener order on a given LLStandardSignal. + * Don't worry, the @c float values are strictly internal! They are not part + * of the interface, for the excellent reason that requiring the caller to + * specify a numeric key to establish order means that the caller must know + * the universe of possible values. We use LLDependencies for that instead. + */ +typedef boost::signals2::signal<bool(const LLSD&), LLStopWhenHandled, float>  LLStandardSignal; +/// Methods that forward listeners (e.g. constructed with +/// <tt>boost::bind()</tt>) should accept (const LLEventListener&) +typedef LLStandardSignal::slot_type LLEventListener; +/// Result of registering a listener, supports <tt>connected()</tt>, +/// <tt>disconnect()</tt> and <tt>blocked()</tt> +typedef boost::signals2::connection LLBoundListener; +/// Storing an LLBoundListener in LLTempBoundListener will disconnect the +/// referenced listener when the LLTempBoundListener instance is destroyed. +typedef boost::signals2::scoped_connection LLTempBoundListener; + +/** + * A common idiom for event-based code is to accept either a callable -- + * directly called on completion -- or the string name of an LLEventPump on + * which to post the completion event. Specifying a parameter as <tt>const + * LLListenerOrPumpName&</tt> allows either. + * + * Calling a validly-constructed LLListenerOrPumpName, passing the LLSD + * 'event' object, either calls the callable or posts the event to the named + * LLEventPump. + * + * A default-constructed LLListenerOrPumpName is 'empty'. (This is useful as + * the default value of an optional method parameter.) Calling it throws + * LLListenerOrPumpName::Empty. Test for this condition beforehand using + * either <tt>if (param)</tt> or <tt>if (! param)</tt>. + */ +class LL_COMMON_API LLListenerOrPumpName +{ +public: +    /// passing string name of LLEventPump +    LLListenerOrPumpName(const std::string& pumpname); +    /// passing string literal (overload so compiler isn't forced to infer +    /// double conversion) +    LLListenerOrPumpName(const char* pumpname); +    /// passing listener -- the "anything else" catch-all case. The type of an +    /// object constructed by boost::bind() isn't intended to be written out. +    /// Normally we'd just accept 'const LLEventListener&', but that would +    /// require double implicit conversion: boost::bind() object to +    /// LLEventListener, LLEventListener to LLListenerOrPumpName. So use a +    /// template to forward anything. +    template<typename T> +    LLListenerOrPumpName(const T& listener): mListener(listener) {} + +    /// for omitted method parameter: uninitialized mListener +    LLListenerOrPumpName() {} + +    /// test for validity +    operator bool() const { return bool(mListener); } +    bool operator! () const { return ! mListener; } + +    /// explicit accessor +    const LLEventListener& getListener() const { return *mListener; } + +    /// implicit conversion to LLEventListener +    operator LLEventListener() const { return *mListener; } + +    /// allow calling directly +    bool operator()(const LLSD& event) const; + +    /// exception if you try to call when empty +    struct Empty: public std::runtime_error +    { +        Empty(const std::string& what): +            std::runtime_error(std::string("LLListenerOrPumpName::Empty: ") + what) {} +    }; + +private: +    boost::optional<LLEventListener> mListener; +}; + +/***************************************************************************** +*   LLEventPumps +*****************************************************************************/ +class LLEventPump; + +/** + * LLEventPumps is a Singleton manager through which one typically accesses + * this subsystem. + */ +class LL_COMMON_API LLEventPumps: public LLSingleton<LLEventPumps> +{ +    friend class LLSingleton<LLEventPumps>; +public: +    /** +     * Find or create an LLEventPump instance with a specific name. We return +     * a reference so there's no question about ownership. obtain() @em finds +     * an instance without conferring @em ownership. +     */ +    LLEventPump& obtain(const std::string& name); +    /** +     * Flush all known LLEventPump instances +     */ +    void flush(); + +    /** +     * Reset all known LLEventPump instances +     * workaround for DEV-35406 crash on shutdown +     */ +    void reset(); + +private: +    friend class LLEventPump; +    /** +     * Register a new LLEventPump instance (internal) +     */ +    std::string registerNew(const LLEventPump&, const std::string& name, bool tweak); +    /** +     * Unregister a doomed LLEventPump instance (internal) +     */ +    void unregister(const LLEventPump&); + +private: +    LLEventPumps(); +    ~LLEventPumps(); + +testable: +    // Map of all known LLEventPump instances, whether or not we instantiated +    // them. We store a plain old LLEventPump* because this map doesn't claim +    // ownership of the instances. Though the common usage pattern is to +    // request an instance using obtain(), it's fair to instantiate an +    // LLEventPump subclass statically, as a class member, on the stack or on +    // the heap. In such cases, the instantiating party is responsible for its +    // lifespan. +    typedef std::map<std::string, LLEventPump*> PumpMap; +    PumpMap mPumpMap; +    // Set of all LLEventPumps we instantiated. Membership in this set means +    // we claim ownership, and will delete them when this LLEventPumps is +    // destroyed. +    typedef std::set<LLEventPump*> PumpSet; +    PumpSet mOurPumps; +    // LLEventPump names that should be instantiated as LLEventQueue rather +    // than as LLEventStream +    typedef std::set<std::string> PumpNames; +    PumpNames mQueueNames; +}; + +/***************************************************************************** +*   details +*****************************************************************************/ +namespace LLEventDetail +{ +    /// Any callable capable of connecting an LLEventListener to an +    /// LLStandardSignal to produce an LLBoundListener can be mapped to this +    /// signature. +    typedef boost::function<LLBoundListener(const LLEventListener&)> ConnectFunc; + +    /** +     * Utility template function to use Visitor appropriately +     * +     * @param listener Callable to connect, typically a boost::bind() +     * expression. This will be visited by Visitor using boost::visit_each(). +     * @param connect_func Callable that will connect() @a listener to an +     * LLStandardSignal, returning LLBoundListener. +     */ +    template <typename LISTENER> +    LLBoundListener visit_and_connect(const LISTENER& listener, +                                      const ConnectFunc& connect_func); +} // namespace LLEventDetail + +/***************************************************************************** +*   LLEventTrackable +*****************************************************************************/ +/** + * LLEventTrackable wraps boost::signals2::trackable, which resembles + * boost::trackable. Derive your listener class from LLEventTrackable instead, + * and use something like + * <tt>LLEventPump::listen(boost::bind(&YourTrackableSubclass::method, + * instance, _1))</tt>. This will implicitly disconnect when the object + * referenced by @c instance is destroyed. + * + * @note + * LLEventTrackable doesn't address a couple of cases: + * * Object destroyed during call + *   - You enter a slot call in thread A. + *   - Thread B destroys the object, which of course disconnects it from any + *     future slot calls. + *   - Thread A's call uses 'this', which now refers to a defunct object. + *     Undefined behavior results. + * * Call during destruction + *   - @c MySubclass is derived from LLEventTrackable. + *   - @c MySubclass registers one of its own methods using + *     <tt>LLEventPump::listen()</tt>. + *   - The @c MySubclass object begins destruction. <tt>~MySubclass()</tt> + *     runs, destroying state specific to the subclass. (For instance, a + *     <tt>Foo*</tt> data member is <tt>delete</tt>d but not zeroed.) + *   - The listening method will not be disconnected until + *     <tt>~LLEventTrackable()</tt> runs. + *   - Before we get there, another thread posts data to the @c LLEventPump + *     instance, calling the @c MySubclass method. + *   - The method in question relies on valid @c MySubclass state. (For + *     instance, it attempts to dereference the <tt>Foo*</tt> pointer that was + *     <tt>delete</tt>d but not zeroed.) + *   - Undefined behavior results. + * If you suspect you may encounter any such scenario, you're better off + * managing the lifespan of your object with <tt>boost::shared_ptr</tt>. + * Passing <tt>LLEventPump::listen()</tt> a <tt>boost::bind()</tt> expression + * involving a <tt>boost::weak_ptr<Foo></tt> is recognized specially, engaging + * thread-safe Boost.Signals2 machinery. + */ +typedef boost::signals2::trackable LLEventTrackable; + +/***************************************************************************** +*   LLEventPump +*****************************************************************************/ +/** + * LLEventPump is the base class interface through which we access the + * concrete subclasses LLEventStream and LLEventQueue. + * + * @NOTE + * LLEventPump derives from LLEventTrackable so that when you "chain" + * LLEventPump instances together, they will automatically disconnect on + * destruction. Please see LLEventTrackable documentation for situations in + * which this may be perilous across threads. + */ +class LL_COMMON_API LLEventPump: public LLEventTrackable +{ +public: +    /** +     * Exception thrown by LLEventPump(). You are trying to instantiate an +     * LLEventPump (subclass) using the same name as some other instance, and +     * you didn't pass <tt>tweak=true</tt> to permit it to generate a unique +     * variant. +     */ +    struct DupPumpName: public std::runtime_error +    { +        DupPumpName(const std::string& what): +            std::runtime_error(std::string("DupPumpName: ") + what) {} +    }; + +    /** +     * Instantiate an LLEventPump (subclass) with the string name by which it +     * can be found using LLEventPumps::obtain(). +     * +     * If you pass (or default) @a tweak to @c false, then a duplicate name +     * will throw DupPumpName. This won't happen if LLEventPumps::obtain() +     * instantiates the LLEventPump, because obtain() uses find-or-create +     * logic. It can only happen if you instantiate an LLEventPump in your own +     * code -- and a collision with the name of some other LLEventPump is +     * likely to cause much more subtle problems! +     * +     * When you hand-instantiate an LLEventPump, consider passing @a tweak as +     * @c true. This directs LLEventPump() to append a suffix to the passed @a +     * name to make it unique. You can retrieve the adjusted name by calling +     * getName() on your new instance. +     */ +    LLEventPump(const std::string& name, bool tweak=false); +    virtual ~LLEventPump(); + +    /// group exceptions thrown by listen(). We use exceptions because these +    /// particular errors are likely to be coding errors, found and fixed by +    /// the developer even before preliminary checkin. +    struct ListenError: public std::runtime_error +    { +        ListenError(const std::string& what): std::runtime_error(what) {} +    }; +    /** +     * exception thrown by listen(). You are attempting to register a +     * listener on this LLEventPump using the same listener name as an +     * already-registered listener. +     */ +    struct DupListenerName: public ListenError +    { +        DupListenerName(const std::string& what): +            ListenError(std::string("DupListenerName: ") + what) +        {} +    }; +    /** +     * exception thrown by listen(). The order dependencies specified for your +     * listener are incompatible with existing listeners. +     * +     * Consider listener "a" which specifies before "b" and "b" which +     * specifies before "c". You are now attempting to register "c" before +     * "a". There is no order that can satisfy all constraints. +     */ +    struct Cycle: public ListenError +    { +        Cycle(const std::string& what): ListenError(std::string("Cycle: ") + what) {} +    }; +    /** +     * exception thrown by listen(). This one means that your new listener +     * would force a change to the order of previously-registered listeners, +     * and we don't have a good way to implement that. +     * +     * Consider listeners "some", "other" and "third". "some" and "other" are +     * registered earlier without specifying relative order, so "other" +     * happens to be first. Now you attempt to register "third" after "some" +     * and before "other". Whoops, that would require swapping "some" and +     * "other", which we can't do. Instead we throw this exception. +     * +     * It may not be possible to change the registration order so we already +     * know "third"s order requirement by the time we register the second of +     * "some" and "other". A solution would be to specify that "some" must +     * come before "other", or equivalently that "other" must come after +     * "some". +     */ +    struct OrderChange: public ListenError +    { +        OrderChange(const std::string& what): ListenError(std::string("OrderChange: ") + what) {} +    }; + +    /// used by listen() +    typedef std::vector<std::string> NameList; +    /// convenience placeholder for when you explicitly want to pass an empty +    /// NameList +    const static NameList empty; + +    /// Get this LLEventPump's name +    std::string getName() const { return mName; } + +    /** +     * Register a new listener with a unique name. Specify an optional list +     * of other listener names after which this one must be called, likewise +     * an optional list of other listener names before which this one must be +     * called. The other listeners mentioned need not yet be registered +     * themselves. listen() can throw any ListenError; see ListenError +     * subclasses. +     * +     * The listener name must be unique among active listeners for this +     * LLEventPump, else you get DupListenerName. If you don't care to invent +     * a name yourself, use inventName(). (I was tempted to recognize e.g. "" +     * and internally generate a distinct name for that case. But that would +     * handle badly the scenario in which you want to add, remove, re-add, +     * etc. the same listener: each new listen() call would necessarily +     * perform a new dependency sort. Assuming you specify the same +     * after/before lists each time, using inventName() when you first +     * instantiate your listener, then passing the same name on each listen() +     * call, allows us to optimize away the second and subsequent dependency +     * sorts. +     * +     * If (as is typical) you pass a <tt>boost::bind()</tt> expression as @a +     * listener, listen() will inspect the components of that expression. If a +     * bound object matches any of several cases, the connection will +     * automatically be disconnected when that object is destroyed. +     * +     * * You bind a <tt>boost::weak_ptr</tt>. +     * * Binding a <tt>boost::shared_ptr</tt> that way would ensure that the +     *   referenced object would @em never be destroyed, since the @c +     *   shared_ptr stored in the LLEventPump would remain an outstanding +     *   reference. Use the weaken() function to convert your @c shared_ptr to +     *   @c weak_ptr. Because this is easy to forget, binding a @c shared_ptr +     *   will produce a compile error (@c BOOST_STATIC_ASSERT failure). +     * * You bind a simple pointer or reference to an object derived from +     *   <tt>boost::enable_shared_from_this</tt>. (UNDER CONSTRUCTION) +     * * You bind a simple pointer or reference to an object derived from +     *   LLEventTrackable. Unlike the cases described above, though, this is +     *   vulnerable to a couple of cross-thread race conditions, as described +     *   in the LLEventTrackable documentation. +     */ +    template <typename LISTENER> +    LLBoundListener listen(const std::string& name, const LISTENER& listener, +                           const NameList& after=NameList(), +                           const NameList& before=NameList()) +    { +        // Examine listener, using our listen_impl() method to make the +        // actual connection. +        // This is why listen() is a template. Conversion from boost::bind() +        // to LLEventListener performs type erasure, so it's important to look +        // at the boost::bind object itself before that happens. +        return LLEventDetail::visit_and_connect(listener, +                                                boost::bind(&LLEventPump::listen_impl, +                                                            this, +                                                            name, +                                                            _1, +                                                            after, +                                                            before)); +    } + +    /// Get the LLBoundListener associated with the passed name (dummy +    /// LLBoundListener if not found) +    virtual LLBoundListener getListener(const std::string& name) const; +    /** +     * Instantiate one of these to block an existing connection: +     * @code +     * { // in some local scope +     *     LLEventPump::Blocker block(someLLBoundListener); +     *     // code that needs the connection blocked +     * } // unblock the connection again +     * @endcode +     */ +    typedef boost::signals2::shared_connection_block Blocker; +    /// Unregister a listener by name. Prefer this to +    /// <tt>getListener(name).disconnect()</tt> because stopListening() also +    /// forgets this name. +    virtual void stopListening(const std::string& name); +    /// Post an event to all listeners. The @c bool return is only meaningful +    /// if the underlying leaf class is LLEventStream -- beware of relying on +    /// it too much! Truthfully, we return @c bool mostly to permit chaining +    /// one LLEventPump as a listener on another. +    virtual bool post(const LLSD&) = 0; +    /// Enable/disable: while disabled, silently ignore all post() calls +    virtual void enable(bool enabled=true) { mEnabled = enabled; } +    /// query +    virtual bool enabled() const { return mEnabled; } + +    /// Generate a distinct name for a listener -- see listen() +    static std::string inventName(const std::string& pfx="listener"); + +private: +    friend class LLEventPumps; +    /// flush queued events +    virtual void flush() {} + +    virtual void reset(); + +private: +    virtual LLBoundListener listen_impl(const std::string& name, const LLEventListener&, +                                        const NameList& after, +                                        const NameList& before); +    std::string mName; + +protected: +    /// implement the dispatching +    boost::scoped_ptr<LLStandardSignal> mSignal; + +    /// valve open? +    bool mEnabled; +    /// Map of named listeners. This tracks the listeners that actually exist +    /// at this moment. When we stopListening(), we discard the entry from +    /// this map. +    typedef std::map<std::string, boost::signals2::connection> ConnectionMap; +    ConnectionMap mConnections; +    typedef LLDependencies<std::string, float> DependencyMap; +    /// Dependencies between listeners. For each listener, track the float +    /// used to establish its place in mSignal's order. This caches all the +    /// listeners that have ever registered; stopListening() does not discard +    /// the entry from this map. This is to avoid a new dependency sort if the +    /// same listener with the same dependencies keeps hopping on and off this +    /// LLEventPump. +    DependencyMap mDeps; +}; + +/***************************************************************************** +*   LLEventStream +*****************************************************************************/ +/** + * LLEventStream is a thin wrapper around LLStandardSignal. Posting an + * event immediately calls all registered listeners. + */ +class LL_COMMON_API LLEventStream: public LLEventPump +{ +public: +    LLEventStream(const std::string& name, bool tweak=false): LLEventPump(name, tweak) {} +    virtual ~LLEventStream() {} + +    /// Post an event to all listeners +    virtual bool post(const LLSD& event); +}; + +/***************************************************************************** +*   LLEventQueue +*****************************************************************************/ +/** + * LLEventQueue isa LLEventPump whose post() method defers calling registered + * listeners until flush() is called. + */ +class LL_COMMON_API LLEventQueue: public LLEventPump +{ +public: +    LLEventQueue(const std::string& name, bool tweak=false): LLEventPump(name, tweak) {} +    virtual ~LLEventQueue() {} + +    /// Post an event to all listeners +    virtual bool post(const LLSD& event); + +private: +    /// flush queued events +    virtual void flush(); + +private: +    typedef std::deque<LLSD> EventQueue; +    EventQueue mEventQueue; +}; + +/***************************************************************************** +*   LLReqID +*****************************************************************************/ +/** + * This class helps the implementer of a given event API to honor the + * ["reqid"] convention. By this convention, each event API stamps into its + * response LLSD a ["reqid"] key whose value echoes the ["reqid"] value, if + * any, from the corresponding request. + * + * This supports an (atypical, but occasionally necessary) use case in which + * two or more asynchronous requests are multiplexed onto the same ["reply"] + * LLEventPump. Since the response events could arrive in arbitrary order, the + * caller must be able to demux them. It does so by matching the ["reqid"] + * value in each response with the ["reqid"] value in the corresponding + * request. + * + * It is the caller's responsibility to ensure distinct ["reqid"] values for + * that case. Though LLSD::UUID is guaranteed to work, it might be overkill: + * the "namespace" of unique ["reqid"] values is simply the set of requests + * specifying the same ["reply"] LLEventPump name. + * + * Making a given event API echo the request's ["reqid"] into the response is + * nearly trivial. This helper is mostly for mnemonic purposes, to serve as a + * place to put these comments. We hope that each time a coder implements a + * new event API based on some existing one, s/he will say, "Huh, what's an + * LLReqID?" and look up this material. + * + * The hardest part about the convention is deciding where to store the + * ["reqid"] value. Ironically, LLReqID can't help with that: you must store + * an LLReqID instance in whatever storage will persist until the reply is + * sent. For example, if the request ultimately ends up using a Responder + * subclass, storing an LLReqID instance in the Responder works. + * + * @note + * The @em implementer of an event API must honor the ["reqid"] convention. + * However, the @em caller of an event API need only use it if s/he is sharing + * the same ["reply"] LLEventPump for two or more asynchronous event API + * requests. + * + * In most cases, it's far easier for the caller to instantiate a local + * LLEventStream and pass its name to the event API in question. Then it's + * perfectly reasonable not to set a ["reqid"] key in the request, ignoring + * the @c isUndefined() ["reqid"] value in the response. + */ +class LL_COMMON_API LLReqID +{ +public: +    /** +     * If you have the request in hand at the time you instantiate the +     * LLReqID, pass that request to extract its ["reqid"]. + */ +    LLReqID(const LLSD& request): +        mReqid(request["reqid"]) +    {} +    /// If you don't yet have the request, use setFrom() later. +    LLReqID() {} + +    /// Extract and store the ["reqid"] value from an incoming request. +    void setFrom(const LLSD& request) +    { +        mReqid = request["reqid"]; +    } + +    /// Set ["reqid"] key into a pending response LLSD object. +    void stamp(LLSD& response) const; + +    /// Make a whole new response LLSD object with our ["reqid"]. +    LLSD makeResponse() const +    { +        LLSD response; +        stamp(response); +        return response; +    } + +    /// Not really sure of a use case for this accessor... +    LLSD getReqID() const { return mReqid; } + +private: +    LLSD mReqid; +}; + +/***************************************************************************** +*   Underpinnings +*****************************************************************************/ +/** + * We originally provided a suite of overloaded + * LLEventTrackable::listenTo(LLEventPump&, ...) methods that would call + * LLEventPump::listen(...) and then pass the returned LLBoundListener to + * LLEventTrackable::track(). This was workable but error-prone: the coder + * must remember to call listenTo() rather than the more straightforward + * listen() method. + * + * Now we publish only the single canonical listen() method, so there's a + * uniform mechanism. Having a single way to do this is good, in that there's + * no question in the coder's mind which of several alternatives to choose. + * + * To support automatic connection management, we use boost::visit_each + * (http://www.boost.org/doc/libs/1_37_0/doc/html/boost/visit_each.html) to + * inspect each argument of a boost::bind expression. (Although the visit_each + * mechanism was first introduced with the original Boost.Signals library, it + * was only later documented.) + * + * Cases: + * * At least one of the function's arguments is a boost::weak_ptr<T>. Pass + *   the corresponding shared_ptr to slot_type::track(). Ideally that would be + *   the object whose method we want to call, but in fact we do the same for + *   any weak_ptr we might find among the bound arguments. If we're passing + *   our bound method a weak_ptr to some object, wouldn't the destruction of + *   that object invalidate the call? So we disconnect automatically when any + *   such object is destroyed. This is the mechanism preferred by boost:: + *   signals2. + * * One of the functions's arguments is a boost::shared_ptr<T>. This produces + *   a compile error: the bound copy of the shared_ptr stored in the + *   boost_bind object stored in the signal object would make the referenced + *   T object immortal. We provide a weaken() function. Pass + *   weaken(your_shared_ptr) instead. (We can inspect, but not modify, the + *   boost::bind object. Otherwise we'd replace the shared_ptr with weak_ptr + *   implicitly and just proceed.) + * * One of the function's arguments is a plain pointer/reference to an object + *   derived from boost::enable_shared_from_this. We assume that this object + *   is managed using boost::shared_ptr, so we implicitly extract a shared_ptr + *   and track that. (UNDER CONSTRUCTION) + * * One of the function's arguments is derived from LLEventTrackable. Pass + *   the LLBoundListener to its LLEventTrackable::track(). This is vulnerable + *   to a couple different race conditions, as described in LLEventTrackable + *   documentation. (NOTE: Now that LLEventTrackable is a typedef for + *   boost::signals2::trackable, the Signals2 library handles this itself, so + *   our visitor needs no special logic for this case.) + * * Any other argument type is irrelevant to automatic connection management. + */ + +namespace LLEventDetail +{ +    template <typename F> +    const F& unwrap(const F& f) { return f; } + +    template <typename F> +    const F& unwrap(const boost::reference_wrapper<F>& f) { return f.get(); } + +    // Most of the following is lifted from the Boost.Signals use of +    // visit_each. +    template<bool Cond> struct truth {}; + +    /** +     * boost::visit_each() Visitor, used on a template argument <tt>const F& +     * f</tt> as follows (see visit_and_connect()): +     * @code +     * LLEventListener listener(f); +     * Visitor visitor(listener); // bind listener so it can track() shared_ptrs +     * using boost::visit_each;   // allow unqualified visit_each() call for ADL +     * visit_each(visitor, unwrap(f)); +     * @endcode +     */ +    class Visitor +    { +    public: +        /** +         * Visitor binds a reference to LLEventListener so we can track() any +         * shared_ptrs we find in the argument list. +         */ +        Visitor(LLEventListener& listener): +            mListener(listener) +        { +        } + +        /** +         * boost::visit_each() calls this method for each component of a +         * boost::bind() expression. +         */ +        template <typename T> +        void operator()(const T& t) const +        { +            decode(t, 0); +        } + +    private: +        // decode() decides between a reference wrapper and anything else +        // boost::ref() variant +        template<typename T> +        void decode(const boost::reference_wrapper<T>& t, int) const +        { +//          add_if_trackable(t.get_pointer()); +        } + +        // decode() anything else +        template<typename T> +        void decode(const T& t, long) const +        { +            typedef truth<(boost::is_pointer<T>::value)> is_a_pointer; +            maybe_get_pointer(t, is_a_pointer()); +        } + +        // maybe_get_pointer() decides between a pointer and a non-pointer +        // plain pointer variant +        template<typename T> +        void maybe_get_pointer(const T& t, truth<true>) const +        { +//          add_if_trackable(t); +        } + +        // shared_ptr variant +        template<typename T> +        void maybe_get_pointer(const boost::shared_ptr<T>& t, truth<false>) const +        { +            // If we have a shared_ptr to this object, it doesn't matter +            // whether the object is derived from LLEventTrackable, so no +            // further analysis of T is needed. +//          mListener.track(t); + +            // Make this case illegal. Passing a bound shared_ptr to +            // slot_type::track() is useless, since the bound shared_ptr will +            // keep the object alive anyway! Force the coder to cast to weak_ptr. + +            // Trivial as it is, make the BOOST_STATIC_ASSERT() condition +            // dependent on template param so the macro is only evaluated if +            // this method is in fact instantiated, as described here: +            // http://www.boost.org/doc/libs/1_34_1/doc/html/boost_staticassert.html + +            // ATTENTION: Don't bind a shared_ptr<anything> using +            // LLEventPump::listen(boost::bind()). Doing so captures a copy of +            // the shared_ptr, making the referenced object effectively +            // immortal. Use the weaken() function, e.g.: +            // somepump.listen(boost::bind(...weaken(my_shared_ptr)...)); +            // This lets us automatically disconnect when the referenced +            // object is destroyed. +            BOOST_STATIC_ASSERT(sizeof(T) == 0); +        } + +        // weak_ptr variant +        template<typename T> +        void maybe_get_pointer(const boost::weak_ptr<T>& t, truth<false>) const +        { +            // If we have a weak_ptr to this object, it doesn't matter +            // whether the object is derived from LLEventTrackable, so no +            // further analysis of T is needed. +            mListener.track(t); +//          std::cout << "Found weak_ptr<" << typeid(T).name() << ">!\n"; +        } + +#if 0 +        // reference to anything derived from boost::enable_shared_from_this +        template <typename T> +        inline void maybe_get_pointer(const boost::enable_shared_from_this<T>& ct, +                                      truth<false>) const +        { +            // Use the slot_type::track(shared_ptr) mechanism. Cast away +            // const-ness because (in our code base anyway) it's unusual +            // to find shared_ptr<const T>. +            boost::enable_shared_from_this<T>& +                t(const_cast<boost::enable_shared_from_this<T>&>(ct)); +            std::cout << "Capturing shared_from_this()" << std::endl; +            boost::shared_ptr<T> sp(t.shared_from_this()); +/*==========================================================================*| +            std::cout << "Capturing weak_ptr" << std::endl; +            boost::weak_ptr<T> wp(sp); +|*==========================================================================*/ +            std::cout << "Tracking shared__ptr" << std::endl; +            mListener.track(sp); +        } +#endif + +        // non-pointer variant +        template<typename T> +        void maybe_get_pointer(const T& t, truth<false>) const +        { +            // Take the address of this object, because the object itself may be +            // trackable +//          add_if_trackable(boost::addressof(t)); +        } + +/*==========================================================================*| +        // add_if_trackable() adds LLEventTrackable objects to mTrackables +        inline void add_if_trackable(const LLEventTrackable* t) const +        { +            if (t) +            { +            } +        } + +        // pointer to anything not an LLEventTrackable subclass +        inline void add_if_trackable(const void*) const +        { +        } + +        // pointer to free function +        // The following construct uses the preprocessor to generate +        // add_if_trackable() overloads accepting pointer-to-function taking +        // 0, 1, ..., LLEVENTS_LISTENER_ARITY parameters of arbitrary type. +#define BOOST_PP_LOCAL_MACRO(n)                                     \ +        template <typename R                                        \ +                  BOOST_PP_COMMA_IF(n)                              \ +                  BOOST_PP_ENUM_PARAMS(n, typename T)>              \ +        inline void                                                 \ +        add_if_trackable(R (*)(BOOST_PP_ENUM_PARAMS(n, T))) const   \ +        {                                                           \ +        } +#define BOOST_PP_LOCAL_LIMITS (0, LLEVENTS_LISTENER_ARITY) +#include BOOST_PP_LOCAL_ITERATE() +#undef  BOOST_PP_LOCAL_MACRO +#undef  BOOST_PP_LOCAL_LIMITS +|*==========================================================================*/ + +        /// Bind a reference to the LLEventListener to call its track() method. +        LLEventListener& mListener; +    }; + +    /** +     * Utility template function to use Visitor appropriately +     * +     * @param raw_listener Callable to connect, typically a boost::bind() +     * expression. This will be visited by Visitor using boost::visit_each(). +     * @param connect_funct Callable that will connect() @a raw_listener to an +     * LLStandardSignal, returning LLBoundListener. +     */ +    template <typename LISTENER> +    LLBoundListener visit_and_connect(const LISTENER& raw_listener, +                                      const ConnectFunc& connect_func) +    { +        // Capture the listener +        LLEventListener listener(raw_listener); +        // Define our Visitor, binding the listener so we can call +        // listener.track() if we discover any shared_ptr<Foo>. +        LLEventDetail::Visitor visitor(listener); +        // Allow unqualified visit_each() call for ADL +        using boost::visit_each; +        // Visit each component of a boost::bind() expression. Pass +        // 'raw_listener', our template argument, rather than 'listener' from +        // which type details have been erased. unwrap() comes from +        // Boost.Signals, in case we were passed a boost::ref(). +        visit_each(visitor, LLEventDetail::unwrap(raw_listener)); +        // Make the connection using passed function. At present, wrapping +        // this functionality into this function is a bit silly: we don't +        // really need a visit_and_connect() function any more, just a visit() +        // function. The definition of this function dates from when, after +        // visit_each(), after establishing the connection, we had to +        // postprocess the new connection with the visitor object. That's no +        // longer necessary. +        return connect_func(listener); +    } +} // namespace LLEventDetail + +// Somewhat to my surprise, passing boost::bind(...boost::weak_ptr<T>...) to +// listen() fails in Boost code trying to instantiate LLEventListener (i.e. +// LLStandardSignal::slot_type) because the boost::get_pointer() utility function isn't +// specialized for boost::weak_ptr. This remedies that omission. +namespace boost +{ +    template <typename T> +    T* get_pointer(const weak_ptr<T>& ptr) { return shared_ptr<T>(ptr).get(); } +} + +/// Since we forbid use of listen(boost::bind(...shared_ptr<T>...)), provide an +/// easy way to cast to the corresponding weak_ptr. +template <typename T> +boost::weak_ptr<T> weaken(const boost::shared_ptr<T>& ptr) +{ +    return boost::weak_ptr<T>(ptr); +} + +#endif /* ! defined(LL_LLEVENTS_H) */ diff --git a/indra/llcommon/llfasttimer.h b/indra/llcommon/llfasttimer.h index 905d736d62..45b84ea3ea 100644 --- a/indra/llcommon/llfasttimer.h +++ b/indra/llcommon/llfasttimer.h @@ -1,317 +1,317 @@ -/** 
 - * @file llfasttimer.h
 - * @brief Declaration of a fast timer.
 - *
 - * $LicenseInfo:firstyear=2004&license=viewergpl$
 - * 
 - * Copyright (c) 2004-2009, Linden Research, Inc.
 - * 
 - * Second Life Viewer Source Code
 - * The source code in this file ("Source Code") is provided by Linden Lab
 - * to you under the terms of the GNU General Public License, version 2.0
 - * ("GPL"), unless you have obtained a separate licensing agreement
 - * ("Other License"), formally executed by you and Linden Lab.  Terms of
 - * the GPL can be found in doc/GPL-license.txt in this distribution, or
 - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
 - * 
 - * There are special exceptions to the terms and conditions of the GPL as
 - * it is applied to this Source Code. View the full text of the exception
 - * in the file doc/FLOSS-exception.txt in this software distribution, or
 - * online at
 - * http://secondlifegrid.net/programs/open_source/licensing/flossexception
 - * 
 - * By copying, modifying or distributing this software, you acknowledge
 - * that you have read and understood your obligations described above,
 - * and agree to abide by those obligations.
 - * 
 - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
 - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
 - * COMPLETENESS OR PERFORMANCE.
 - * $/LicenseInfo$
 - */
 -
 -#ifndef LL_FASTTIMER_H
 -#define LL_FASTTIMER_H
 -
 -#include "llinstancetracker.h"
 -
 -#define FAST_TIMER_ON 1
 -
 -#if LL_WINDOWS
 -
 -// shift off lower 8 bits for lower resolution but longer term timing
 -// on 1Ghz machine, a 32-bit word will hold ~1000 seconds of timing
 -inline U32 get_cpu_clock_count_32()
 -{
 -	U32 ret_val;
 -	__asm 
 -	{
 -        _emit   0x0f
 -        _emit   0x31
 -		shr eax,8
 -		shl edx,24
 -		or eax, edx
 -		mov dword ptr [ret_val], eax
 -	}
 -    return ret_val;
 -}
 -
 -// return full timer value, still shifted by 8 bits
 -inline U64 get_cpu_clock_count_64()
 -{
 -	U64 ret_val;
 -	__asm 
 -	{
 -        _emit   0x0f
 -        _emit   0x31
 -		mov eax,eax
 -		mov edx,edx
 -		mov dword ptr [ret_val+4], edx
 -		mov dword ptr [ret_val], eax
 -	}
 -    return ret_val >> 8;
 -}
 -
 -#endif // LL_WINDOWS
 -
 -#if (LL_LINUX || LL_SOLARIS || LL_DARWIN) && (defined(__i386__) || defined(__amd64__))
 -inline U32 get_cpu_clock_count_32()
 -{																	
 -	U64 x;															
 -	__asm__ volatile (".byte 0x0f, 0x31": "=A"(x));					
 -	return (U32)x >> 8;													
 -}
 -
 -inline U32 get_cpu_clock_count_64()
 -{																	
 -	U64 x;
 -	__asm__ volatile (".byte 0x0f, 0x31": "=A"(x));
 -	return x >> 8;
 -}
 -#endif
 -
 -#if ( LL_DARWIN && !(defined(__i386__) || defined(__amd64__))) || (LL_SOLARIS && defined(__sparc__))
 -//
 -// Mac PPC (deprecated) & Solaris SPARC implementation of CPU clock
 -//
 -// Just use gettimeofday implementation for now
 -
 -inline U32 get_cpu_clock_count_32()
 -{
 -	return (U32)get_clock_count();
 -}
 -
 -inline U32 get_cpu_clock_count_64()
 -{																	
 -	return get_clock_count();
 -}
 -#endif
 -
 -class LLMutex;
 -
 -#include <queue>
 -#include "llsd.h"
 -
 -
 -class LL_COMMON_API LLFastTimer
 -{
 -public:
 -	// stores a "named" timer instance to be reused via multiple LLFastTimer stack instances
 -	class LL_COMMON_API NamedTimer 
 -	:	public LLInstanceTracker<NamedTimer>
 -	{
 -		friend class DeclareTimer;
 -	public:
 -		~NamedTimer();
 -
 -		enum { HISTORY_NUM = 60 };
 -
 -		const std::string& getName() const { return mName; }
 -		NamedTimer* getParent() const { return mParent; }
 -		void setParent(NamedTimer* parent);
 -		S32 getDepth();
 -		std::string getToolTip(S32 history_index = -1);
 -
 -		typedef std::vector<NamedTimer*>::const_iterator child_const_iter;
 -		child_const_iter beginChildren();
 -		child_const_iter endChildren();
 -		std::vector<NamedTimer*>& getChildren();
 -
 -		void setCollapsed(bool collapsed) { mCollapsed = collapsed; }
 -		bool getCollapsed() const { return mCollapsed; }
 -
 -		U32 getCountAverage() const { return mCountAverage; }
 -		U32 getCallAverage() const { return mCallAverage; }
 -
 -		U32 getHistoricalCount(S32 history_index = 0) const;
 -		U32 getHistoricalCalls(S32 history_index = 0) const;
 -
 -		static NamedTimer& getRootNamedTimer();
 -
 -		struct FrameState
 -		{
 -			FrameState(NamedTimer* timerp);
 -
 -			U32 		mSelfTimeCounter;
 -			U32 		mCalls;
 -			FrameState*	mParent;		// info for caller timer
 -			FrameState*	mLastCaller;	// used to bootstrap tree construction
 -			NamedTimer*	mTimer;
 -			U16			mActiveCount;	// number of timers with this ID active on stack
 -			bool		mMoveUpTree;	// needs to be moved up the tree of timers at the end of frame
 -		};
 -
 -		S32 getFrameStateIndex() const { return mFrameStateIndex; }
 -
 -		FrameState& getFrameState() const;
 -
 -
 -	private: 
 -		friend class LLFastTimer;
 -		friend class NamedTimerFactory;
 -
 -		//
 -		// methods
 -		//
 -		NamedTimer(const std::string& name);
 -		// recursive call to gather total time from children
 -		static void accumulateTimings();
 -
 -		// updates cumulative times and hierarchy, 
 -		// can be called multiple times in a frame, at any point
 -		static void processTimes();
 -
 -		static void buildHierarchy();
 -		static void resetFrame();
 -		static void reset();
 -
 -	
 -		//
 -		// members
 -		//
 -		S32			mFrameStateIndex;
 -
 -		std::string	mName;
 -
 -		U32 		mTotalTimeCounter;
 -
 -		U32 		mCountAverage;
 -		U32			mCallAverage;
 -
 -		U32*		mCountHistory;
 -		U32*		mCallHistory;
 -
 -		// tree structure
 -		NamedTimer*					mParent;				// NamedTimer of caller(parent)
 -		std::vector<NamedTimer*>	mChildren;
 -		bool						mCollapsed;				// don't show children
 -		bool						mNeedsSorting;			// sort children whenever child added
 -
 -	};
 -
 -	// used to statically declare a new named timer
 -	class LL_COMMON_API DeclareTimer
 -	:	public LLInstanceTracker<DeclareTimer>
 -	{
 -	public:
 -		DeclareTimer(const std::string& name, bool open);
 -		DeclareTimer(const std::string& name);
 -
 -		static void updateCachedPointers();
 -
 -		// convertable to NamedTimer::FrameState for convenient usage of LLFastTimer(declared_timer)
 -		operator NamedTimer::FrameState&() { return *mFrameState; }
 -	private:
 -		NamedTimer&				mTimer;
 -		NamedTimer::FrameState* mFrameState; 
 -	};
 -
 -
 -public:
 -	static LLMutex* sLogLock;
 -	static std::queue<LLSD> sLogQueue;
 -	static BOOL sLog;
 -	static BOOL sMetricLog;
 -
 -	typedef std::vector<NamedTimer::FrameState> info_list_t;
 -	static info_list_t& getFrameStateList();
 -
 -	enum RootTimerMarker { ROOT };
 -	LLFastTimer(RootTimerMarker);
 -
 -	LLFastTimer(NamedTimer::FrameState& timer)
 -	:	mFrameState(&timer)
 -	{
 -#if FAST_TIMER_ON
 -		NamedTimer::FrameState* frame_state = &timer;
 -		U32 cur_time = get_cpu_clock_count_32();
 -		mStartSelfTime = cur_time;
 -		mStartTotalTime = cur_time;
 -
 -		frame_state->mActiveCount++;
 -		frame_state->mCalls++;
 -		// keep current parent as long as it is active when we are
 -		frame_state->mMoveUpTree |= (frame_state->mParent->mActiveCount == 0);
 -	
 -		mLastTimer = sCurTimer;
 -		sCurTimer = this;
 -#endif
 -	}
 -
 -	~LLFastTimer()
 -	{
 -#if FAST_TIMER_ON
 -		NamedTimer::FrameState* frame_state = mFrameState;
 -		U32 cur_time = get_cpu_clock_count_32();
 -		frame_state->mSelfTimeCounter += cur_time - mStartSelfTime;
 -
 -		frame_state->mActiveCount--;
 -		LLFastTimer* last_timer = mLastTimer;
 -		sCurTimer = last_timer;
 -
 -		// store last caller to bootstrap tree creation
 -		frame_state->mLastCaller = last_timer->mFrameState;
 -
 -		// we are only tracking self time, so subtract our total time delta from parents
 -		U32 total_time = cur_time - mStartTotalTime;
 -		last_timer->mStartSelfTime += total_time;
 -#endif
 -	}
 -
 -
 -	// call this once a frame to reset timers
 -	static void nextFrame();
 -
 -	// dumps current cumulative frame stats to log
 -	// call nextFrame() to reset timers
 -	static void dumpCurTimes(); 
 -
 -	// call this to reset timer hierarchy, averages, etc.
 -	static void reset();
 -
 -	static U64 countsPerSecond();
 -	static S32 getLastFrameIndex() { return sLastFrameIndex; }
 -	static S32 getCurFrameIndex() { return sCurFrameIndex; }
 -
 -	static void writeLog(std::ostream& os);
 -	static const NamedTimer* getTimerByName(const std::string& name);
 -
 -public:
 -	static bool 		sPauseHistory;
 -	static bool 		sResetHistory;
 -	
 -private:
 -	typedef std::vector<LLFastTimer*> timer_stack_t;
 -	static LLFastTimer*		sCurTimer;
 -	static S32				sCurFrameIndex;
 -	static S32				sLastFrameIndex;
 -	static U64				sLastFrameTime;
 -	static info_list_t*		sTimerInfos;
 -
 -	U32						mStartSelfTime;	// start time + time of all child timers
 -	U32						mStartTotalTime;	// start time + time of all child timers
 -	NamedTimer::FrameState*	mFrameState;
 -	LLFastTimer*			mLastTimer;
 -};
 -
 -#endif // LL_LLFASTTIMER_H
 +/**  + * @file llfasttimer.h + * @brief Declaration of a fast timer. + * + * $LicenseInfo:firstyear=2004&license=viewergpl$ + *  + * Copyright (c) 2004-2009, Linden Research, Inc. + *  + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab.  Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + *  + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + *  + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + *  + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_FASTTIMER_H +#define LL_FASTTIMER_H + +#include "llinstancetracker.h" + +#define FAST_TIMER_ON 1 + +#if LL_WINDOWS + +// shift off lower 8 bits for lower resolution but longer term timing +// on 1Ghz machine, a 32-bit word will hold ~1000 seconds of timing +inline U32 get_cpu_clock_count_32() +{ +	U32 ret_val; +	__asm  +	{ +        _emit   0x0f +        _emit   0x31 +		shr eax,8 +		shl edx,24 +		or eax, edx +		mov dword ptr [ret_val], eax +	} +    return ret_val; +} + +// return full timer value, still shifted by 8 bits +inline U64 get_cpu_clock_count_64() +{ +	U64 ret_val; +	__asm  +	{ +        _emit   0x0f +        _emit   0x31 +		mov eax,eax +		mov edx,edx +		mov dword ptr [ret_val+4], edx +		mov dword ptr [ret_val], eax +	} +    return ret_val >> 8; +} + +#endif // LL_WINDOWS + +#if (LL_LINUX || LL_SOLARIS || LL_DARWIN) && (defined(__i386__) || defined(__amd64__)) +inline U32 get_cpu_clock_count_32() +{																	 +	U64 x;															 +	__asm__ volatile (".byte 0x0f, 0x31": "=A"(x));					 +	return (U32)x >> 8;													 +} + +inline U32 get_cpu_clock_count_64() +{																	 +	U64 x; +	__asm__ volatile (".byte 0x0f, 0x31": "=A"(x)); +	return x >> 8; +} +#endif + +#if ( LL_DARWIN && !(defined(__i386__) || defined(__amd64__))) || (LL_SOLARIS && defined(__sparc__)) +// +// Mac PPC (deprecated) & Solaris SPARC implementation of CPU clock +// +// Just use gettimeofday implementation for now + +inline U32 get_cpu_clock_count_32() +{ +	return (U32)get_clock_count(); +} + +inline U32 get_cpu_clock_count_64() +{																	 +	return get_clock_count(); +} +#endif + +class LLMutex; + +#include <queue> +#include "llsd.h" + + +class LL_COMMON_API LLFastTimer +{ +public: +	// stores a "named" timer instance to be reused via multiple LLFastTimer stack instances +	class LL_COMMON_API NamedTimer  +	:	public LLInstanceTracker<NamedTimer> +	{ +		friend class DeclareTimer; +	public: +		~NamedTimer(); + +		enum { HISTORY_NUM = 60 }; + +		const std::string& getName() const { return mName; } +		NamedTimer* getParent() const { return mParent; } +		void setParent(NamedTimer* parent); +		S32 getDepth(); +		std::string getToolTip(S32 history_index = -1); + +		typedef std::vector<NamedTimer*>::const_iterator child_const_iter; +		child_const_iter beginChildren(); +		child_const_iter endChildren(); +		std::vector<NamedTimer*>& getChildren(); + +		void setCollapsed(bool collapsed) { mCollapsed = collapsed; } +		bool getCollapsed() const { return mCollapsed; } + +		U32 getCountAverage() const { return mCountAverage; } +		U32 getCallAverage() const { return mCallAverage; } + +		U32 getHistoricalCount(S32 history_index = 0) const; +		U32 getHistoricalCalls(S32 history_index = 0) const; + +		static NamedTimer& getRootNamedTimer(); + +		struct FrameState +		{ +			FrameState(NamedTimer* timerp); + +			U32 		mSelfTimeCounter; +			U32 		mCalls; +			FrameState*	mParent;		// info for caller timer +			FrameState*	mLastCaller;	// used to bootstrap tree construction +			NamedTimer*	mTimer; +			U16			mActiveCount;	// number of timers with this ID active on stack +			bool		mMoveUpTree;	// needs to be moved up the tree of timers at the end of frame +		}; + +		S32 getFrameStateIndex() const { return mFrameStateIndex; } + +		FrameState& getFrameState() const; + + +	private:  +		friend class LLFastTimer; +		friend class NamedTimerFactory; + +		// +		// methods +		// +		NamedTimer(const std::string& name); +		// recursive call to gather total time from children +		static void accumulateTimings(); + +		// updates cumulative times and hierarchy,  +		// can be called multiple times in a frame, at any point +		static void processTimes(); + +		static void buildHierarchy(); +		static void resetFrame(); +		static void reset(); + +	 +		// +		// members +		// +		S32			mFrameStateIndex; + +		std::string	mName; + +		U32 		mTotalTimeCounter; + +		U32 		mCountAverage; +		U32			mCallAverage; + +		U32*		mCountHistory; +		U32*		mCallHistory; + +		// tree structure +		NamedTimer*					mParent;				// NamedTimer of caller(parent) +		std::vector<NamedTimer*>	mChildren; +		bool						mCollapsed;				// don't show children +		bool						mNeedsSorting;			// sort children whenever child added + +	}; + +	// used to statically declare a new named timer +	class LL_COMMON_API DeclareTimer +	:	public LLInstanceTracker<DeclareTimer> +	{ +	public: +		DeclareTimer(const std::string& name, bool open); +		DeclareTimer(const std::string& name); + +		static void updateCachedPointers(); + +		// convertable to NamedTimer::FrameState for convenient usage of LLFastTimer(declared_timer) +		operator NamedTimer::FrameState&() { return *mFrameState; } +	private: +		NamedTimer&				mTimer; +		NamedTimer::FrameState* mFrameState;  +	}; + + +public: +	static LLMutex* sLogLock; +	static std::queue<LLSD> sLogQueue; +	static BOOL sLog; +	static BOOL sMetricLog; + +	typedef std::vector<NamedTimer::FrameState> info_list_t; +	static info_list_t& getFrameStateList(); + +	enum RootTimerMarker { ROOT }; +	LLFastTimer(RootTimerMarker); + +	LLFastTimer(NamedTimer::FrameState& timer) +	:	mFrameState(&timer) +	{ +#if FAST_TIMER_ON +		NamedTimer::FrameState* frame_state = &timer; +		U32 cur_time = get_cpu_clock_count_32(); +		mStartSelfTime = cur_time; +		mStartTotalTime = cur_time; + +		frame_state->mActiveCount++; +		frame_state->mCalls++; +		// keep current parent as long as it is active when we are +		frame_state->mMoveUpTree |= (frame_state->mParent->mActiveCount == 0); +	 +		mLastTimer = sCurTimer; +		sCurTimer = this; +#endif +	} + +	~LLFastTimer() +	{ +#if FAST_TIMER_ON +		NamedTimer::FrameState* frame_state = mFrameState; +		U32 cur_time = get_cpu_clock_count_32(); +		frame_state->mSelfTimeCounter += cur_time - mStartSelfTime; + +		frame_state->mActiveCount--; +		LLFastTimer* last_timer = mLastTimer; +		sCurTimer = last_timer; + +		// store last caller to bootstrap tree creation +		frame_state->mLastCaller = last_timer->mFrameState; + +		// we are only tracking self time, so subtract our total time delta from parents +		U32 total_time = cur_time - mStartTotalTime; +		last_timer->mStartSelfTime += total_time; +#endif +	} + + +	// call this once a frame to reset timers +	static void nextFrame(); + +	// dumps current cumulative frame stats to log +	// call nextFrame() to reset timers +	static void dumpCurTimes();  + +	// call this to reset timer hierarchy, averages, etc. +	static void reset(); + +	static U64 countsPerSecond(); +	static S32 getLastFrameIndex() { return sLastFrameIndex; } +	static S32 getCurFrameIndex() { return sCurFrameIndex; } + +	static void writeLog(std::ostream& os); +	static const NamedTimer* getTimerByName(const std::string& name); + +public: +	static bool 		sPauseHistory; +	static bool 		sResetHistory; +	 +private: +	typedef std::vector<LLFastTimer*> timer_stack_t; +	static LLFastTimer*		sCurTimer; +	static S32				sCurFrameIndex; +	static S32				sLastFrameIndex; +	static U64				sLastFrameTime; +	static info_list_t*		sTimerInfos; + +	U32						mStartSelfTime;	// start time + time of all child timers +	U32						mStartTotalTime;	// start time + time of all child timers +	NamedTimer::FrameState*	mFrameState; +	LLFastTimer*			mLastTimer; +}; + +#endif // LL_LLFASTTIMER_H diff --git a/indra/llcommon/llfoldertype.cpp b/indra/llcommon/llfoldertype.cpp new file mode 100644 index 0000000000..9107b11597 --- /dev/null +++ b/indra/llcommon/llfoldertype.cpp @@ -0,0 +1,165 @@ +/**  + * @file llfoldertype.cpp + * @brief Implementatino of LLFolderType functionality. + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + *  + * Copyright (c) 2001-2009, Linden Research, Inc. + *  + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab.  Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + *  + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + *  + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + *  + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "llfoldertype.h" +#include "lldictionary.h" +#include "llmemory.h" +#include "llsingleton.h" + +///---------------------------------------------------------------------------- +/// Class LLFolderType +///---------------------------------------------------------------------------- +struct FolderEntry : public LLDictionaryEntry +{ +	FolderEntry(const std::string &type_name, // 8 character limit! +				bool is_protected) // can the viewer change categories of this type? +		: +	LLDictionaryEntry(type_name), +	mIsProtected(is_protected) +	{ +		llassert(type_name.length() <= 8); +	} + +	const bool mIsProtected; +}; + +class LLFolderDictionary : public LLSingleton<LLFolderDictionary>, +						   public LLDictionary<LLFolderType::EType, FolderEntry> +{ +public: +	LLFolderDictionary(); +}; + +LLFolderDictionary::LLFolderDictionary() +{ +	//       													    TYPE NAME	PROTECTED +	//      													   |-----------|---------| +	addEntry(LLFolderType::FT_TEXTURE, 				new FolderEntry("texture",	TRUE)); +	addEntry(LLFolderType::FT_SOUND, 				new FolderEntry("sound",	TRUE)); +	addEntry(LLFolderType::FT_CALLINGCARD, 			new FolderEntry("callcard",	TRUE)); +	addEntry(LLFolderType::FT_LANDMARK, 			new FolderEntry("landmark",	TRUE)); +	addEntry(LLFolderType::FT_CLOTHING, 			new FolderEntry("clothing",	TRUE)); +	addEntry(LLFolderType::FT_OBJECT, 				new FolderEntry("object",	TRUE)); +	addEntry(LLFolderType::FT_NOTECARD, 			new FolderEntry("notecard",	TRUE)); +	addEntry(LLFolderType::FT_CATEGORY, 			new FolderEntry("category",	TRUE)); +	addEntry(LLFolderType::FT_ROOT_CATEGORY, 		new FolderEntry("root",		TRUE)); +	addEntry(LLFolderType::FT_LSL_TEXT, 			new FolderEntry("lsltext",	TRUE)); +	addEntry(LLFolderType::FT_BODYPART, 			new FolderEntry("bodypart",	TRUE)); +	addEntry(LLFolderType::FT_TRASH, 				new FolderEntry("trash",	TRUE)); +	addEntry(LLFolderType::FT_SNAPSHOT_CATEGORY, 	new FolderEntry("snapshot", TRUE)); +	addEntry(LLFolderType::FT_LOST_AND_FOUND, 		new FolderEntry("lstndfnd",	TRUE)); +	addEntry(LLFolderType::FT_ANIMATION, 			new FolderEntry("animatn",	TRUE)); +	addEntry(LLFolderType::FT_GESTURE, 				new FolderEntry("gesture",	TRUE)); +	addEntry(LLFolderType::FT_FAVORITE, 			new FolderEntry("favorite",	TRUE)); +	 +	for (S32 ensemble_num = S32(LLFolderType::FT_ENSEMBLE_START); ensemble_num <= S32(LLFolderType::FT_ENSEMBLE_END); ensemble_num++) +	{ +		addEntry(LLFolderType::EType(ensemble_num), new FolderEntry("ensemble", FALSE));  +	} + +	addEntry(LLFolderType::FT_CURRENT_OUTFIT, 		new FolderEntry("current",	TRUE)); +	addEntry(LLFolderType::FT_OUTFIT, 				new FolderEntry("outfit",	FALSE)); +	addEntry(LLFolderType::FT_MY_OUTFITS, 			new FolderEntry("my_otfts",	TRUE)); +	addEntry(LLFolderType::FT_INBOX, 				new FolderEntry("inbox",	TRUE)); +		  +	addEntry(LLFolderType::FT_NONE, 				new FolderEntry("-1",		FALSE)); +}; + +// static +LLFolderType::EType LLFolderType::lookup(const std::string& name) +{ +	return LLFolderDictionary::getInstance()->lookup(name); +} + +// static +const std::string &LLFolderType::lookup(LLFolderType::EType folder_type) +{ +	const FolderEntry *entry = LLFolderDictionary::getInstance()->lookup(folder_type); +	if (entry) +	{ +		return entry->mName; +	} +	else +	{ +		return badLookup(); +	} +} + +// static +// Only ensembles and plain folders aren't protected.  "Protected" means +// you can't change certain properties such as their type. +bool LLFolderType::lookupIsProtectedType(EType folder_type) +{ +	const LLFolderDictionary *dict = LLFolderDictionary::getInstance(); +	const FolderEntry *entry = dict->lookup(folder_type); +	if (entry) +	{ +		return entry->mIsProtected; +	} +	return true; +} + +// static +bool LLFolderType::lookupIsEnsembleType(EType folder_type) +{ +	return (folder_type >= FT_ENSEMBLE_START && +			folder_type <= FT_ENSEMBLE_END); +} + +// static +LLAssetType::EType LLFolderType::folderTypeToAssetType(LLFolderType::EType folder_type) +{ +	if (LLAssetType::lookup(LLAssetType::EType(folder_type)) == LLAssetType::badLookup()) +	{ +		llwarns << "Converting to unknown asset type " << folder_type << llendl; +	} +	return (LLAssetType::EType)folder_type; +} + +// static +LLFolderType::EType LLFolderType::assetTypeToFolderType(LLAssetType::EType asset_type) +{ +	if (LLFolderType::lookup(LLFolderType::EType(asset_type)) == LLFolderType::badLookup()) +	{ +		llwarns << "Converting to unknown folder type " << asset_type << llendl; +	} +	return (LLFolderType::EType)asset_type; +} + +// static +const std::string &LLFolderType::badLookup() +{ +	static const std::string sBadLookup = "llfoldertype_bad_lookup"; +	return sBadLookup; +} diff --git a/indra/llcommon/llfoldertype.h b/indra/llcommon/llfoldertype.h new file mode 100644 index 0000000000..5374ffd829 --- /dev/null +++ b/indra/llcommon/llfoldertype.h @@ -0,0 +1,123 @@ +/**  + * @file llfoldertype.h + * @brief Declaration of LLFolderType. + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + *  + * Copyright (c) 2001-2009, Linden Research, Inc. + *  + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab.  Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + *  + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + *  + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + *  + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLFOLDERTYPE_H +#define LL_LLFOLDERTYPE_H + +#include <string> +#include "llassettype.h" + +// This class handles folder types (similar to assettype, except for folders) +// and operations on those. +class LL_COMMON_API LLFolderType +{ +public: +	// ! BACKWARDS COMPATIBILITY ! Folder type enums must match asset type enums. +	enum EType +	{ +		FT_TEXTURE = 0, + +		FT_SOUND = 1,  + +		FT_CALLINGCARD = 2, + +		FT_LANDMARK = 3, + +		// FT_SCRIPT = 4, + +		FT_CLOTHING = 5, + +		FT_OBJECT = 6, + +		FT_NOTECARD = 7, + +		FT_CATEGORY = 8, + +		FT_ROOT_CATEGORY = 9, + +		FT_LSL_TEXT = 10, + +		// FT_LSL_BYTECODE = 11, +		// FT_TEXTURE_TGA = 12, + +		FT_BODYPART = 13, + +		FT_TRASH = 14, + +		FT_SNAPSHOT_CATEGORY = 15, + +		FT_LOST_AND_FOUND = 16, + +		// FT_SOUND_WAV = 17, +		// FT_IMAGE_TGA = 18, +		// FT_IMAGE_JPEG = 19, + +		FT_ANIMATION = 20, + +		FT_GESTURE = 21, + +		// FT_SIMSTATE = 22, + +		FT_FAVORITE = 23, + +		FT_ENSEMBLE_START = 26, +		FT_ENSEMBLE_END = 45, +			// This range is reserved for special clothing folder types. + +		FT_CURRENT_OUTFIT = 46, +		FT_OUTFIT = 47, +		FT_MY_OUTFITS = 48, +		 +		FT_INBOX = 49, + +		FT_COUNT = 50, + +		FT_NONE = -1 +	}; + +	static EType 				lookup(const std::string& type_name); +	static const std::string&	lookup(EType folder_type); + +	static bool 				lookupIsProtectedType(EType folder_type); +	static bool 				lookupIsEnsembleType(EType folder_type); + +	static LLAssetType::EType	folderTypeToAssetType(LLFolderType::EType folder_type); +	static LLFolderType::EType	assetTypeToFolderType(LLAssetType::EType asset_type); + +	static const std::string&	badLookup(); // error string when a lookup fails + +protected: +	LLFolderType() {} +	~LLFolderType() {} +}; + +#endif // LL_LLFOLDERTYPE_H diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h index 09f19532b7..1c6f64dd8b 100644 --- a/indra/llcommon/llmemory.h +++ b/indra/llcommon/llmemory.h @@ -1,65 +1,65 @@ -/** 
 - * @file llmemory.h
 - * @brief Memory allocation/deallocation header-stuff goes here.
 - *
 - * $LicenseInfo:firstyear=2002&license=viewergpl$
 - * 
 - * Copyright (c) 2002-2009, Linden Research, Inc.
 - * 
 - * Second Life Viewer Source Code
 - * The source code in this file ("Source Code") is provided by Linden Lab
 - * to you under the terms of the GNU General Public License, version 2.0
 - * ("GPL"), unless you have obtained a separate licensing agreement
 - * ("Other License"), formally executed by you and Linden Lab.  Terms of
 - * the GPL can be found in doc/GPL-license.txt in this distribution, or
 - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
 - * 
 - * There are special exceptions to the terms and conditions of the GPL as
 - * it is applied to this Source Code. View the full text of the exception
 - * in the file doc/FLOSS-exception.txt in this software distribution, or
 - * online at
 - * http://secondlifegrid.net/programs/open_source/licensing/flossexception
 - * 
 - * By copying, modifying or distributing this software, you acknowledge
 - * that you have read and understood your obligations described above,
 - * and agree to abide by those obligations.
 - * 
 - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
 - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
 - * COMPLETENESS OR PERFORMANCE.
 - * $/LicenseInfo$
 - */
 -#ifndef LLMEMORY_H
 -#define LLMEMORY_H
 -
 -
 -
 -extern S32 gTotalDAlloc;
 -extern S32 gTotalDAUse;
 -extern S32 gDACount;
 -
 -extern void* ll_allocate (size_t size);
 -extern void ll_release (void *p);
 -
 -class LL_COMMON_API LLMemory
 -{
 -public:
 -	static void initClass();
 -	static void cleanupClass();
 -	static void freeReserve();
 -	// Return the resident set size of the current process, in bytes.
 -	// Return value is zero if not known.
 -	static U64 getCurrentRSS();
 -private:
 -	static char* reserveMem;
 -};
 -
 -// LLRefCount moved to llrefcount.h
 -
 -// LLPointer moved to llpointer.h
 -
 -// LLSafeHandle moved to llsafehandle.h
 -
 -// LLSingleton moved to llsingleton.h
 -
 -#endif
 +/**  + * @file llmemory.h + * @brief Memory allocation/deallocation header-stuff goes here. + * + * $LicenseInfo:firstyear=2002&license=viewergpl$ + *  + * Copyright (c) 2002-2009, Linden Research, Inc. + *  + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab.  Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + *  + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + *  + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + *  + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ +#ifndef LLMEMORY_H +#define LLMEMORY_H + + + +extern S32 gTotalDAlloc; +extern S32 gTotalDAUse; +extern S32 gDACount; + +extern void* ll_allocate (size_t size); +extern void ll_release (void *p); + +class LL_COMMON_API LLMemory +{ +public: +	static void initClass(); +	static void cleanupClass(); +	static void freeReserve(); +	// Return the resident set size of the current process, in bytes. +	// Return value is zero if not known. +	static U64 getCurrentRSS(); +private: +	static char* reserveMem; +}; + +// LLRefCount moved to llrefcount.h + +// LLPointer moved to llpointer.h + +// LLSafeHandle moved to llsafehandle.h + +// LLSingleton moved to llsingleton.h + +#endif diff --git a/indra/llcommon/llmemtype.h b/indra/llcommon/llmemtype.h index 5952a3a7c5..677fad3034 100644 --- a/indra/llcommon/llmemtype.h +++ b/indra/llcommon/llmemtype.h @@ -1,248 +1,248 @@ -/** 
 - * @file llmemtype.h
 - * @brief Runtime memory usage debugging utilities.
 - *
 - * $LicenseInfo:firstyear=2005&license=viewergpl$
 - * 
 - * Copyright (c) 2005-2009, Linden Research, Inc.
 - * 
 - * Second Life Viewer Source Code
 - * The source code in this file ("Source Code") is provided by Linden Lab
 - * to you under the terms of the GNU General Public License, version 2.0
 - * ("GPL"), unless you have obtained a separate licensing agreement
 - * ("Other License"), formally executed by you and Linden Lab.  Terms of
 - * the GPL can be found in doc/GPL-license.txt in this distribution, or
 - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
 - * 
 - * There are special exceptions to the terms and conditions of the GPL as
 - * it is applied to this Source Code. View the full text of the exception
 - * in the file doc/FLOSS-exception.txt in this software distribution, or
 - * online at
 - * http://secondlifegrid.net/programs/open_source/licensing/flossexception
 - * 
 - * By copying, modifying or distributing this software, you acknowledge
 - * that you have read and understood your obligations described above,
 - * and agree to abide by those obligations.
 - * 
 - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
 - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
 - * COMPLETENESS OR PERFORMANCE.
 - * $/LicenseInfo$
 - */
 -
 -#ifndef LL_MEMTYPE_H
 -#define LL_MEMTYPE_H
 -
 -//----------------------------------------------------------------------------
 -//----------------------------------------------------------------------------
 -
 -//----------------------------------------------------------------------------
 -
 -#include "linden_common.h"
 -//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 -// WARNING: Never commit with MEM_TRACK_MEM == 1
 -//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
 -#define MEM_TRACK_MEM (0 && LL_WINDOWS)
 -
 -#include <vector>
 -
 -#define MEM_TYPE_NEW(T)
 -
 -class LL_COMMON_API LLMemType
 -{
 -public:
 -
 -	// class we'll initialize all instances of as
 -	// static members of MemType.  Then use
 -	// to construct any new mem type.
 -	class LL_COMMON_API DeclareMemType
 -	{
 -	public:
 -		DeclareMemType(char const * st);
 -		~DeclareMemType();
 -	
 -		S32 mID;
 -		char const * mName;
 -		
 -		// array so we can map an index ID to Name
 -		static std::vector<char const *> mNameList;
 -	};
 -
 -	LLMemType(DeclareMemType& dt);
 -	~LLMemType();
 -
 -	static char const * getNameFromID(S32 id);
 -
 -	static DeclareMemType MTYPE_INIT;
 -	static DeclareMemType MTYPE_STARTUP;
 -	static DeclareMemType MTYPE_MAIN;
 -	static DeclareMemType MTYPE_FRAME;
 -
 -	static DeclareMemType MTYPE_GATHER_INPUT;
 -	static DeclareMemType MTYPE_JOY_KEY;
 -
 -	static DeclareMemType MTYPE_IDLE;
 -	static DeclareMemType MTYPE_IDLE_PUMP;
 -	static DeclareMemType MTYPE_IDLE_NETWORK;
 -	static DeclareMemType MTYPE_IDLE_UPDATE_REGIONS;
 -	static DeclareMemType MTYPE_IDLE_UPDATE_VIEWER_REGION;
 -	static DeclareMemType MTYPE_IDLE_UPDATE_SURFACE;
 -	static DeclareMemType MTYPE_IDLE_UPDATE_PARCEL_OVERLAY;
 -	static DeclareMemType MTYPE_IDLE_AUDIO;
 -
 -	static DeclareMemType MTYPE_CACHE_PROCESS_PENDING;
 -	static DeclareMemType MTYPE_CACHE_PROCESS_PENDING_ASKS;
 -	static DeclareMemType MTYPE_CACHE_PROCESS_PENDING_REPLIES;
 -
 -	static DeclareMemType MTYPE_MESSAGE_CHECK_ALL;
 -	static DeclareMemType MTYPE_MESSAGE_PROCESS_ACKS;
 -
 -	static DeclareMemType MTYPE_RENDER;
 -	static DeclareMemType MTYPE_SLEEP;
 -
 -	static DeclareMemType MTYPE_NETWORK;
 -	static DeclareMemType MTYPE_PHYSICS;
 -	static DeclareMemType MTYPE_INTERESTLIST;
 -
 -	static DeclareMemType MTYPE_IMAGEBASE;
 -	static DeclareMemType MTYPE_IMAGERAW;
 -	static DeclareMemType MTYPE_IMAGEFORMATTED;
 -	
 -	static DeclareMemType MTYPE_APPFMTIMAGE;
 -	static DeclareMemType MTYPE_APPRAWIMAGE;
 -	static DeclareMemType MTYPE_APPAUXRAWIMAGE;
 -	
 -	static DeclareMemType MTYPE_DRAWABLE;
 -	
 -	static DeclareMemType MTYPE_OBJECT;
 -	static DeclareMemType MTYPE_OBJECT_PROCESS_UPDATE;
 -	static DeclareMemType MTYPE_OBJECT_PROCESS_UPDATE_CORE;
 -
 -	static DeclareMemType MTYPE_DISPLAY;
 -	static DeclareMemType MTYPE_DISPLAY_UPDATE;
 -	static DeclareMemType MTYPE_DISPLAY_UPDATE_CAMERA;
 -	static DeclareMemType MTYPE_DISPLAY_UPDATE_GEOM;
 -	static DeclareMemType MTYPE_DISPLAY_SWAP;
 -	static DeclareMemType MTYPE_DISPLAY_UPDATE_HUD;
 -	static DeclareMemType MTYPE_DISPLAY_GEN_REFLECTION;
 -	static DeclareMemType MTYPE_DISPLAY_IMAGE_UPDATE;
 -	static DeclareMemType MTYPE_DISPLAY_STATE_SORT;
 -	static DeclareMemType MTYPE_DISPLAY_SKY;
 -	static DeclareMemType MTYPE_DISPLAY_RENDER_GEOM;
 -	static DeclareMemType MTYPE_DISPLAY_RENDER_FLUSH;
 -	static DeclareMemType MTYPE_DISPLAY_RENDER_UI;
 -	static DeclareMemType MTYPE_DISPLAY_RENDER_ATTACHMENTS;
 -
 -	static DeclareMemType MTYPE_VERTEX_DATA;
 -	static DeclareMemType MTYPE_VERTEX_CONSTRUCTOR;
 -	static DeclareMemType MTYPE_VERTEX_DESTRUCTOR;
 -	static DeclareMemType MTYPE_VERTEX_CREATE_VERTICES;
 -	static DeclareMemType MTYPE_VERTEX_CREATE_INDICES;
 -	static DeclareMemType MTYPE_VERTEX_DESTROY_BUFFER;	
 -	static DeclareMemType MTYPE_VERTEX_DESTROY_INDICES;
 -	static DeclareMemType MTYPE_VERTEX_UPDATE_VERTS;
 -	static DeclareMemType MTYPE_VERTEX_UPDATE_INDICES;
 -	static DeclareMemType MTYPE_VERTEX_ALLOCATE_BUFFER;
 -	static DeclareMemType MTYPE_VERTEX_RESIZE_BUFFER;
 -	static DeclareMemType MTYPE_VERTEX_MAP_BUFFER;
 -	static DeclareMemType MTYPE_VERTEX_MAP_BUFFER_VERTICES;
 -	static DeclareMemType MTYPE_VERTEX_MAP_BUFFER_INDICES;
 -	static DeclareMemType MTYPE_VERTEX_UNMAP_BUFFER;
 -	static DeclareMemType MTYPE_VERTEX_SET_STRIDE;
 -	static DeclareMemType MTYPE_VERTEX_SET_BUFFER;
 -	static DeclareMemType MTYPE_VERTEX_SETUP_VERTEX_BUFFER;
 -	static DeclareMemType MTYPE_VERTEX_CLEANUP_CLASS;
 -
 -	static DeclareMemType MTYPE_SPACE_PARTITION;
 -
 -	static DeclareMemType MTYPE_PIPELINE;
 -	static DeclareMemType MTYPE_PIPELINE_INIT;
 -	static DeclareMemType MTYPE_PIPELINE_CREATE_BUFFERS;
 -	static DeclareMemType MTYPE_PIPELINE_RESTORE_GL;
 -	static DeclareMemType MTYPE_PIPELINE_UNLOAD_SHADERS;
 -	static DeclareMemType MTYPE_PIPELINE_LIGHTING_DETAIL;
 -	static DeclareMemType MTYPE_PIPELINE_GET_POOL_TYPE;
 -	static DeclareMemType MTYPE_PIPELINE_ADD_POOL;
 -	static DeclareMemType MTYPE_PIPELINE_ALLOCATE_DRAWABLE;
 -	static DeclareMemType MTYPE_PIPELINE_ADD_OBJECT;
 -	static DeclareMemType MTYPE_PIPELINE_CREATE_OBJECTS;
 -	static DeclareMemType MTYPE_PIPELINE_UPDATE_MOVE;
 -	static DeclareMemType MTYPE_PIPELINE_UPDATE_GEOM;
 -	static DeclareMemType MTYPE_PIPELINE_MARK_VISIBLE;
 -	static DeclareMemType MTYPE_PIPELINE_MARK_MOVED;
 -	static DeclareMemType MTYPE_PIPELINE_MARK_SHIFT;
 -	static DeclareMemType MTYPE_PIPELINE_SHIFT_OBJECTS;
 -	static DeclareMemType MTYPE_PIPELINE_MARK_TEXTURED;
 -	static DeclareMemType MTYPE_PIPELINE_MARK_REBUILD;
 -	static DeclareMemType MTYPE_PIPELINE_UPDATE_CULL;
 -	static DeclareMemType MTYPE_PIPELINE_STATE_SORT;
 -	static DeclareMemType MTYPE_PIPELINE_POST_SORT;
 -	
 -	static DeclareMemType MTYPE_PIPELINE_RENDER_HUD_ELS;
 -	static DeclareMemType MTYPE_PIPELINE_RENDER_HL;
 -	static DeclareMemType MTYPE_PIPELINE_RENDER_GEOM;
 -	static DeclareMemType MTYPE_PIPELINE_RENDER_GEOM_DEFFERRED;
 -	static DeclareMemType MTYPE_PIPELINE_RENDER_GEOM_POST_DEF;
 -	static DeclareMemType MTYPE_PIPELINE_RENDER_GEOM_SHADOW;
 -	static DeclareMemType MTYPE_PIPELINE_RENDER_SELECT;
 -	static DeclareMemType MTYPE_PIPELINE_REBUILD_POOLS;
 -	static DeclareMemType MTYPE_PIPELINE_QUICK_LOOKUP;
 -	static DeclareMemType MTYPE_PIPELINE_RENDER_OBJECTS;
 -	static DeclareMemType MTYPE_PIPELINE_GENERATE_IMPOSTOR;
 -	static DeclareMemType MTYPE_PIPELINE_RENDER_BLOOM;
 -
 -	static DeclareMemType MTYPE_UPKEEP_POOLS;
 -
 -	static DeclareMemType MTYPE_AVATAR;
 -	static DeclareMemType MTYPE_AVATAR_MESH;
 -	static DeclareMemType MTYPE_PARTICLES;
 -	static DeclareMemType MTYPE_REGIONS;
 -
 -	static DeclareMemType MTYPE_INVENTORY;
 -	static DeclareMemType MTYPE_INVENTORY_DRAW;
 -	static DeclareMemType MTYPE_INVENTORY_BUILD_NEW_VIEWS;
 -	static DeclareMemType MTYPE_INVENTORY_DO_FOLDER;
 -	static DeclareMemType MTYPE_INVENTORY_POST_BUILD;
 -	static DeclareMemType MTYPE_INVENTORY_FROM_XML;
 -	static DeclareMemType MTYPE_INVENTORY_CREATE_NEW_ITEM;
 -	static DeclareMemType MTYPE_INVENTORY_VIEW_INIT;
 -	static DeclareMemType MTYPE_INVENTORY_VIEW_SHOW;
 -	static DeclareMemType MTYPE_INVENTORY_VIEW_TOGGLE;
 -
 -	static DeclareMemType MTYPE_ANIMATION;
 -	static DeclareMemType MTYPE_VOLUME;
 -	static DeclareMemType MTYPE_PRIMITIVE;
 -	
 -	static DeclareMemType MTYPE_SCRIPT;
 -	static DeclareMemType MTYPE_SCRIPT_RUN;
 -	static DeclareMemType MTYPE_SCRIPT_BYTECODE;
 -	
 -	static DeclareMemType MTYPE_IO_PUMP;
 -	static DeclareMemType MTYPE_IO_TCP;
 -	static DeclareMemType MTYPE_IO_BUFFER;
 -	static DeclareMemType MTYPE_IO_HTTP_SERVER;
 -	static DeclareMemType MTYPE_IO_SD_SERVER;
 -	static DeclareMemType MTYPE_IO_SD_CLIENT;
 -	static DeclareMemType MTYPE_IO_URL_REQUEST;
 -
 -	static DeclareMemType MTYPE_DIRECTX_INIT;
 -
 -	static DeclareMemType MTYPE_TEMP1;
 -	static DeclareMemType MTYPE_TEMP2;
 -	static DeclareMemType MTYPE_TEMP3;
 -	static DeclareMemType MTYPE_TEMP4;
 -	static DeclareMemType MTYPE_TEMP5;
 -	static DeclareMemType MTYPE_TEMP6;
 -	static DeclareMemType MTYPE_TEMP7;
 -	static DeclareMemType MTYPE_TEMP8;
 -	static DeclareMemType MTYPE_TEMP9;
 -
 -	static DeclareMemType MTYPE_OTHER; // Special; used by display code
 -
 -	S32 mTypeIndex;
 -};
 -
 -//----------------------------------------------------------------------------
 -
 -#endif
 -
 +/**  + * @file llmemtype.h + * @brief Runtime memory usage debugging utilities. + * + * $LicenseInfo:firstyear=2005&license=viewergpl$ + *  + * Copyright (c) 2005-2009, Linden Research, Inc. + *  + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab.  Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + *  + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + *  + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + *  + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_MEMTYPE_H +#define LL_MEMTYPE_H + +//---------------------------------------------------------------------------- +//---------------------------------------------------------------------------- + +//---------------------------------------------------------------------------- + +#include "linden_common.h" +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +// WARNING: Never commit with MEM_TRACK_MEM == 1 +//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +#define MEM_TRACK_MEM (0 && LL_WINDOWS) + +#include <vector> + +#define MEM_TYPE_NEW(T) + +class LL_COMMON_API LLMemType +{ +public: + +	// class we'll initialize all instances of as +	// static members of MemType.  Then use +	// to construct any new mem type. +	class LL_COMMON_API DeclareMemType +	{ +	public: +		DeclareMemType(char const * st); +		~DeclareMemType(); +	 +		S32 mID; +		char const * mName; +		 +		// array so we can map an index ID to Name +		static std::vector<char const *> mNameList; +	}; + +	LLMemType(DeclareMemType& dt); +	~LLMemType(); + +	static char const * getNameFromID(S32 id); + +	static DeclareMemType MTYPE_INIT; +	static DeclareMemType MTYPE_STARTUP; +	static DeclareMemType MTYPE_MAIN; +	static DeclareMemType MTYPE_FRAME; + +	static DeclareMemType MTYPE_GATHER_INPUT; +	static DeclareMemType MTYPE_JOY_KEY; + +	static DeclareMemType MTYPE_IDLE; +	static DeclareMemType MTYPE_IDLE_PUMP; +	static DeclareMemType MTYPE_IDLE_NETWORK; +	static DeclareMemType MTYPE_IDLE_UPDATE_REGIONS; +	static DeclareMemType MTYPE_IDLE_UPDATE_VIEWER_REGION; +	static DeclareMemType MTYPE_IDLE_UPDATE_SURFACE; +	static DeclareMemType MTYPE_IDLE_UPDATE_PARCEL_OVERLAY; +	static DeclareMemType MTYPE_IDLE_AUDIO; + +	static DeclareMemType MTYPE_CACHE_PROCESS_PENDING; +	static DeclareMemType MTYPE_CACHE_PROCESS_PENDING_ASKS; +	static DeclareMemType MTYPE_CACHE_PROCESS_PENDING_REPLIES; + +	static DeclareMemType MTYPE_MESSAGE_CHECK_ALL; +	static DeclareMemType MTYPE_MESSAGE_PROCESS_ACKS; + +	static DeclareMemType MTYPE_RENDER; +	static DeclareMemType MTYPE_SLEEP; + +	static DeclareMemType MTYPE_NETWORK; +	static DeclareMemType MTYPE_PHYSICS; +	static DeclareMemType MTYPE_INTERESTLIST; + +	static DeclareMemType MTYPE_IMAGEBASE; +	static DeclareMemType MTYPE_IMAGERAW; +	static DeclareMemType MTYPE_IMAGEFORMATTED; +	 +	static DeclareMemType MTYPE_APPFMTIMAGE; +	static DeclareMemType MTYPE_APPRAWIMAGE; +	static DeclareMemType MTYPE_APPAUXRAWIMAGE; +	 +	static DeclareMemType MTYPE_DRAWABLE; +	 +	static DeclareMemType MTYPE_OBJECT; +	static DeclareMemType MTYPE_OBJECT_PROCESS_UPDATE; +	static DeclareMemType MTYPE_OBJECT_PROCESS_UPDATE_CORE; + +	static DeclareMemType MTYPE_DISPLAY; +	static DeclareMemType MTYPE_DISPLAY_UPDATE; +	static DeclareMemType MTYPE_DISPLAY_UPDATE_CAMERA; +	static DeclareMemType MTYPE_DISPLAY_UPDATE_GEOM; +	static DeclareMemType MTYPE_DISPLAY_SWAP; +	static DeclareMemType MTYPE_DISPLAY_UPDATE_HUD; +	static DeclareMemType MTYPE_DISPLAY_GEN_REFLECTION; +	static DeclareMemType MTYPE_DISPLAY_IMAGE_UPDATE; +	static DeclareMemType MTYPE_DISPLAY_STATE_SORT; +	static DeclareMemType MTYPE_DISPLAY_SKY; +	static DeclareMemType MTYPE_DISPLAY_RENDER_GEOM; +	static DeclareMemType MTYPE_DISPLAY_RENDER_FLUSH; +	static DeclareMemType MTYPE_DISPLAY_RENDER_UI; +	static DeclareMemType MTYPE_DISPLAY_RENDER_ATTACHMENTS; + +	static DeclareMemType MTYPE_VERTEX_DATA; +	static DeclareMemType MTYPE_VERTEX_CONSTRUCTOR; +	static DeclareMemType MTYPE_VERTEX_DESTRUCTOR; +	static DeclareMemType MTYPE_VERTEX_CREATE_VERTICES; +	static DeclareMemType MTYPE_VERTEX_CREATE_INDICES; +	static DeclareMemType MTYPE_VERTEX_DESTROY_BUFFER;	 +	static DeclareMemType MTYPE_VERTEX_DESTROY_INDICES; +	static DeclareMemType MTYPE_VERTEX_UPDATE_VERTS; +	static DeclareMemType MTYPE_VERTEX_UPDATE_INDICES; +	static DeclareMemType MTYPE_VERTEX_ALLOCATE_BUFFER; +	static DeclareMemType MTYPE_VERTEX_RESIZE_BUFFER; +	static DeclareMemType MTYPE_VERTEX_MAP_BUFFER; +	static DeclareMemType MTYPE_VERTEX_MAP_BUFFER_VERTICES; +	static DeclareMemType MTYPE_VERTEX_MAP_BUFFER_INDICES; +	static DeclareMemType MTYPE_VERTEX_UNMAP_BUFFER; +	static DeclareMemType MTYPE_VERTEX_SET_STRIDE; +	static DeclareMemType MTYPE_VERTEX_SET_BUFFER; +	static DeclareMemType MTYPE_VERTEX_SETUP_VERTEX_BUFFER; +	static DeclareMemType MTYPE_VERTEX_CLEANUP_CLASS; + +	static DeclareMemType MTYPE_SPACE_PARTITION; + +	static DeclareMemType MTYPE_PIPELINE; +	static DeclareMemType MTYPE_PIPELINE_INIT; +	static DeclareMemType MTYPE_PIPELINE_CREATE_BUFFERS; +	static DeclareMemType MTYPE_PIPELINE_RESTORE_GL; +	static DeclareMemType MTYPE_PIPELINE_UNLOAD_SHADERS; +	static DeclareMemType MTYPE_PIPELINE_LIGHTING_DETAIL; +	static DeclareMemType MTYPE_PIPELINE_GET_POOL_TYPE; +	static DeclareMemType MTYPE_PIPELINE_ADD_POOL; +	static DeclareMemType MTYPE_PIPELINE_ALLOCATE_DRAWABLE; +	static DeclareMemType MTYPE_PIPELINE_ADD_OBJECT; +	static DeclareMemType MTYPE_PIPELINE_CREATE_OBJECTS; +	static DeclareMemType MTYPE_PIPELINE_UPDATE_MOVE; +	static DeclareMemType MTYPE_PIPELINE_UPDATE_GEOM; +	static DeclareMemType MTYPE_PIPELINE_MARK_VISIBLE; +	static DeclareMemType MTYPE_PIPELINE_MARK_MOVED; +	static DeclareMemType MTYPE_PIPELINE_MARK_SHIFT; +	static DeclareMemType MTYPE_PIPELINE_SHIFT_OBJECTS; +	static DeclareMemType MTYPE_PIPELINE_MARK_TEXTURED; +	static DeclareMemType MTYPE_PIPELINE_MARK_REBUILD; +	static DeclareMemType MTYPE_PIPELINE_UPDATE_CULL; +	static DeclareMemType MTYPE_PIPELINE_STATE_SORT; +	static DeclareMemType MTYPE_PIPELINE_POST_SORT; +	 +	static DeclareMemType MTYPE_PIPELINE_RENDER_HUD_ELS; +	static DeclareMemType MTYPE_PIPELINE_RENDER_HL; +	static DeclareMemType MTYPE_PIPELINE_RENDER_GEOM; +	static DeclareMemType MTYPE_PIPELINE_RENDER_GEOM_DEFFERRED; +	static DeclareMemType MTYPE_PIPELINE_RENDER_GEOM_POST_DEF; +	static DeclareMemType MTYPE_PIPELINE_RENDER_GEOM_SHADOW; +	static DeclareMemType MTYPE_PIPELINE_RENDER_SELECT; +	static DeclareMemType MTYPE_PIPELINE_REBUILD_POOLS; +	static DeclareMemType MTYPE_PIPELINE_QUICK_LOOKUP; +	static DeclareMemType MTYPE_PIPELINE_RENDER_OBJECTS; +	static DeclareMemType MTYPE_PIPELINE_GENERATE_IMPOSTOR; +	static DeclareMemType MTYPE_PIPELINE_RENDER_BLOOM; + +	static DeclareMemType MTYPE_UPKEEP_POOLS; + +	static DeclareMemType MTYPE_AVATAR; +	static DeclareMemType MTYPE_AVATAR_MESH; +	static DeclareMemType MTYPE_PARTICLES; +	static DeclareMemType MTYPE_REGIONS; + +	static DeclareMemType MTYPE_INVENTORY; +	static DeclareMemType MTYPE_INVENTORY_DRAW; +	static DeclareMemType MTYPE_INVENTORY_BUILD_NEW_VIEWS; +	static DeclareMemType MTYPE_INVENTORY_DO_FOLDER; +	static DeclareMemType MTYPE_INVENTORY_POST_BUILD; +	static DeclareMemType MTYPE_INVENTORY_FROM_XML; +	static DeclareMemType MTYPE_INVENTORY_CREATE_NEW_ITEM; +	static DeclareMemType MTYPE_INVENTORY_VIEW_INIT; +	static DeclareMemType MTYPE_INVENTORY_VIEW_SHOW; +	static DeclareMemType MTYPE_INVENTORY_VIEW_TOGGLE; + +	static DeclareMemType MTYPE_ANIMATION; +	static DeclareMemType MTYPE_VOLUME; +	static DeclareMemType MTYPE_PRIMITIVE; +	 +	static DeclareMemType MTYPE_SCRIPT; +	static DeclareMemType MTYPE_SCRIPT_RUN; +	static DeclareMemType MTYPE_SCRIPT_BYTECODE; +	 +	static DeclareMemType MTYPE_IO_PUMP; +	static DeclareMemType MTYPE_IO_TCP; +	static DeclareMemType MTYPE_IO_BUFFER; +	static DeclareMemType MTYPE_IO_HTTP_SERVER; +	static DeclareMemType MTYPE_IO_SD_SERVER; +	static DeclareMemType MTYPE_IO_SD_CLIENT; +	static DeclareMemType MTYPE_IO_URL_REQUEST; + +	static DeclareMemType MTYPE_DIRECTX_INIT; + +	static DeclareMemType MTYPE_TEMP1; +	static DeclareMemType MTYPE_TEMP2; +	static DeclareMemType MTYPE_TEMP3; +	static DeclareMemType MTYPE_TEMP4; +	static DeclareMemType MTYPE_TEMP5; +	static DeclareMemType MTYPE_TEMP6; +	static DeclareMemType MTYPE_TEMP7; +	static DeclareMemType MTYPE_TEMP8; +	static DeclareMemType MTYPE_TEMP9; + +	static DeclareMemType MTYPE_OTHER; // Special; used by display code + +	S32 mTypeIndex; +}; + +//---------------------------------------------------------------------------- + +#endif + diff --git a/indra/llcommon/llpreprocessor.h b/indra/llcommon/llpreprocessor.h index 48baa50edb..48244480b1 100644 --- a/indra/llcommon/llpreprocessor.h +++ b/indra/llcommon/llpreprocessor.h @@ -1,168 +1,168 @@ -/** 
 - * @file llpreprocessor.h
 - * @brief This file should be included in all Linden Lab files and
 - * should only contain special preprocessor directives
 - *
 - * $LicenseInfo:firstyear=2001&license=viewergpl$
 - * 
 - * Copyright (c) 2001-2009, Linden Research, Inc.
 - * 
 - * Second Life Viewer Source Code
 - * The source code in this file ("Source Code") is provided by Linden Lab
 - * to you under the terms of the GNU General Public License, version 2.0
 - * ("GPL"), unless you have obtained a separate licensing agreement
 - * ("Other License"), formally executed by you and Linden Lab.  Terms of
 - * the GPL can be found in doc/GPL-license.txt in this distribution, or
 - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
 - * 
 - * There are special exceptions to the terms and conditions of the GPL as
 - * it is applied to this Source Code. View the full text of the exception
 - * in the file doc/FLOSS-exception.txt in this software distribution, or
 - * online at
 - * http://secondlifegrid.net/programs/open_source/licensing/flossexception
 - * 
 - * By copying, modifying or distributing this software, you acknowledge
 - * that you have read and understood your obligations described above,
 - * and agree to abide by those obligations.
 - * 
 - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
 - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
 - * COMPLETENESS OR PERFORMANCE.
 - * $/LicenseInfo$
 - */
 -
 -#ifndef LLPREPROCESSOR_H
 -#define LLPREPROCESSOR_H
 -
 -// Figure out endianness of platform
 -#ifdef LL_LINUX
 -#define __ENABLE_WSTRING
 -#include <endian.h>
 -#endif	//	LL_LINUX
 -
 -#if LL_SOLARIS
 -#   ifdef  __sparc     // Since we're talking Solaris 10 and up, only 64 bit is supported.
 -#      define LL_BIG_ENDIAN 1
 -#      define LL_SOLARIS_ALIGNED_CPU 1     //  used to designate issues where SPARC alignment is addressed
 -#      define LL_SOLARIS_NON_MESA_GL 1      //  The SPARC GL does not provide a MESA-based GL API
 -#   endif
 -#   include <sys/isa_defs.h> // ensure we know which end is up
 -#endif // LL_SOLARIS
 -
 -#if (defined(LL_WINDOWS) || (defined(LL_LINUX) && (__BYTE_ORDER == __LITTLE_ENDIAN)) || (defined(LL_DARWIN) && defined(__LITTLE_ENDIAN__)) || (defined(LL_SOLARIS) && defined(__i386)))
 -#define LL_LITTLE_ENDIAN 1
 -#else
 -#define LL_BIG_ENDIAN 1
 -#endif
 -
 -// Per-compiler switches
 -#ifdef __GNUC__
 -#define LL_FORCE_INLINE inline __attribute__((always_inline))
 -#else
 -#define LL_FORCE_INLINE __forceinline
 -#endif
 -
 -// Figure out differences between compilers
 -#if defined(__GNUC__)
 -	#define GCC_VERSION (__GNUC__ * 10000 \
 -						+ __GNUC_MINOR__ * 100 \
 -						+ __GNUC_PATCHLEVEL__)
 -	#ifndef LL_GNUC
 -		#define LL_GNUC 1
 -	#endif
 -#elif defined(__MSVC_VER__) || defined(_MSC_VER)
 -	#ifndef LL_MSVC
 -		#define LL_MSVC 1
 -	#endif
 -	#if _MSC_VER < 1400
 -		#define LL_MSVC7 //Visual C++ 2003 or earlier
 -	#endif
 -#endif
 -
 -// Deal with minor differences on Unixy OSes.
 -#if LL_DARWIN || LL_LINUX
 -	// Different name, same functionality.
 -	#define stricmp strcasecmp
 -	#define strnicmp strncasecmp
 -
 -	// Not sure why this is different, but...
 -	#ifndef MAX_PATH
 -		#define MAX_PATH PATH_MAX
 -	#endif	//	not MAX_PATH
 -
 -#endif
 -
 -
 -// Static linking with apr on windows needs to be declared.
 -#if LL_WINDOWS && !LL_COMMON_LINK_SHARED
 -#ifndef APR_DECLARE_STATIC
 -#define APR_DECLARE_STATIC // For APR on Windows
 -#endif
 -#ifndef APU_DECLARE_STATIC
 -#define APU_DECLARE_STATIC // For APR util on Windows
 -#endif
 -#endif
 -
 -#if defined(LL_WINDOWS)
 -#define BOOST_REGEX_NO_LIB 1
 -#define CURL_STATICLIB 1
 -#ifndef XML_STATIC
 -#define XML_STATIC
 -#endif
 -#endif	//	LL_WINDOWS
 -
 -
 -// Deal with VC6 problems
 -#if LL_MSVC
 -#pragma warning( 3	     : 4701 )	// "local variable used without being initialized"  Treat this as level 3, not level 4.
 -#pragma warning( 3	     : 4702 )	// "unreachable code"  Treat this as level 3, not level 4.
 -#pragma warning( 3	     : 4189 )	// "local variable initialized but not referenced"  Treat this as level 3, not level 4.
 -//#pragma warning( 3	: 4018 )	// "signed/unsigned mismatch"  Treat this as level 3, not level 4.
 -#pragma warning( 3      :  4263 )	// 'function' : member function does not override any base class virtual member function
 -#pragma warning( 3      :  4264 )	// "'virtual_function' : no override available for virtual member function from base 'class'; function is hidden"
 -#pragma warning( 3       : 4265 )	// "class has virtual functions, but destructor is not virtual"
 -#pragma warning( 3      :  4266 )	// 'function' : no override available for virtual member function from base 'type'; function is hidden
 -#pragma warning( disable : 4284 )	// silly MS warning deep inside their <map> include file
 -#pragma warning( disable : 4503 )	// 'decorated name length exceeded, name was truncated'. Does not seem to affect compilation.
 -#pragma warning( disable : 4800 )	// 'BOOL' : forcing value to bool 'true' or 'false' (performance warning)
 -#pragma warning( disable : 4996 )	// warning: deprecated
 -
 -// level 4 warnings that we need to disable:
 -#pragma warning (disable : 4100) // unreferenced formal parameter
 -#pragma warning (disable : 4127) // conditional expression is constant (e.g. while(1) )
 -#pragma warning (disable : 4244) // possible loss of data on conversions
 -#pragma warning (disable : 4396) // the inline specifier cannot be used when a friend declaration refers to a specialization of a function template
 -#pragma warning (disable : 4512) // assignment operator could not be generated
 -#pragma warning (disable : 4706) // assignment within conditional (even if((x = y)) )
 -
 -#pragma warning (disable : 4251) // member needs to have dll-interface to be used by clients of class
 -#pragma warning (disable : 4275) // non dll-interface class used as base for dll-interface class
 -#endif	//	LL_MSVC
 -
 -#if LL_WINDOWS
 -#define LL_DLLEXPORT __declspec(dllexport)
 -#define LL_DLLIMPORT __declspec(dllimport)
 -#elif LL_LINUX
 -#define LL_DLLEXPORT __attribute__ ((visibility("default")))
 -#define LL_DLLIMPORT
 -#else
 -#define LL_DLLEXPORT
 -#define LL_DLLIMPORT
 -#endif // LL_WINDOWS
 -
 -#if LL_COMMON_LINK_SHARED
 -// CMake automagically defines llcommon_EXPORTS only when building llcommon
 -// sources, and only when llcommon is a shared library (i.e. when
 -// LL_COMMON_LINK_SHARED). We must still test LL_COMMON_LINK_SHARED because
 -// otherwise we can't distinguish between (non-llcommon source) and (llcommon
 -// not shared).
 -# if defined(llcommon_EXPORTS)
 -#   define LL_COMMON_API LL_DLLEXPORT
 -# else //llcommon_EXPORTS
 -#   define LL_COMMON_API LL_DLLIMPORT
 -# endif //llcommon_EXPORTS
 -#else // LL_COMMON_LINK_SHARED
 -# define LL_COMMON_API
 -#endif // LL_COMMON_LINK_SHARED
 -
 -#endif	//	not LL_LINDEN_PREPROCESSOR_H
 +/**  + * @file llpreprocessor.h + * @brief This file should be included in all Linden Lab files and + * should only contain special preprocessor directives + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + *  + * Copyright (c) 2001-2009, Linden Research, Inc. + *  + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab.  Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + *  + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + *  + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + *  + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LLPREPROCESSOR_H +#define LLPREPROCESSOR_H + +// Figure out endianness of platform +#ifdef LL_LINUX +#define __ENABLE_WSTRING +#include <endian.h> +#endif	//	LL_LINUX + +#if LL_SOLARIS +#   ifdef  __sparc     // Since we're talking Solaris 10 and up, only 64 bit is supported. +#      define LL_BIG_ENDIAN 1 +#      define LL_SOLARIS_ALIGNED_CPU 1     //  used to designate issues where SPARC alignment is addressed +#      define LL_SOLARIS_NON_MESA_GL 1      //  The SPARC GL does not provide a MESA-based GL API +#   endif +#   include <sys/isa_defs.h> // ensure we know which end is up +#endif // LL_SOLARIS + +#if (defined(LL_WINDOWS) || (defined(LL_LINUX) && (__BYTE_ORDER == __LITTLE_ENDIAN)) || (defined(LL_DARWIN) && defined(__LITTLE_ENDIAN__)) || (defined(LL_SOLARIS) && defined(__i386))) +#define LL_LITTLE_ENDIAN 1 +#else +#define LL_BIG_ENDIAN 1 +#endif + +// Per-compiler switches +#ifdef __GNUC__ +#define LL_FORCE_INLINE inline __attribute__((always_inline)) +#else +#define LL_FORCE_INLINE __forceinline +#endif + +// Figure out differences between compilers +#if defined(__GNUC__) +	#define GCC_VERSION (__GNUC__ * 10000 \ +						+ __GNUC_MINOR__ * 100 \ +						+ __GNUC_PATCHLEVEL__) +	#ifndef LL_GNUC +		#define LL_GNUC 1 +	#endif +#elif defined(__MSVC_VER__) || defined(_MSC_VER) +	#ifndef LL_MSVC +		#define LL_MSVC 1 +	#endif +	#if _MSC_VER < 1400 +		#define LL_MSVC7 //Visual C++ 2003 or earlier +	#endif +#endif + +// Deal with minor differences on Unixy OSes. +#if LL_DARWIN || LL_LINUX +	// Different name, same functionality. +	#define stricmp strcasecmp +	#define strnicmp strncasecmp + +	// Not sure why this is different, but... +	#ifndef MAX_PATH +		#define MAX_PATH PATH_MAX +	#endif	//	not MAX_PATH + +#endif + + +// Static linking with apr on windows needs to be declared. +#if LL_WINDOWS && !LL_COMMON_LINK_SHARED +#ifndef APR_DECLARE_STATIC +#define APR_DECLARE_STATIC // For APR on Windows +#endif +#ifndef APU_DECLARE_STATIC +#define APU_DECLARE_STATIC // For APR util on Windows +#endif +#endif + +#if defined(LL_WINDOWS) +#define BOOST_REGEX_NO_LIB 1 +#define CURL_STATICLIB 1 +#ifndef XML_STATIC +#define XML_STATIC +#endif +#endif	//	LL_WINDOWS + + +// Deal with VC6 problems +#if LL_MSVC +#pragma warning( 3	     : 4701 )	// "local variable used without being initialized"  Treat this as level 3, not level 4. +#pragma warning( 3	     : 4702 )	// "unreachable code"  Treat this as level 3, not level 4. +#pragma warning( 3	     : 4189 )	// "local variable initialized but not referenced"  Treat this as level 3, not level 4. +//#pragma warning( 3	: 4018 )	// "signed/unsigned mismatch"  Treat this as level 3, not level 4. +#pragma warning( 3      :  4263 )	// 'function' : member function does not override any base class virtual member function +#pragma warning( 3      :  4264 )	// "'virtual_function' : no override available for virtual member function from base 'class'; function is hidden" +#pragma warning( 3       : 4265 )	// "class has virtual functions, but destructor is not virtual" +#pragma warning( 3      :  4266 )	// 'function' : no override available for virtual member function from base 'type'; function is hidden +#pragma warning( disable : 4284 )	// silly MS warning deep inside their <map> include file +#pragma warning( disable : 4503 )	// 'decorated name length exceeded, name was truncated'. Does not seem to affect compilation. +#pragma warning( disable : 4800 )	// 'BOOL' : forcing value to bool 'true' or 'false' (performance warning) +#pragma warning( disable : 4996 )	// warning: deprecated + +// level 4 warnings that we need to disable: +#pragma warning (disable : 4100) // unreferenced formal parameter +#pragma warning (disable : 4127) // conditional expression is constant (e.g. while(1) ) +#pragma warning (disable : 4244) // possible loss of data on conversions +#pragma warning (disable : 4396) // the inline specifier cannot be used when a friend declaration refers to a specialization of a function template +#pragma warning (disable : 4512) // assignment operator could not be generated +#pragma warning (disable : 4706) // assignment within conditional (even if((x = y)) ) + +#pragma warning (disable : 4251) // member needs to have dll-interface to be used by clients of class +#pragma warning (disable : 4275) // non dll-interface class used as base for dll-interface class +#endif	//	LL_MSVC + +#if LL_WINDOWS +#define LL_DLLEXPORT __declspec(dllexport) +#define LL_DLLIMPORT __declspec(dllimport) +#elif LL_LINUX +#define LL_DLLEXPORT __attribute__ ((visibility("default"))) +#define LL_DLLIMPORT +#else +#define LL_DLLEXPORT +#define LL_DLLIMPORT +#endif // LL_WINDOWS + +#if LL_COMMON_LINK_SHARED +// CMake automagically defines llcommon_EXPORTS only when building llcommon +// sources, and only when llcommon is a shared library (i.e. when +// LL_COMMON_LINK_SHARED). We must still test LL_COMMON_LINK_SHARED because +// otherwise we can't distinguish between (non-llcommon source) and (llcommon +// not shared). +# if defined(llcommon_EXPORTS) +#   define LL_COMMON_API LL_DLLEXPORT +# else //llcommon_EXPORTS +#   define LL_COMMON_API LL_DLLIMPORT +# endif //llcommon_EXPORTS +#else // LL_COMMON_LINK_SHARED +# define LL_COMMON_API +#endif // LL_COMMON_LINK_SHARED + +#endif	//	not LL_LINDEN_PREPROCESSOR_H diff --git a/indra/llcommon/llqueuedthread.cpp b/indra/llcommon/llqueuedthread.cpp index 3db5c36545..e7ad571a90 100644 --- a/indra/llcommon/llqueuedthread.cpp +++ b/indra/llcommon/llqueuedthread.cpp @@ -42,7 +42,8 @@ LLQueuedThread::LLQueuedThread(const std::string& name, bool threaded) :  	LLThread(name),  	mThreaded(threaded),  	mIdleThread(TRUE), -	mNextHandle(0) +	mNextHandle(0), +	mStarted(FALSE)  {  	if (mThreaded)  	{ @@ -53,6 +54,10 @@ LLQueuedThread::LLQueuedThread(const std::string& name, bool threaded) :  // MAIN THREAD  LLQueuedThread::~LLQueuedThread()  { +	if (!mThreaded) +	{ +		endThread(); +	}  	shutdown();  	// ~LLThread() will be called here  } @@ -106,6 +111,14 @@ void LLQueuedThread::shutdown()  // virtual  S32 LLQueuedThread::update(U32 max_time_ms)  { +	if (!mStarted) +	{ +		if (!mThreaded) +		{ +			startThread(); +			mStarted = TRUE; +		} +	}  	return updateQueue(max_time_ms);  } @@ -452,26 +465,12 @@ S32 LLQueuedThread::processNextRequest()  		}  	} -	S32 res;  	S32 pending = getPending(); -	if (pending == 0) -	{ -		if (isQuitting()) -		{ -			res = -1; // exit thread -		} -		else -		{ -			res = 0; -		} -	} -	else -	{ -		res = pending; -	} -	return res; + +	return pending;  } +// virtual  bool LLQueuedThread::runCondition()  {  	// mRunCondition must be locked here @@ -481,35 +480,53 @@ bool LLQueuedThread::runCondition()  		return true;  } +// virtual  void LLQueuedThread::run()  { +	// call checPause() immediately so we don't try to do anything before the class is fully constructed +	checkPause(); +	startThread(); +	mStarted = TRUE; +	  	while (1)  	{  		// this will block on the condition until runCondition() returns true, the thread is unpaused, or the thread leaves the RUNNING state.  		checkPause(); -		if(isQuitting()) +		if (isQuitting()) +		{ +			endThread();  			break; - -		//llinfos << "QUEUED THREAD RUNNING, queue size = " << mRequestQueue.size() << llendl; +		}  		mIdleThread = FALSE; + +		threadedUpdate();  		int res = processNextRequest();  		if (res == 0)  		{  			mIdleThread = TRUE; +			ms_sleep(1);  		} -		 -		if (res < 0) // finished working and want to exit -		{ -			break; -		} -  		//LLThread::yield(); // thread should yield after each request		  	} +	llinfos << "LLQueuedThread " << mName << " EXITING." << llendl; +} + +// virtual +void LLQueuedThread::startThread() +{ +} -	llinfos << "QUEUED THREAD " << mName << " EXITING." << llendl; +// virtual +void LLQueuedThread::endThread() +{ +} + +// virtual +void LLQueuedThread::threadedUpdate() +{  }  //============================================================================ diff --git a/indra/llcommon/llqueuedthread.h b/indra/llcommon/llqueuedthread.h index 8bfa5632a1..9a9dbb18cc 100644 --- a/indra/llcommon/llqueuedthread.h +++ b/indra/llcommon/llqueuedthread.h @@ -166,6 +166,9 @@ private:  	virtual bool runCondition(void);  	virtual void run(void); +	virtual void startThread(void); +	virtual void endThread(void); +	virtual void threadedUpdate(void);  protected:  	handle_t generateHandle(); @@ -200,6 +203,7 @@ public:  protected:  	BOOL mThreaded;  // if false, run on main thread and do updates during update() +	BOOL mStarted;  // required when mThreaded is false to call startThread() from update()  	LLAtomic32<BOOL> mIdleThread; // request queue is empty (or we are quitting) and the thread is idle  	typedef std::set<QueuedRequest*, queued_request_less> request_queue_t; diff --git a/indra/llcommon/llstacktrace.cpp b/indra/llcommon/llstacktrace.cpp index 3cb074257b..6558df70a4 100644 --- a/indra/llcommon/llstacktrace.cpp +++ b/indra/llcommon/llstacktrace.cpp @@ -1,142 +1,142 @@ -/** 
 - * @file llstacktrace.cpp
 - * @brief stack tracing functionality
 - *
 - * $LicenseInfo:firstyear=2001&license=viewergpl$
 - * 
 - * Copyright (c) 2001-2009, Linden Research, Inc.
 - * 
 - * Second Life Viewer Source Code
 - * The source code in this file ("Source Code") is provided by Linden Lab
 - * to you under the terms of the GNU General Public License, version 2.0
 - * ("GPL"), unless you have obtained a separate licensing agreement
 - * ("Other License"), formally executed by you and Linden Lab.  Terms of
 - * the GPL can be found in doc/GPL-license.txt in this distribution, or
 - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
 - * 
 - * There are special exceptions to the terms and conditions of the GPL as
 - * it is applied to this Source Code. View the full text of the exception
 - * in the file doc/FLOSS-exception.txt in this software distribution, or
 - * online at
 - * http://secondlifegrid.net/programs/open_source/licensing/flossexception
 - * 
 - * By copying, modifying or distributing this software, you acknowledge
 - * that you have read and understood your obligations described above,
 - * and agree to abide by those obligations.
 - * 
 - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
 - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
 - * COMPLETENESS OR PERFORMANCE.
 - * $/LicenseInfo$
 - */
 -
 -#include "linden_common.h"
 -#include "llstacktrace.h"
 -
 -#ifdef LL_WINDOWS
 -
 -#include <iostream>
 -#include <sstream>
 -
 -#include "windows.h"
 -#include "Dbghelp.h"
 -
 -typedef USHORT NTAPI RtlCaptureStackBackTrace_Function(
 -    IN ULONG frames_to_skip,
 -    IN ULONG frames_to_capture,
 -    OUT PVOID *backtrace,
 -    OUT PULONG backtrace_hash);
 -
 -static RtlCaptureStackBackTrace_Function* const RtlCaptureStackBackTrace_fn =
 -   (RtlCaptureStackBackTrace_Function*)
 -   GetProcAddress(GetModuleHandleA("ntdll.dll"), "RtlCaptureStackBackTrace");
 -
 -bool ll_get_stack_trace(std::vector<std::string>& lines)
 -{
 -	const S32 MAX_STACK_DEPTH = 32;
 -	const S32 STRING_NAME_LENGTH = 200;
 -	const S32 FRAME_SKIP = 2;
 -	static BOOL symbolsLoaded = false;
 -	static BOOL firstCall = true;
 -
 -	HANDLE hProc = GetCurrentProcess();
 -
 -	// load the symbols if they're not loaded
 -	if(!symbolsLoaded && firstCall)
 -	{
 -		symbolsLoaded = SymInitialize(hProc, NULL, true);
 -		firstCall = false;
 -	}
 -
 -	// if loaded, get the call stack
 -	if(symbolsLoaded)
 -	{
 -		// create the frames to hold the addresses
 -		void* frames[MAX_STACK_DEPTH];
 -		memset(frames, 0, sizeof(void*)*MAX_STACK_DEPTH);
 -		S32 depth = 0;
 -
 -		// get the addresses
 -		depth = RtlCaptureStackBackTrace_fn(FRAME_SKIP, MAX_STACK_DEPTH, frames, NULL);
 -
 -		IMAGEHLP_LINE64 line;
 -		memset(&line, 0, sizeof(IMAGEHLP_LINE64));
 -		line.SizeOfStruct = sizeof(IMAGEHLP_LINE64);
 -
 -		// create something to hold address info
 -		PIMAGEHLP_SYMBOL64 pSym;
 -		pSym = (PIMAGEHLP_SYMBOL64)malloc(sizeof(IMAGEHLP_SYMBOL64) + STRING_NAME_LENGTH);
 -		memset(pSym, 0, sizeof(IMAGEHLP_SYMBOL64) + STRING_NAME_LENGTH);
 -		pSym->MaxNameLength = STRING_NAME_LENGTH;
 -		pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64);
 -
 -		// get address info for each address frame
 -		// and store
 -		for(S32 i=0; i < depth; i++)
 -		{
 -			std::stringstream stack_line;
 -			BOOL ret;
 -
 -			DWORD64 addr = (DWORD64)frames[i];
 -			ret = SymGetSymFromAddr64(hProc, addr, 0, pSym);
 -			if(ret)
 -			{
 -				stack_line << pSym->Name << " ";
 -			}
 -
 -			DWORD dummy;
 -			ret = SymGetLineFromAddr64(hProc, addr, &dummy, &line);
 -			if(ret)
 -			{
 -				std::string file_name = line.FileName;
 -				std::string::size_type index = file_name.rfind("\\");
 -				stack_line << file_name.substr(index + 1, file_name.size()) << ":" << line.LineNumber; 
 -			}
 -
 -			lines.push_back(stack_line.str());
 -		}
 -		
 -		free(pSym);
 -
 -		// TODO: figure out a way to cleanup symbol loading
 -		// Not hugely necessary, however.
 -		//SymCleanup(hProc);
 -		return true;
 -	}
 -	else
 -	{
 -		lines.push_back("Stack Trace Failed.  PDB symbol info not loaded");
 -	}
 -
 -	return false;
 -}
 -
 -#else
 -
 -bool ll_get_stack_trace(std::vector<std::string>& lines)
 -{
 -	return false;
 -}
 -
 -#endif
 -
 +/**  + * @file llstacktrace.cpp + * @brief stack tracing functionality + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + *  + * Copyright (c) 2001-2009, Linden Research, Inc. + *  + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab.  Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + *  + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + *  + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + *  + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#include "linden_common.h" +#include "llstacktrace.h" + +#ifdef LL_WINDOWS + +#include <iostream> +#include <sstream> + +#include "windows.h" +#include "Dbghelp.h" + +typedef USHORT NTAPI RtlCaptureStackBackTrace_Function( +    IN ULONG frames_to_skip, +    IN ULONG frames_to_capture, +    OUT PVOID *backtrace, +    OUT PULONG backtrace_hash); + +static RtlCaptureStackBackTrace_Function* const RtlCaptureStackBackTrace_fn = +   (RtlCaptureStackBackTrace_Function*) +   GetProcAddress(GetModuleHandleA("ntdll.dll"), "RtlCaptureStackBackTrace"); + +bool ll_get_stack_trace(std::vector<std::string>& lines) +{ +	const S32 MAX_STACK_DEPTH = 32; +	const S32 STRING_NAME_LENGTH = 200; +	const S32 FRAME_SKIP = 2; +	static BOOL symbolsLoaded = false; +	static BOOL firstCall = true; + +	HANDLE hProc = GetCurrentProcess(); + +	// load the symbols if they're not loaded +	if(!symbolsLoaded && firstCall) +	{ +		symbolsLoaded = SymInitialize(hProc, NULL, true); +		firstCall = false; +	} + +	// if loaded, get the call stack +	if(symbolsLoaded) +	{ +		// create the frames to hold the addresses +		void* frames[MAX_STACK_DEPTH]; +		memset(frames, 0, sizeof(void*)*MAX_STACK_DEPTH); +		S32 depth = 0; + +		// get the addresses +		depth = RtlCaptureStackBackTrace_fn(FRAME_SKIP, MAX_STACK_DEPTH, frames, NULL); + +		IMAGEHLP_LINE64 line; +		memset(&line, 0, sizeof(IMAGEHLP_LINE64)); +		line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); + +		// create something to hold address info +		PIMAGEHLP_SYMBOL64 pSym; +		pSym = (PIMAGEHLP_SYMBOL64)malloc(sizeof(IMAGEHLP_SYMBOL64) + STRING_NAME_LENGTH); +		memset(pSym, 0, sizeof(IMAGEHLP_SYMBOL64) + STRING_NAME_LENGTH); +		pSym->MaxNameLength = STRING_NAME_LENGTH; +		pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64); + +		// get address info for each address frame +		// and store +		for(S32 i=0; i < depth; i++) +		{ +			std::stringstream stack_line; +			BOOL ret; + +			DWORD64 addr = (DWORD64)frames[i]; +			ret = SymGetSymFromAddr64(hProc, addr, 0, pSym); +			if(ret) +			{ +				stack_line << pSym->Name << " "; +			} + +			DWORD dummy; +			ret = SymGetLineFromAddr64(hProc, addr, &dummy, &line); +			if(ret) +			{ +				std::string file_name = line.FileName; +				std::string::size_type index = file_name.rfind("\\"); +				stack_line << file_name.substr(index + 1, file_name.size()) << ":" << line.LineNumber;  +			} + +			lines.push_back(stack_line.str()); +		} +		 +		free(pSym); + +		// TODO: figure out a way to cleanup symbol loading +		// Not hugely necessary, however. +		//SymCleanup(hProc); +		return true; +	} +	else +	{ +		lines.push_back("Stack Trace Failed.  PDB symbol info not loaded"); +	} + +	return false; +} + +#else + +bool ll_get_stack_trace(std::vector<std::string>& lines) +{ +	return false; +} + +#endif + diff --git a/indra/llcommon/llstacktrace.h b/indra/llcommon/llstacktrace.h index b84b1aa6ad..9f857f0fd3 100644 --- a/indra/llcommon/llstacktrace.h +++ b/indra/llcommon/llstacktrace.h @@ -1,44 +1,44 @@ -/** 
 - * @file llstacktrace.h
 - * @brief stack trace functions
 - *
 - * $LicenseInfo:firstyear=2001&license=viewergpl$
 - * 
 - * Copyright (c) 2001-2009, Linden Research, Inc.
 - * 
 - * Second Life Viewer Source Code
 - * The source code in this file ("Source Code") is provided by Linden Lab
 - * to you under the terms of the GNU General Public License, version 2.0
 - * ("GPL"), unless you have obtained a separate licensing agreement
 - * ("Other License"), formally executed by you and Linden Lab.  Terms of
 - * the GPL can be found in doc/GPL-license.txt in this distribution, or
 - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
 - * 
 - * There are special exceptions to the terms and conditions of the GPL as
 - * it is applied to this Source Code. View the full text of the exception
 - * in the file doc/FLOSS-exception.txt in this software distribution, or
 - * online at
 - * http://secondlifegrid.net/programs/open_source/licensing/flossexception
 - * 
 - * By copying, modifying or distributing this software, you acknowledge
 - * that you have read and understood your obligations described above,
 - * and agree to abide by those obligations.
 - * 
 - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
 - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
 - * COMPLETENESS OR PERFORMANCE.
 - * $/LicenseInfo$
 - */
 -
 -
 -#ifndef LL_LLSTACKTRACE_H
 -#define LL_LLSTACKTRACE_H
 -
 -#include "stdtypes.h"
 -#include <vector>
 -#include <string>
 -
 -LL_COMMON_API bool ll_get_stack_trace(std::vector<std::string>& lines);
 -
 -#endif
 -
 +/**  + * @file llstacktrace.h + * @brief stack trace functions + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + *  + * Copyright (c) 2001-2009, Linden Research, Inc. + *  + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab.  Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + *  + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + *  + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + *  + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + + +#ifndef LL_LLSTACKTRACE_H +#define LL_LLSTACKTRACE_H + +#include "stdtypes.h" +#include <vector> +#include <string> + +LL_COMMON_API bool ll_get_stack_trace(std::vector<std::string>& lines); + +#endif + diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h index edbb007f61..31e70e0fe4 100644 --- a/indra/llcommon/llstring.h +++ b/indra/llcommon/llstring.h @@ -1,1300 +1,1300 @@ -/** 
 - * @file llstring.h
 - * @brief String utility functions and std::string class.
 - *
 - * $LicenseInfo:firstyear=2001&license=viewergpl$
 - * 
 - * Copyright (c) 2001-2009, Linden Research, Inc.
 - * 
 - * Second Life Viewer Source Code
 - * The source code in this file ("Source Code") is provided by Linden Lab
 - * to you under the terms of the GNU General Public License, version 2.0
 - * ("GPL"), unless you have obtained a separate licensing agreement
 - * ("Other License"), formally executed by you and Linden Lab.  Terms of
 - * the GPL can be found in doc/GPL-license.txt in this distribution, or
 - * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
 - * 
 - * There are special exceptions to the terms and conditions of the GPL as
 - * it is applied to this Source Code. View the full text of the exception
 - * in the file doc/FLOSS-exception.txt in this software distribution, or
 - * online at
 - * http://secondlifegrid.net/programs/open_source/licensing/flossexception
 - * 
 - * By copying, modifying or distributing this software, you acknowledge
 - * that you have read and understood your obligations described above,
 - * and agree to abide by those obligations.
 - * 
 - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
 - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
 - * COMPLETENESS OR PERFORMANCE.
 - * $/LicenseInfo$
 - */
 -
 -#ifndef LL_LLSTRING_H
 -#define LL_LLSTRING_H
 -
 -#include <string>
 -#include <cstdio>
 -#include <locale>
 -#include <iomanip>
 -#include "llsd.h"
 -#include "llfasttimer.h"
 -
 -#if LL_LINUX || LL_SOLARIS
 -#include <wctype.h>
 -#include <wchar.h>
 -#endif
 -
 -#include <string.h>
 -
 -#if LL_SOLARIS
 -// stricmp and strnicmp do not exist on Solaris:
 -#define stricmp strcasecmp
 -#define strnicmp strncasecmp
 -#endif
 -
 -const char LL_UNKNOWN_CHAR = '?';
 -
 -#if LL_DARWIN || LL_LINUX || LL_SOLARIS
 -// Template specialization of char_traits for U16s. Only necessary on Mac and Linux (exists on Windows already)
 -#include <cstring>
 -
 -namespace std
 -{
 -template<>
 -struct char_traits<U16>
 -{
 -	typedef U16 		char_type;
 -	typedef int 	    int_type;
 -	typedef streampos 	pos_type;
 -	typedef streamoff 	off_type;
 -	typedef mbstate_t 	state_type;
 -	
 -	static void 
 -		assign(char_type& __c1, const char_type& __c2)
 -	{ __c1 = __c2; }
 -	
 -	static bool 
 -		eq(const char_type& __c1, const char_type& __c2)
 -	{ return __c1 == __c2; }
 -	
 -	static bool 
 -		lt(const char_type& __c1, const char_type& __c2)
 -	{ return __c1 < __c2; }
 -	
 -	static int 
 -		compare(const char_type* __s1, const char_type* __s2, size_t __n)
 -	{ return memcmp(__s1, __s2, __n * sizeof(char_type)); }
 -	
 -	static size_t
 -		length(const char_type* __s)
 -	{
 -		const char_type *cur_char = __s;
 -		while (*cur_char != 0)
 -		{
 -			++cur_char;
 -		}
 -		return cur_char - __s;
 -	}
 -	
 -	static const char_type* 
 -		find(const char_type* __s, size_t __n, const char_type& __a)
 -	{ return static_cast<const char_type*>(memchr(__s, __a, __n * sizeof(char_type))); }
 -	
 -	static char_type* 
 -		move(char_type* __s1, const char_type* __s2, size_t __n)
 -	{ return static_cast<char_type*>(memmove(__s1, __s2, __n * sizeof(char_type))); }
 -	
 -	static char_type* 
 -		copy(char_type* __s1, const char_type* __s2, size_t __n)
 -	{  return static_cast<char_type*>(memcpy(__s1, __s2, __n * sizeof(char_type))); }	/* Flawfinder: ignore */
 -	
 -	static char_type* 
 -		assign(char_type* __s, size_t __n, char_type __a)
 -	{ 
 -		// This isn't right.
 -		//return static_cast<char_type*>(memset(__s, __a, __n * sizeof(char_type))); 
 -		
 -		// I don't think there's a standard 'memset' for 16-bit values.
 -		// Do this the old-fashioned way.
 -		
 -		size_t __i;
 -		for(__i = 0; __i < __n; __i++)
 -		{
 -			__s[__i] = __a;
 -		}
 -		return __s; 
 -	}
 -	
 -	static char_type 
 -		to_char_type(const int_type& __c)
 -	{ return static_cast<char_type>(__c); }
 -	
 -	static int_type 
 -		to_int_type(const char_type& __c)
 -	{ return static_cast<int_type>(__c); }
 -	
 -	static bool 
 -		eq_int_type(const int_type& __c1, const int_type& __c2)
 -	{ return __c1 == __c2; }
 -	
 -	static int_type 
 -		eof() { return static_cast<int_type>(EOF); }
 -	
 -	static int_type 
 -		not_eof(const int_type& __c)
 -      { return (__c == eof()) ? 0 : __c; }
 -  };
 -};
 -#endif
 -
 -class LL_COMMON_API LLStringOps
 -{
 -private:
 -	static long sPacificTimeOffset;
 -	static long sLocalTimeOffset;
 -	static bool sPacificDaylightTime;
 -	static std::map<std::string, std::string> datetimeToCodes;
 -
 -public:
 -	static char toUpper(char elem) { return toupper((unsigned char)elem); }
 -	static llwchar toUpper(llwchar elem) { return towupper(elem); }
 -	
 -	static char toLower(char elem) { return tolower((unsigned char)elem); }
 -	static llwchar toLower(llwchar elem) { return towlower(elem); }
 -
 -	static bool isSpace(char elem) { return isspace((unsigned char)elem) != 0; }
 -	static bool isSpace(llwchar elem) { return iswspace(elem) != 0; }
 -
 -	static bool isUpper(char elem) { return isupper((unsigned char)elem) != 0; }
 -	static bool isUpper(llwchar elem) { return iswupper(elem) != 0; }
 -
 -	static bool isLower(char elem) { return islower((unsigned char)elem) != 0; }
 -	static bool isLower(llwchar elem) { return iswlower(elem) != 0; }
 -
 -	static bool isDigit(char a) { return isdigit((unsigned char)a) != 0; }
 -	static bool isDigit(llwchar a) { return iswdigit(a) != 0; }
 -
 -	static bool isPunct(char a) { return ispunct((unsigned char)a) != 0; }
 -	static bool isPunct(llwchar a) { return iswpunct(a) != 0; }
 -
 -	static bool isAlnum(char a) { return isalnum((unsigned char)a) != 0; }
 -	static bool isAlnum(llwchar a) { return iswalnum(a) != 0; }
 -
 -	static S32	collate(const char* a, const char* b) { return strcoll(a, b); }
 -	static S32	collate(const llwchar* a, const llwchar* b);
 -
 -	static void setupDatetimeInfo(bool pacific_daylight_time);
 -	static long getPacificTimeOffset(void) { return sPacificTimeOffset;}
 -	static long getLocalTimeOffset(void) { return sLocalTimeOffset;}
 -	// Is the Pacific time zone (aka server time zone)
 -	// currently in daylight savings time?
 -	static bool getPacificDaylightTime(void) { return sPacificDaylightTime;}
 -
 -	static std::string getDatetimeCode (std::string key);
 -};
 -
 -/**
 - * @brief Return a string constructed from in without crashing if the
 - * pointer is NULL.
 - */
 -LL_COMMON_API std::string ll_safe_string(const char* in);
 -LL_COMMON_API std::string ll_safe_string(const char* in, S32 maxlen);
 -
 -
 -// Allowing assignments from non-strings into format_map_t is apparently
 -// *really* error-prone, so subclass std::string with just basic c'tors.
 -class LLFormatMapString
 -{
 -public:
 -	LLFormatMapString() {};
 -	LLFormatMapString(const char* s) : mString(ll_safe_string(s)) {};
 -	LLFormatMapString(const std::string& s) : mString(s) {};
 -	operator std::string() const { return mString; }
 -	bool operator<(const LLFormatMapString& rhs) const { return mString < rhs.mString; }
 -	std::size_t length() const { return mString.length(); }
 -	
 -private:
 -	std::string mString;
 -};
 -
 -template <class T>
 -class LLStringUtilBase
 -{
 -private:
 -	static std::string sLocale;
 -
 -public:
 -	typedef typename std::basic_string<T>::size_type size_type;
 -	
 -public:
 -	/////////////////////////////////////////////////////////////////////////////////////////
 -	// Static Utility functions that operate on std::strings
 -
 -	static std::basic_string<T> null;
 -	
 -	typedef std::map<LLFormatMapString, LLFormatMapString> format_map_t;
 -	LL_COMMON_API static void getTokens(const std::basic_string<T>& instr, std::vector<std::basic_string<T> >& tokens, const std::basic_string<T>& delims);
 -	LL_COMMON_API static void formatNumber(std::basic_string<T>& numStr, std::basic_string<T> decimals);
 -	LL_COMMON_API static bool formatDatetime(std::basic_string<T>& replacement, std::basic_string<T> token, std::basic_string<T> param, S32 secFromEpoch);
 -	LL_COMMON_API static S32 format(std::basic_string<T>& s, const format_map_t& substitutions);
 -	LL_COMMON_API static S32 format(std::basic_string<T>& s, const LLSD& substitutions);
 -	LL_COMMON_API static bool simpleReplacement(std::basic_string<T>& replacement, std::basic_string<T> token, const format_map_t& substitutions);
 -	LL_COMMON_API static bool simpleReplacement(std::basic_string<T>& replacement, std::basic_string<T> token, const LLSD& substitutions);
 -	static void setLocale (std::string inLocale) {sLocale = inLocale;};
 -	static std::string getLocale (void) {return sLocale;};
 -	
 -	static bool isValidIndex(const std::basic_string<T>& string, size_type i)
 -	{
 -		return !string.empty() && (0 <= i) && (i <= string.size());
 -	}
 -
 -	static void	trimHead(std::basic_string<T>& string);
 -	static void	trimTail(std::basic_string<T>& string);
 -	static void	trim(std::basic_string<T>& string)	{ trimHead(string); trimTail(string); }
 -	static void truncate(std::basic_string<T>& string, size_type count);
 -
 -	static void	toUpper(std::basic_string<T>& string);
 -	static void	toLower(std::basic_string<T>& string);
 -	
 -	// True if this is the head of s.
 -	static BOOL	isHead( const std::basic_string<T>& string, const T* s ); 
 -
 -	/**
 -	 * @brief Returns true if string starts with substr
 -	 *
 -	 * If etither string or substr are empty, this method returns false.
 -	 */
 -	static bool startsWith(
 -		const std::basic_string<T>& string,
 -		const std::basic_string<T>& substr);
 -
 -	/**
 -	 * @brief Returns true if string ends in substr
 -	 *
 -	 * If etither string or substr are empty, this method returns false.
 -	 */
 -	static bool endsWith(
 -		const std::basic_string<T>& string,
 -		const std::basic_string<T>& substr);
 -
 -	static void	addCRLF(std::basic_string<T>& string);
 -	static void	removeCRLF(std::basic_string<T>& string);
 -
 -	static void	replaceTabsWithSpaces( std::basic_string<T>& string, size_type spaces_per_tab );
 -	static void	replaceNonstandardASCII( std::basic_string<T>& string, T replacement );
 -	static void	replaceChar( std::basic_string<T>& string, T target, T replacement );
 -	static void replaceString( std::basic_string<T>& string, std::basic_string<T> target, std::basic_string<T> replacement );
 -	
 -	static BOOL	containsNonprintable(const std::basic_string<T>& string);
 -	static void	stripNonprintable(std::basic_string<T>& string);
 -
 -	/**
 -	 * @brief Unsafe way to make ascii characters. You should probably
 -	 * only call this when interacting with the host operating system.
 -	 * The 1 byte std::string does not work correctly.
 -	 * The 2 and 4 byte std::string probably work, so LLWStringUtil::_makeASCII
 -	 * should work.
 -	 */
 -	static void _makeASCII(std::basic_string<T>& string);
 -
 -	// Conversion to other data types
 -	static BOOL	convertToBOOL(const std::basic_string<T>& string, BOOL& value);
 -	static BOOL	convertToU8(const std::basic_string<T>& string, U8& value);
 -	static BOOL	convertToS8(const std::basic_string<T>& string, S8& value);
 -	static BOOL	convertToS16(const std::basic_string<T>& string, S16& value);
 -	static BOOL	convertToU16(const std::basic_string<T>& string, U16& value);
 -	static BOOL	convertToU32(const std::basic_string<T>& string, U32& value);
 -	static BOOL	convertToS32(const std::basic_string<T>& string, S32& value);
 -	static BOOL	convertToF32(const std::basic_string<T>& string, F32& value);
 -	static BOOL	convertToF64(const std::basic_string<T>& string, F64& value);
 -
 -	/////////////////////////////////////////////////////////////////////////////////////////
 -	// Utility functions for working with char*'s and strings
 -
 -	// Like strcmp but also handles empty strings. Uses
 -	// current locale.
 -	static S32		compareStrings(const T* lhs, const T* rhs);
 -	static S32		compareStrings(const std::basic_string<T>& lhs, const std::basic_string<T>& rhs);
 -	
 -	// case insensitive version of above. Uses current locale on
 -	// Win32, and falls back to a non-locale aware comparison on
 -	// Linux.
 -	static S32		compareInsensitive(const T* lhs, const T* rhs);
 -	static S32		compareInsensitive(const std::basic_string<T>& lhs, const std::basic_string<T>& rhs);
 -
 -	// Case sensitive comparison with good handling of numbers.  Does not use current locale.
 -	// a.k.a. strdictcmp()
 -	static S32		compareDict(const std::basic_string<T>& a, const std::basic_string<T>& b);
 -
 -	// Case *in*sensitive comparison with good handling of numbers.  Does not use current locale.
 -	// a.k.a. strdictcmp()
 -	static S32		compareDictInsensitive(const std::basic_string<T>& a, const std::basic_string<T>& b);
 -
 -	// Puts compareDict() in a form appropriate for LL container classes to use for sorting.
 -	static BOOL		precedesDict( const std::basic_string<T>& a, const std::basic_string<T>& b );
 -
 -	// A replacement for strncpy.
 -	// If the dst buffer is dst_size bytes long or more, ensures that dst is null terminated and holds
 -	// up to dst_size-1 characters of src.
 -	static void		copy(T* dst, const T* src, size_type dst_size);
 -	
 -	// Copies src into dst at a given offset.  
 -	static void		copyInto(std::basic_string<T>& dst, const std::basic_string<T>& src, size_type offset);
 -	
 -	static bool		isPartOfWord(T c) { return (c == (T)'_') || LLStringOps::isAlnum(c); }
 -
 -
 -#ifdef _DEBUG	
 -	LL_COMMON_API static void		testHarness();
 -#endif
 -
 -private:
 -	LL_COMMON_API static size_type getSubstitution(const std::basic_string<T>& instr, size_type& start, std::vector<std::basic_string<T> >& tokens);
 -};
 -
 -template<class T> std::basic_string<T> LLStringUtilBase<T>::null;
 -template<class T> std::string LLStringUtilBase<T>::sLocale;
 -
 -typedef LLStringUtilBase<char> LLStringUtil;
 -typedef LLStringUtilBase<llwchar> LLWStringUtil;
 -typedef std::basic_string<llwchar> LLWString;
 -
 -//@ Use this where we want to disallow input in the form of "foo"
 -//  This is used to catch places where english text is embedded in the code
 -//  instead of in a translatable XUI file.
 -class LLStringExplicit : public std::string
 -{
 -public:
 -	explicit LLStringExplicit(const char* s) : std::string(s) {}
 -	LLStringExplicit(const std::string& s) : std::string(s) {}
 -	LLStringExplicit(const std::string& s, size_type pos, size_type n = std::string::npos) : std::string(s, pos, n) {}
 -};
 -
 -struct LLDictionaryLess
 -{
 -public:
 -	bool operator()(const std::string& a, const std::string& b)
 -	{
 -		return (LLStringUtil::precedesDict(a, b) ? true : false);
 -	}
 -};
 -
 -
 -/**
 - * Simple support functions
 - */
 -
 -/**
 - * @brief chop off the trailing characters in a string.
 - *
 - * This function works on bytes rather than glyphs, so this will
 - * incorrectly truncate non-single byte strings.
 - * Use utf8str_truncate() for utf8 strings
 - * @return a copy of in string minus the trailing count bytes.
 - */
 -inline std::string chop_tail_copy(
 -	const std::string& in,
 -	std::string::size_type count)
 -{
 -	return std::string(in, 0, in.length() - count);
 -}
 -
 -/**
 - * @brief This translates a nybble stored as a hex value from 0-f back
 - * to a nybble in the low order bits of the return byte.
 - */
 -LL_COMMON_API U8 hex_as_nybble(char hex);
 -
 -/**
 - * @brief read the contents of a file into a string.
 - *
 - * Since this function has no concept of character encoding, most
 - * anything you do with this method ill-advised. Please avoid.
 - * @param str [out] The string which will have.
 - * @param filename The full name of the file to read.
 - * @return Returns true on success. If false, str is unmodified.
 - */
 -LL_COMMON_API bool _read_file_into_string(std::string& str, const std::string& filename);
 -LL_COMMON_API bool iswindividual(llwchar elem);
 -
 -/**
 - * Unicode support
 - */
 -
 -// Make the incoming string a utf8 string. Replaces any unknown glyph
 -// with the UNKOWN_CHARACTER. Once any unknown glph is found, the rest
 -// of the data may not be recovered.
 -LL_COMMON_API std::string rawstr_to_utf8(const std::string& raw);
 -
 -//
 -// We should never use UTF16 except when communicating with Win32!
 -//
 -typedef std::basic_string<U16> llutf16string;
 -
 -LL_COMMON_API LLWString utf16str_to_wstring(const llutf16string &utf16str, S32 len);
 -LL_COMMON_API LLWString utf16str_to_wstring(const llutf16string &utf16str);
 -
 -LL_COMMON_API llutf16string wstring_to_utf16str(const LLWString &utf32str, S32 len);
 -LL_COMMON_API llutf16string wstring_to_utf16str(const LLWString &utf32str);
 -
 -LL_COMMON_API llutf16string utf8str_to_utf16str ( const std::string& utf8str, S32 len);
 -LL_COMMON_API llutf16string utf8str_to_utf16str ( const std::string& utf8str );
 -
 -LL_COMMON_API LLWString utf8str_to_wstring(const std::string &utf8str, S32 len);
 -LL_COMMON_API LLWString utf8str_to_wstring(const std::string &utf8str);
 -// Same function, better name. JC
 -inline LLWString utf8string_to_wstring(const std::string& utf8_string) { return utf8str_to_wstring(utf8_string); }
 -
 -//
 -LL_COMMON_API S32 wchar_to_utf8chars(llwchar inchar, char* outchars);
 -
 -LL_COMMON_API std::string wstring_to_utf8str(const LLWString &utf32str, S32 len);
 -LL_COMMON_API std::string wstring_to_utf8str(const LLWString &utf32str);
 -
 -LL_COMMON_API std::string utf16str_to_utf8str(const llutf16string &utf16str, S32 len);
 -LL_COMMON_API std::string utf16str_to_utf8str(const llutf16string &utf16str);
 -
 -// Length of this UTF32 string in bytes when transformed to UTF8
 -LL_COMMON_API S32 wstring_utf8_length(const LLWString& wstr); 
 -
 -// Length in bytes of this wide char in a UTF8 string
 -LL_COMMON_API S32 wchar_utf8_length(const llwchar wc); 
 -
 -LL_COMMON_API std::string utf8str_tolower(const std::string& utf8str);
 -
 -// Length in llwchar (UTF-32) of the first len units (16 bits) of the given UTF-16 string.
 -LL_COMMON_API S32 utf16str_wstring_length(const llutf16string &utf16str, S32 len);
 -
 -// Length in utf16string (UTF-16) of wlen wchars beginning at woffset.
 -LL_COMMON_API S32 wstring_utf16_length(const LLWString & wstr, S32 woffset, S32 wlen);
 -
 -// Length in wstring (i.e., llwchar count) of a part of a wstring specified by utf16 length (i.e., utf16 units.)
 -LL_COMMON_API S32 wstring_wstring_length_from_utf16_length(const LLWString & wstr, S32 woffset, S32 utf16_length, BOOL *unaligned = NULL);
 -
 -/**
 - * @brief Properly truncate a utf8 string to a maximum byte count.
 - * 
 - * The returned string may be less than max_len if the truncation
 - * happens in the middle of a glyph. If max_len is longer than the
 - * string passed in, the return value == utf8str.
 - * @param utf8str A valid utf8 string to truncate.
 - * @param max_len The maximum number of bytes in the return value.
 - * @return Returns a valid utf8 string with byte count <= max_len.
 - */
 -LL_COMMON_API std::string utf8str_truncate(const std::string& utf8str, const S32 max_len);
 -
 -LL_COMMON_API std::string utf8str_trim(const std::string& utf8str);
 -
 -LL_COMMON_API S32 utf8str_compare_insensitive(
 -	const std::string& lhs,
 -	const std::string& rhs);
 -
 -/**
 - * @brief Replace all occurences of target_char with replace_char
 - *
 - * @param utf8str A utf8 string to process.
 - * @param target_char The wchar to be replaced
 - * @param replace_char The wchar which is written on replace
 - */
 -LL_COMMON_API std::string utf8str_substChar(
 -	const std::string& utf8str,
 -	const llwchar target_char,
 -	const llwchar replace_char);
 -
 -LL_COMMON_API std::string utf8str_makeASCII(const std::string& utf8str);
 -
 -// Hack - used for evil notecards.
 -LL_COMMON_API std::string mbcsstring_makeASCII(const std::string& str); 
 -
 -LL_COMMON_API std::string utf8str_removeCRLF(const std::string& utf8str);
 -
 -
 -#if LL_WINDOWS
 -/* @name Windows string helpers
 - */
 -//@{
 -
 -/**
 - * @brief Implementation the expected snprintf interface.
 - *
 - * If the size of the passed in buffer is not large enough to hold the string,
 - * two bad things happen:
 - * 1. resulting formatted string is NOT null terminated
 - * 2. Depending on the platform, the return value could be a) the required
 - *    size of the buffer to copy the entire formatted string or b) -1.
 - *    On Windows with VS.Net 2003, it returns -1 e.g. 
 - *
 - * safe_snprintf always adds a NULL terminator so that the caller does not
 - * need to check for return value or need to add the NULL terminator.
 - * It does not, however change the return value - to let the caller know
 - * that the passed in buffer size was not large enough to hold the
 - * formatted string.
 - *
 - */
 -
 -// Deal with the differeneces on Windows
 -namespace snprintf_hack
 -{
 -	LL_COMMON_API int snprintf(char *str, size_t size, const char *format, ...);
 -}
 -
 -using snprintf_hack::snprintf;
 -
 -/**
 - * @brief Convert a wide string to std::string
 - *
 - * This replaces the unsafe W2A macro from ATL.
 - */
 -LL_COMMON_API std::string ll_convert_wide_to_string(const wchar_t* in);
 -
 -//@}
 -#endif // LL_WINDOWS
 -
 -/**
 - * Many of the 'strip' and 'replace' methods of LLStringUtilBase need
 - * specialization to work with the signed char type.
 - * Sadly, it is not possible (AFAIK) to specialize a single method of
 - * a template class.
 - * That stuff should go here.
 - */
 -namespace LLStringFn
 -{
 -	/**
 -	 * @brief Replace all non-printable characters with replacement in
 -	 * string.
 -	 * NOTE - this will zap non-ascii
 -	 *
 -	 * @param [in,out] string the to modify. out value is the string
 -	 * with zero non-printable characters.
 -	 * @param The replacement character. use LL_UNKNOWN_CHAR if unsure.
 -	 */
 -	LL_COMMON_API void replace_nonprintable_in_ascii(
 -		std::basic_string<char>& string,
 -		char replacement);
 -
 -
 -	/**
 -	 * @brief Replace all non-printable characters and pipe characters
 -	 * with replacement in a string.
 -	 * NOTE - this will zap non-ascii
 -	 *
 -	 * @param [in,out] the string to modify. out value is the string
 -	 * with zero non-printable characters and zero pipe characters.
 -	 * @param The replacement character. use LL_UNKNOWN_CHAR if unsure.
 -	 */
 -	LL_COMMON_API void replace_nonprintable_and_pipe_in_ascii(std::basic_string<char>& str,
 -									   char replacement);
 -
 -
 -	/**
 -	 * @brief Remove all characters that are not allowed in XML 1.0.
 -	 * Returns a copy of the string with those characters removed.
 -	 * Works with US ASCII and UTF-8 encoded strings.  JC
 -	 */
 -	LL_COMMON_API std::string strip_invalid_xml(const std::string& input);
 -
 -
 -	/**
 -	 * @brief Replace all control characters (0 <= c < 0x20) with replacement in
 -	 * string.   This is safe for utf-8
 -	 *
 -	 * @param [in,out] string the to modify. out value is the string
 -	 * with zero non-printable characters.
 -	 * @param The replacement character. use LL_UNKNOWN_CHAR if unsure.
 -	 */
 -	LL_COMMON_API void replace_ascii_controlchars(
 -		std::basic_string<char>& string,
 -		char replacement);
 -}
 -
 -////////////////////////////////////////////////////////////
 -// NOTE: LLStringUtil::format, getTokens, and support functions moved to llstring.cpp.
 -// There is no LLWStringUtil::format implementation currently.
 -// Calling thse for anything other than LLStringUtil will produce link errors.
 -
 -////////////////////////////////////////////////////////////
 -
 -
 -// static
 -template<class T> 
 -S32 LLStringUtilBase<T>::compareStrings(const T* lhs, const T* rhs)
 -{	
 -	S32 result;
 -	if( lhs == rhs )
 -	{
 -		result = 0;
 -	}
 -	else
 -	if ( !lhs || !lhs[0] )
 -	{
 -		result = ((!rhs || !rhs[0]) ? 0 : 1);
 -	}
 -	else
 -	if ( !rhs || !rhs[0])
 -	{
 -		result = -1;
 -	}
 -	else
 -	{
 -		result = LLStringOps::collate(lhs, rhs);
 -	}
 -	return result;
 -}
 -
 -//static 
 -template<class T> 
 -S32 LLStringUtilBase<T>::compareStrings(const std::basic_string<T>& lhs, const std::basic_string<T>& rhs)
 -{
 -	return LLStringOps::collate(lhs.c_str(), rhs.c_str());
 -}
 -
 -// static
 -template<class T> 
 -S32 LLStringUtilBase<T>::compareInsensitive(const T* lhs, const T* rhs )
 -{
 -	S32 result;
 -	if( lhs == rhs )
 -	{
 -		result = 0;
 -	}
 -	else
 -	if ( !lhs || !lhs[0] )
 -	{
 -		result = ((!rhs || !rhs[0]) ? 0 : 1);
 -	}
 -	else
 -	if ( !rhs || !rhs[0] )
 -	{
 -		result = -1;
 -	}
 -	else
 -	{
 -		std::basic_string<T> lhs_string(lhs);
 -		std::basic_string<T> rhs_string(rhs);
 -		LLStringUtilBase<T>::toUpper(lhs_string);
 -		LLStringUtilBase<T>::toUpper(rhs_string);
 -		result = LLStringOps::collate(lhs_string.c_str(), rhs_string.c_str());
 -	}
 -	return result;
 -}
 -
 -//static 
 -template<class T> 
 -S32 LLStringUtilBase<T>::compareInsensitive(const std::basic_string<T>& lhs, const std::basic_string<T>& rhs)
 -{
 -	std::basic_string<T> lhs_string(lhs);
 -	std::basic_string<T> rhs_string(rhs);
 -	LLStringUtilBase<T>::toUpper(lhs_string);
 -	LLStringUtilBase<T>::toUpper(rhs_string);
 -	return LLStringOps::collate(lhs_string.c_str(), rhs_string.c_str());
 -}
 -
 -// Case sensitive comparison with good handling of numbers.  Does not use current locale.
 -// a.k.a. strdictcmp()
 -
 -//static 
 -template<class T>
 -S32 LLStringUtilBase<T>::compareDict(const std::basic_string<T>& astr, const std::basic_string<T>& bstr)
 -{
 -	const T* a = astr.c_str();
 -	const T* b = bstr.c_str();
 -	T ca, cb;
 -	S32 ai, bi, cnt = 0;
 -	S32 bias = 0;
 -
 -	ca = *(a++);
 -	cb = *(b++);
 -	while( ca && cb ){
 -		if( bias==0 ){
 -			if( LLStringOps::isUpper(ca) ){ ca = LLStringOps::toLower(ca); bias--; }
 -			if( LLStringOps::isUpper(cb) ){ cb = LLStringOps::toLower(cb); bias++; }
 -		}else{
 -			if( LLStringOps::isUpper(ca) ){ ca = LLStringOps::toLower(ca); }
 -			if( LLStringOps::isUpper(cb) ){ cb = LLStringOps::toLower(cb); }
 -		}
 -		if( LLStringOps::isDigit(ca) ){
 -			if( cnt-->0 ){
 -				if( cb!=ca ) break;
 -			}else{
 -				if( !LLStringOps::isDigit(cb) ) break;
 -				for(ai=0; LLStringOps::isDigit(a[ai]); ai++);
 -				for(bi=0; LLStringOps::isDigit(b[bi]); bi++);
 -				if( ai<bi ){ ca=0; break; }
 -				if( bi<ai ){ cb=0; break; }
 -				if( ca!=cb ) break;
 -				cnt = ai;
 -			}
 -		}else if( ca!=cb ){   break;
 -		}
 -		ca = *(a++);
 -		cb = *(b++);
 -	}
 -	if( ca==cb ) ca += bias;
 -	return ca-cb;
 -}
 -
 -// static
 -template<class T>
 -S32 LLStringUtilBase<T>::compareDictInsensitive(const std::basic_string<T>& astr, const std::basic_string<T>& bstr)
 -{
 -	const T* a = astr.c_str();
 -	const T* b = bstr.c_str();
 -	T ca, cb;
 -	S32 ai, bi, cnt = 0;
 -
 -	ca = *(a++);
 -	cb = *(b++);
 -	while( ca && cb ){
 -		if( LLStringOps::isUpper(ca) ){ ca = LLStringOps::toLower(ca); }
 -		if( LLStringOps::isUpper(cb) ){ cb = LLStringOps::toLower(cb); }
 -		if( LLStringOps::isDigit(ca) ){
 -			if( cnt-->0 ){
 -				if( cb!=ca ) break;
 -			}else{
 -				if( !LLStringOps::isDigit(cb) ) break;
 -				for(ai=0; LLStringOps::isDigit(a[ai]); ai++);
 -				for(bi=0; LLStringOps::isDigit(b[bi]); bi++);
 -				if( ai<bi ){ ca=0; break; }
 -				if( bi<ai ){ cb=0; break; }
 -				if( ca!=cb ) break;
 -				cnt = ai;
 -			}
 -		}else if( ca!=cb ){   break;
 -		}
 -		ca = *(a++);
 -		cb = *(b++);
 -	}
 -	return ca-cb;
 -}
 -
 -// Puts compareDict() in a form appropriate for LL container classes to use for sorting.
 -// static 
 -template<class T> 
 -BOOL LLStringUtilBase<T>::precedesDict( const std::basic_string<T>& a, const std::basic_string<T>& b )
 -{
 -	if( a.size() && b.size() )
 -	{
 -		return (LLStringUtilBase<T>::compareDict(a.c_str(), b.c_str()) < 0);
 -	}
 -	else
 -	{
 -		return (!b.empty());
 -	}
 -}
 -
 -//static
 -template<class T> 
 -void LLStringUtilBase<T>::toUpper(std::basic_string<T>& string)	
 -{ 
 -	if( !string.empty() )
 -	{ 
 -		std::transform(
 -			string.begin(),
 -			string.end(),
 -			string.begin(),
 -			(T(*)(T)) &LLStringOps::toUpper);
 -	}
 -}
 -
 -//static
 -template<class T> 
 -void LLStringUtilBase<T>::toLower(std::basic_string<T>& string)
 -{ 
 -	if( !string.empty() )
 -	{ 
 -		std::transform(
 -			string.begin(),
 -			string.end(),
 -			string.begin(),
 -			(T(*)(T)) &LLStringOps::toLower);
 -	}
 -}
 -
 -//static
 -template<class T> 
 -void LLStringUtilBase<T>::trimHead(std::basic_string<T>& string)
 -{			
 -	if( !string.empty() )
 -	{
 -		size_type i = 0;
 -		while( i < string.length() && LLStringOps::isSpace( string[i] ) )
 -		{
 -			i++;
 -		}
 -		string.erase(0, i);
 -	}
 -}
 -
 -//static
 -template<class T> 
 -void LLStringUtilBase<T>::trimTail(std::basic_string<T>& string)
 -{			
 -	if( string.size() )
 -	{
 -		size_type len = string.length();
 -		size_type i = len;
 -		while( i > 0 && LLStringOps::isSpace( string[i-1] ) )
 -		{
 -			i--;
 -		}
 -
 -		string.erase( i, len - i );
 -	}
 -}
 -
 -
 -// Replace line feeds with carriage return-line feed pairs.
 -//static
 -template<class T>
 -void LLStringUtilBase<T>::addCRLF(std::basic_string<T>& string)
 -{
 -	const T LF = 10;
 -	const T CR = 13;
 -
 -	// Count the number of line feeds
 -	size_type count = 0;
 -	size_type len = string.size();
 -	size_type i;
 -	for( i = 0; i < len; i++ )
 -	{
 -		if( string[i] == LF )
 -		{
 -			count++;
 -		}
 -	}
 -
 -	// Insert a carriage return before each line feed
 -	if( count )
 -	{
 -		size_type size = len + count;
 -		T *t = new T[size];
 -		size_type j = 0;
 -		for( i = 0; i < len; ++i )
 -		{
 -			if( string[i] == LF )
 -			{
 -				t[j] = CR;
 -				++j;
 -			}
 -			t[j] = string[i];
 -			++j;
 -		}
 -
 -		string.assign(t, size);
 -	}
 -}
 -
 -// Remove all carriage returns
 -//static
 -template<class T> 
 -void LLStringUtilBase<T>::removeCRLF(std::basic_string<T>& string)
 -{
 -	const T CR = 13;
 -
 -	size_type cr_count = 0;
 -	size_type len = string.size();
 -	size_type i;
 -	for( i = 0; i < len - cr_count; i++ )
 -	{
 -		if( string[i+cr_count] == CR )
 -		{
 -			cr_count++;
 -		}
 -
 -		string[i] = string[i+cr_count];
 -	}
 -	string.erase(i, cr_count);
 -}
 -
 -//static
 -template<class T> 
 -void LLStringUtilBase<T>::replaceChar( std::basic_string<T>& string, T target, T replacement )
 -{
 -	size_type found_pos = 0;
 -	while( (found_pos = string.find(target, found_pos)) != std::basic_string<T>::npos ) 
 -	{
 -		string[found_pos] = replacement;
 -		found_pos++; // avoid infinite defeat if target == replacement
 -	}
 -}
 -
 -//static
 -template<class T> 
 -void LLStringUtilBase<T>::replaceString( std::basic_string<T>& string, std::basic_string<T> target, std::basic_string<T> replacement )
 -{
 -	size_type found_pos = 0;
 -	while( (found_pos = string.find(target, found_pos)) != std::basic_string<T>::npos )
 -	{
 -		string.replace( found_pos, target.length(), replacement );
 -		found_pos += replacement.length(); // avoid infinite defeat if replacement contains target
 -	}
 -}
 -
 -//static
 -template<class T> 
 -void LLStringUtilBase<T>::replaceNonstandardASCII( std::basic_string<T>& string, T replacement )
 -{
 -	const char LF = 10;
 -	const S8 MIN = 32;
 -//	const S8 MAX = 127;
 -
 -	size_type len = string.size();
 -	for( size_type i = 0; i < len; i++ )
 -	{
 -		// No need to test MAX < mText[i] because we treat mText[i] as a signed char,
 -		// which has a max value of 127.
 -		if( ( S8(string[i]) < MIN ) && (string[i] != LF) )
 -		{
 -			string[i] = replacement;
 -		}
 -	}
 -}
 -
 -//static
 -template<class T> 
 -void LLStringUtilBase<T>::replaceTabsWithSpaces( std::basic_string<T>& str, size_type spaces_per_tab )
 -{
 -	const T TAB = '\t';
 -	const T SPACE = ' ';
 -
 -	std::basic_string<T> out_str;
 -	// Replace tabs with spaces
 -	for (size_type i = 0; i < str.length(); i++)
 -	{
 -		if (str[i] == TAB)
 -		{
 -			for (size_type j = 0; j < spaces_per_tab; j++)
 -				out_str += SPACE;
 -		}
 -		else
 -		{
 -			out_str += str[i];
 -		}
 -	}
 -	str = out_str;
 -}
 -
 -//static
 -template<class T> 
 -BOOL LLStringUtilBase<T>::containsNonprintable(const std::basic_string<T>& string)
 -{
 -	const char MIN = 32;
 -	BOOL rv = FALSE;
 -	for (size_type i = 0; i < string.size(); i++)
 -	{
 -		if(string[i] < MIN)
 -		{
 -			rv = TRUE;
 -			break;
 -		}
 -	}
 -	return rv;
 -}
 -
 -//static
 -template<class T> 
 -void LLStringUtilBase<T>::stripNonprintable(std::basic_string<T>& string)
 -{
 -	const char MIN = 32;
 -	size_type j = 0;
 -	if (string.empty())
 -	{
 -		return;
 -	}
 -	size_t src_size = string.size();
 -	char* c_string = new char[src_size + 1];
 -	if(c_string == NULL)
 -	{
 -		return;
 -	}
 -	copy(c_string, string.c_str(), src_size+1);
 -	char* write_head = &c_string[0];
 -	for (size_type i = 0; i < src_size; i++)
 -	{
 -		char* read_head = &string[i];
 -		write_head = &c_string[j];
 -		if(!(*read_head < MIN))
 -		{
 -			*write_head = *read_head;
 -			++j;
 -		}
 -	}
 -	c_string[j]= '\0';
 -	string = c_string;
 -	delete []c_string;
 -}
 -
 -template<class T> 
 -void LLStringUtilBase<T>::_makeASCII(std::basic_string<T>& string)
 -{
 -	// Replace non-ASCII chars with LL_UNKNOWN_CHAR
 -	for (size_type i = 0; i < string.length(); i++)
 -	{
 -		if (string[i] > 0x7f)
 -		{
 -			string[i] = LL_UNKNOWN_CHAR;
 -		}
 -	}
 -}
 -
 -// static
 -template<class T> 
 -void LLStringUtilBase<T>::copy( T* dst, const T* src, size_type dst_size )
 -{
 -	if( dst_size > 0 )
 -	{
 -		size_type min_len = 0;
 -		if( src )
 -		{
 -			min_len = llmin( dst_size - 1, strlen( src ) );  /* Flawfinder: ignore */
 -			memcpy(dst, src, min_len * sizeof(T));		/* Flawfinder: ignore */
 -		}
 -		dst[min_len] = '\0';
 -	}
 -}
 -
 -// static
 -template<class T> 
 -void LLStringUtilBase<T>::copyInto(std::basic_string<T>& dst, const std::basic_string<T>& src, size_type offset)
 -{
 -	if ( offset == dst.length() )
 -	{
 -		// special case - append to end of string and avoid expensive
 -		// (when strings are large) string manipulations
 -		dst += src;
 -	}
 -	else
 -	{
 -		std::basic_string<T> tail = dst.substr(offset);
 -
 -		dst = dst.substr(0, offset);
 -		dst += src;
 -		dst += tail;
 -	};
 -}
 -
 -// True if this is the head of s.
 -//static
 -template<class T> 
 -BOOL LLStringUtilBase<T>::isHead( const std::basic_string<T>& string, const T* s ) 
 -{ 
 -	if( string.empty() )
 -	{
 -		// Early exit
 -		return FALSE;
 -	}
 -	else
 -	{
 -		return (strncmp( s, string.c_str(), string.size() ) == 0);
 -	}
 -}
 -
 -// static
 -template<class T> 
 -bool LLStringUtilBase<T>::startsWith(
 -	const std::basic_string<T>& string,
 -	const std::basic_string<T>& substr)
 -{
 -	if(string.empty() || (substr.empty())) return false;
 -	if(0 == string.find(substr)) return true;
 -	return false;
 -}
 -
 -// static
 -template<class T> 
 -bool LLStringUtilBase<T>::endsWith(
 -	const std::basic_string<T>& string,
 -	const std::basic_string<T>& substr)
 -{
 -	if(string.empty() || (substr.empty())) return false;
 -	std::string::size_type idx = string.rfind(substr);
 -	if(std::string::npos == idx) return false;
 -	return (idx == (string.size() - substr.size()));
 -}
 -
 -
 -template<class T> 
 -BOOL LLStringUtilBase<T>::convertToBOOL(const std::basic_string<T>& string, BOOL& value)
 -{
 -	if( string.empty() )
 -	{
 -		return FALSE;
 -	}
 -
 -	std::basic_string<T> temp( string );
 -	trim(temp);
 -	if( 
 -		(temp == "1") || 
 -		(temp == "T") || 
 -		(temp == "t") || 
 -		(temp == "TRUE") || 
 -		(temp == "true") || 
 -		(temp == "True") )
 -	{
 -		value = TRUE;
 -		return TRUE;
 -	}
 -	else
 -	if( 
 -		(temp == "0") || 
 -		(temp == "F") || 
 -		(temp == "f") || 
 -		(temp == "FALSE") || 
 -		(temp == "false") || 
 -		(temp == "False") )
 -	{
 -		value = FALSE;
 -		return TRUE;
 -	}
 -
 -	return FALSE;
 -}
 -
 -template<class T> 
 -BOOL LLStringUtilBase<T>::convertToU8(const std::basic_string<T>& string, U8& value) 
 -{
 -	S32 value32 = 0;
 -	BOOL success = convertToS32(string, value32);
 -	if( success && (U8_MIN <= value32) && (value32 <= U8_MAX) )
 -	{
 -		value = (U8) value32;
 -		return TRUE;
 -	}
 -	return FALSE;
 -}
 -
 -template<class T> 
 -BOOL LLStringUtilBase<T>::convertToS8(const std::basic_string<T>& string, S8& value) 
 -{
 -	S32 value32 = 0;
 -	BOOL success = convertToS32(string, value32);
 -	if( success && (S8_MIN <= value32) && (value32 <= S8_MAX) )
 -	{
 -		value = (S8) value32;
 -		return TRUE;
 -	}
 -	return FALSE;
 -}
 -
 -template<class T> 
 -BOOL LLStringUtilBase<T>::convertToS16(const std::basic_string<T>& string, S16& value) 
 -{
 -	S32 value32 = 0;
 -	BOOL success = convertToS32(string, value32);
 -	if( success && (S16_MIN <= value32) && (value32 <= S16_MAX) )
 -	{
 -		value = (S16) value32;
 -		return TRUE;
 -	}
 -	return FALSE;
 -}
 -
 -template<class T> 
 -BOOL LLStringUtilBase<T>::convertToU16(const std::basic_string<T>& string, U16& value) 
 -{
 -	S32 value32 = 0;
 -	BOOL success = convertToS32(string, value32);
 -	if( success && (U16_MIN <= value32) && (value32 <= U16_MAX) )
 -	{
 -		value = (U16) value32;
 -		return TRUE;
 -	}
 -	return FALSE;
 -}
 -
 -template<class T> 
 -BOOL LLStringUtilBase<T>::convertToU32(const std::basic_string<T>& string, U32& value) 
 -{
 -	if( string.empty() )
 -	{
 -		return FALSE;
 -	}
 -
 -	std::basic_string<T> temp( string );
 -	trim(temp);
 -	U32 v;
 -	std::basic_istringstream<T> i_stream((std::basic_string<T>)temp);
 -	if(i_stream >> v)
 -	{
 -		value = v;
 -		return TRUE;
 -	}
 -	return FALSE;
 -}
 -
 -template<class T> 
 -BOOL LLStringUtilBase<T>::convertToS32(const std::basic_string<T>& string, S32& value) 
 -{
 -	if( string.empty() )
 -	{
 -		return FALSE;
 -	}
 -
 -	std::basic_string<T> temp( string );
 -	trim(temp);
 -	S32 v;
 -	std::basic_istringstream<T> i_stream((std::basic_string<T>)temp);
 -	if(i_stream >> v)
 -	{
 -		//TODO: figure out overflow and underflow reporting here
 -		//if((LONG_MAX == v) || (LONG_MIN == v))
 -		//{
 -		//	// Underflow or overflow
 -		//	return FALSE;
 -		//}
 -
 -		value = v;
 -		return TRUE;
 -	}
 -	return FALSE;
 -}
 -
 -template<class T> 
 -BOOL LLStringUtilBase<T>::convertToF32(const std::basic_string<T>& string, F32& value) 
 -{
 -	F64 value64 = 0.0;
 -	BOOL success = convertToF64(string, value64);
 -	if( success && (-F32_MAX <= value64) && (value64 <= F32_MAX) )
 -	{
 -		value = (F32) value64;
 -		return TRUE;
 -	}
 -	return FALSE;
 -}
 -
 -template<class T> 
 -BOOL LLStringUtilBase<T>::convertToF64(const std::basic_string<T>& string, F64& value)
 -{
 -	if( string.empty() )
 -	{
 -		return FALSE;
 -	}
 -
 -	std::basic_string<T> temp( string );
 -	trim(temp);
 -	F64 v;
 -	std::basic_istringstream<T> i_stream((std::basic_string<T>)temp);
 -	if(i_stream >> v)
 -	{
 -		//TODO: figure out overflow and underflow reporting here
 -		//if( ((-HUGE_VAL == v) || (HUGE_VAL == v))) )
 -		//{
 -		//	// Underflow or overflow
 -		//	return FALSE;
 -		//}
 -
 -		value = v;
 -		return TRUE;
 -	}
 -	return FALSE;
 -}
 -
 -template<class T> 
 -void LLStringUtilBase<T>::truncate(std::basic_string<T>& string, size_type count)
 -{
 -	size_type cur_size = string.size();
 -	string.resize(count < cur_size ? count : cur_size);
 -}
 -
 -#endif  // LL_STRING_H
 +/**  + * @file llstring.h + * @brief String utility functions and std::string class. + * + * $LicenseInfo:firstyear=2001&license=viewergpl$ + *  + * Copyright (c) 2001-2009, Linden Research, Inc. + *  + * Second Life Viewer Source Code + * The source code in this file ("Source Code") is provided by Linden Lab + * to you under the terms of the GNU General Public License, version 2.0 + * ("GPL"), unless you have obtained a separate licensing agreement + * ("Other License"), formally executed by you and Linden Lab.  Terms of + * the GPL can be found in doc/GPL-license.txt in this distribution, or + * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2 + *  + * There are special exceptions to the terms and conditions of the GPL as + * it is applied to this Source Code. View the full text of the exception + * in the file doc/FLOSS-exception.txt in this software distribution, or + * online at + * http://secondlifegrid.net/programs/open_source/licensing/flossexception + *  + * By copying, modifying or distributing this software, you acknowledge + * that you have read and understood your obligations described above, + * and agree to abide by those obligations. + *  + * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO + * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, + * COMPLETENESS OR PERFORMANCE. + * $/LicenseInfo$ + */ + +#ifndef LL_LLSTRING_H +#define LL_LLSTRING_H + +#include <string> +#include <cstdio> +#include <locale> +#include <iomanip> +#include "llsd.h" +#include "llfasttimer.h" + +#if LL_LINUX || LL_SOLARIS +#include <wctype.h> +#include <wchar.h> +#endif + +#include <string.h> + +#if LL_SOLARIS +// stricmp and strnicmp do not exist on Solaris: +#define stricmp strcasecmp +#define strnicmp strncasecmp +#endif + +const char LL_UNKNOWN_CHAR = '?'; + +#if LL_DARWIN || LL_LINUX || LL_SOLARIS +// Template specialization of char_traits for U16s. Only necessary on Mac and Linux (exists on Windows already) +#include <cstring> + +namespace std +{ +template<> +struct char_traits<U16> +{ +	typedef U16 		char_type; +	typedef int 	    int_type; +	typedef streampos 	pos_type; +	typedef streamoff 	off_type; +	typedef mbstate_t 	state_type; +	 +	static void  +		assign(char_type& __c1, const char_type& __c2) +	{ __c1 = __c2; } +	 +	static bool  +		eq(const char_type& __c1, const char_type& __c2) +	{ return __c1 == __c2; } +	 +	static bool  +		lt(const char_type& __c1, const char_type& __c2) +	{ return __c1 < __c2; } +	 +	static int  +		compare(const char_type* __s1, const char_type* __s2, size_t __n) +	{ return memcmp(__s1, __s2, __n * sizeof(char_type)); } +	 +	static size_t +		length(const char_type* __s) +	{ +		const char_type *cur_char = __s; +		while (*cur_char != 0) +		{ +			++cur_char; +		} +		return cur_char - __s; +	} +	 +	static const char_type*  +		find(const char_type* __s, size_t __n, const char_type& __a) +	{ return static_cast<const char_type*>(memchr(__s, __a, __n * sizeof(char_type))); } +	 +	static char_type*  +		move(char_type* __s1, const char_type* __s2, size_t __n) +	{ return static_cast<char_type*>(memmove(__s1, __s2, __n * sizeof(char_type))); } +	 +	static char_type*  +		copy(char_type* __s1, const char_type* __s2, size_t __n) +	{  return static_cast<char_type*>(memcpy(__s1, __s2, __n * sizeof(char_type))); }	/* Flawfinder: ignore */ +	 +	static char_type*  +		assign(char_type* __s, size_t __n, char_type __a) +	{  +		// This isn't right. +		//return static_cast<char_type*>(memset(__s, __a, __n * sizeof(char_type)));  +		 +		// I don't think there's a standard 'memset' for 16-bit values. +		// Do this the old-fashioned way. +		 +		size_t __i; +		for(__i = 0; __i < __n; __i++) +		{ +			__s[__i] = __a; +		} +		return __s;  +	} +	 +	static char_type  +		to_char_type(const int_type& __c) +	{ return static_cast<char_type>(__c); } +	 +	static int_type  +		to_int_type(const char_type& __c) +	{ return static_cast<int_type>(__c); } +	 +	static bool  +		eq_int_type(const int_type& __c1, const int_type& __c2) +	{ return __c1 == __c2; } +	 +	static int_type  +		eof() { return static_cast<int_type>(EOF); } +	 +	static int_type  +		not_eof(const int_type& __c) +      { return (__c == eof()) ? 0 : __c; } +  }; +}; +#endif + +class LL_COMMON_API LLStringOps +{ +private: +	static long sPacificTimeOffset; +	static long sLocalTimeOffset; +	static bool sPacificDaylightTime; +	static std::map<std::string, std::string> datetimeToCodes; + +public: +	static char toUpper(char elem) { return toupper((unsigned char)elem); } +	static llwchar toUpper(llwchar elem) { return towupper(elem); } +	 +	static char toLower(char elem) { return tolower((unsigned char)elem); } +	static llwchar toLower(llwchar elem) { return towlower(elem); } + +	static bool isSpace(char elem) { return isspace((unsigned char)elem) != 0; } +	static bool isSpace(llwchar elem) { return iswspace(elem) != 0; } + +	static bool isUpper(char elem) { return isupper((unsigned char)elem) != 0; } +	static bool isUpper(llwchar elem) { return iswupper(elem) != 0; } + +	static bool isLower(char elem) { return islower((unsigned char)elem) != 0; } +	static bool isLower(llwchar elem) { return iswlower(elem) != 0; } + +	static bool isDigit(char a) { return isdigit((unsigned char)a) != 0; } +	static bool isDigit(llwchar a) { return iswdigit(a) != 0; } + +	static bool isPunct(char a) { return ispunct((unsigned char)a) != 0; } +	static bool isPunct(llwchar a) { return iswpunct(a) != 0; } + +	static bool isAlnum(char a) { return isalnum((unsigned char)a) != 0; } +	static bool isAlnum(llwchar a) { return iswalnum(a) != 0; } + +	static S32	collate(const char* a, const char* b) { return strcoll(a, b); } +	static S32	collate(const llwchar* a, const llwchar* b); + +	static void setupDatetimeInfo(bool pacific_daylight_time); +	static long getPacificTimeOffset(void) { return sPacificTimeOffset;} +	static long getLocalTimeOffset(void) { return sLocalTimeOffset;} +	// Is the Pacific time zone (aka server time zone) +	// currently in daylight savings time? +	static bool getPacificDaylightTime(void) { return sPacificDaylightTime;} + +	static std::string getDatetimeCode (std::string key); +}; + +/** + * @brief Return a string constructed from in without crashing if the + * pointer is NULL. + */ +LL_COMMON_API std::string ll_safe_string(const char* in); +LL_COMMON_API std::string ll_safe_string(const char* in, S32 maxlen); + + +// Allowing assignments from non-strings into format_map_t is apparently +// *really* error-prone, so subclass std::string with just basic c'tors. +class LLFormatMapString +{ +public: +	LLFormatMapString() {}; +	LLFormatMapString(const char* s) : mString(ll_safe_string(s)) {}; +	LLFormatMapString(const std::string& s) : mString(s) {}; +	operator std::string() const { return mString; } +	bool operator<(const LLFormatMapString& rhs) const { return mString < rhs.mString; } +	std::size_t length() const { return mString.length(); } +	 +private: +	std::string mString; +}; + +template <class T> +class LLStringUtilBase +{ +private: +	static std::string sLocale; + +public: +	typedef typename std::basic_string<T>::size_type size_type; +	 +public: +	///////////////////////////////////////////////////////////////////////////////////////// +	// Static Utility functions that operate on std::strings + +	static std::basic_string<T> null; +	 +	typedef std::map<LLFormatMapString, LLFormatMapString> format_map_t; +	LL_COMMON_API static void getTokens(const std::basic_string<T>& instr, std::vector<std::basic_string<T> >& tokens, const std::basic_string<T>& delims); +	LL_COMMON_API static void formatNumber(std::basic_string<T>& numStr, std::basic_string<T> decimals); +	LL_COMMON_API static bool formatDatetime(std::basic_string<T>& replacement, std::basic_string<T> token, std::basic_string<T> param, S32 secFromEpoch); +	LL_COMMON_API static S32 format(std::basic_string<T>& s, const format_map_t& substitutions); +	LL_COMMON_API static S32 format(std::basic_string<T>& s, const LLSD& substitutions); +	LL_COMMON_API static bool simpleReplacement(std::basic_string<T>& replacement, std::basic_string<T> token, const format_map_t& substitutions); +	LL_COMMON_API static bool simpleReplacement(std::basic_string<T>& replacement, std::basic_string<T> token, const LLSD& substitutions); +	static void setLocale (std::string inLocale) {sLocale = inLocale;}; +	static std::string getLocale (void) {return sLocale;}; +	 +	static bool isValidIndex(const std::basic_string<T>& string, size_type i) +	{ +		return !string.empty() && (0 <= i) && (i <= string.size()); +	} + +	static void	trimHead(std::basic_string<T>& string); +	static void	trimTail(std::basic_string<T>& string); +	static void	trim(std::basic_string<T>& string)	{ trimHead(string); trimTail(string); } +	static void truncate(std::basic_string<T>& string, size_type count); + +	static void	toUpper(std::basic_string<T>& string); +	static void	toLower(std::basic_string<T>& string); +	 +	// True if this is the head of s. +	static BOOL	isHead( const std::basic_string<T>& string, const T* s );  + +	/** +	 * @brief Returns true if string starts with substr +	 * +	 * If etither string or substr are empty, this method returns false. +	 */ +	static bool startsWith( +		const std::basic_string<T>& string, +		const std::basic_string<T>& substr); + +	/** +	 * @brief Returns true if string ends in substr +	 * +	 * If etither string or substr are empty, this method returns false. +	 */ +	static bool endsWith( +		const std::basic_string<T>& string, +		const std::basic_string<T>& substr); + +	static void	addCRLF(std::basic_string<T>& string); +	static void	removeCRLF(std::basic_string<T>& string); + +	static void	replaceTabsWithSpaces( std::basic_string<T>& string, size_type spaces_per_tab ); +	static void	replaceNonstandardASCII( std::basic_string<T>& string, T replacement ); +	static void	replaceChar( std::basic_string<T>& string, T target, T replacement ); +	static void replaceString( std::basic_string<T>& string, std::basic_string<T> target, std::basic_string<T> replacement ); +	 +	static BOOL	containsNonprintable(const std::basic_string<T>& string); +	static void	stripNonprintable(std::basic_string<T>& string); + +	/** +	 * @brief Unsafe way to make ascii characters. You should probably +	 * only call this when interacting with the host operating system. +	 * The 1 byte std::string does not work correctly. +	 * The 2 and 4 byte std::string probably work, so LLWStringUtil::_makeASCII +	 * should work. +	 */ +	static void _makeASCII(std::basic_string<T>& string); + +	// Conversion to other data types +	static BOOL	convertToBOOL(const std::basic_string<T>& string, BOOL& value); +	static BOOL	convertToU8(const std::basic_string<T>& string, U8& value); +	static BOOL	convertToS8(const std::basic_string<T>& string, S8& value); +	static BOOL	convertToS16(const std::basic_string<T>& string, S16& value); +	static BOOL	convertToU16(const std::basic_string<T>& string, U16& value); +	static BOOL	convertToU32(const std::basic_string<T>& string, U32& value); +	static BOOL	convertToS32(const std::basic_string<T>& string, S32& value); +	static BOOL	convertToF32(const std::basic_string<T>& string, F32& value); +	static BOOL	convertToF64(const std::basic_string<T>& string, F64& value); + +	///////////////////////////////////////////////////////////////////////////////////////// +	// Utility functions for working with char*'s and strings + +	// Like strcmp but also handles empty strings. Uses +	// current locale. +	static S32		compareStrings(const T* lhs, const T* rhs); +	static S32		compareStrings(const std::basic_string<T>& lhs, const std::basic_string<T>& rhs); +	 +	// case insensitive version of above. Uses current locale on +	// Win32, and falls back to a non-locale aware comparison on +	// Linux. +	static S32		compareInsensitive(const T* lhs, const T* rhs); +	static S32		compareInsensitive(const std::basic_string<T>& lhs, const std::basic_string<T>& rhs); + +	// Case sensitive comparison with good handling of numbers.  Does not use current locale. +	// a.k.a. strdictcmp() +	static S32		compareDict(const std::basic_string<T>& a, const std::basic_string<T>& b); + +	// Case *in*sensitive comparison with good handling of numbers.  Does not use current locale. +	// a.k.a. strdictcmp() +	static S32		compareDictInsensitive(const std::basic_string<T>& a, const std::basic_string<T>& b); + +	// Puts compareDict() in a form appropriate for LL container classes to use for sorting. +	static BOOL		precedesDict( const std::basic_string<T>& a, const std::basic_string<T>& b ); + +	// A replacement for strncpy. +	// If the dst buffer is dst_size bytes long or more, ensures that dst is null terminated and holds +	// up to dst_size-1 characters of src. +	static void		copy(T* dst, const T* src, size_type dst_size); +	 +	// Copies src into dst at a given offset.   +	static void		copyInto(std::basic_string<T>& dst, const std::basic_string<T>& src, size_type offset); +	 +	static bool		isPartOfWord(T c) { return (c == (T)'_') || LLStringOps::isAlnum(c); } + + +#ifdef _DEBUG	 +	LL_COMMON_API static void		testHarness(); +#endif + +private: +	LL_COMMON_API static size_type getSubstitution(const std::basic_string<T>& instr, size_type& start, std::vector<std::basic_string<T> >& tokens); +}; + +template<class T> std::basic_string<T> LLStringUtilBase<T>::null; +template<class T> std::string LLStringUtilBase<T>::sLocale; + +typedef LLStringUtilBase<char> LLStringUtil; +typedef LLStringUtilBase<llwchar> LLWStringUtil; +typedef std::basic_string<llwchar> LLWString; + +//@ Use this where we want to disallow input in the form of "foo" +//  This is used to catch places where english text is embedded in the code +//  instead of in a translatable XUI file. +class LLStringExplicit : public std::string +{ +public: +	explicit LLStringExplicit(const char* s) : std::string(s) {} +	LLStringExplicit(const std::string& s) : std::string(s) {} +	LLStringExplicit(const std::string& s, size_type pos, size_type n = std::string::npos) : std::string(s, pos, n) {} +}; + +struct LLDictionaryLess +{ +public: +	bool operator()(const std::string& a, const std::string& b) +	{ +		return (LLStringUtil::precedesDict(a, b) ? true : false); +	} +}; + + +/** + * Simple support functions + */ + +/** + * @brief chop off the trailing characters in a string. + * + * This function works on bytes rather than glyphs, so this will + * incorrectly truncate non-single byte strings. + * Use utf8str_truncate() for utf8 strings + * @return a copy of in string minus the trailing count bytes. + */ +inline std::string chop_tail_copy( +	const std::string& in, +	std::string::size_type count) +{ +	return std::string(in, 0, in.length() - count); +} + +/** + * @brief This translates a nybble stored as a hex value from 0-f back + * to a nybble in the low order bits of the return byte. + */ +LL_COMMON_API U8 hex_as_nybble(char hex); + +/** + * @brief read the contents of a file into a string. + * + * Since this function has no concept of character encoding, most + * anything you do with this method ill-advised. Please avoid. + * @param str [out] The string which will have. + * @param filename The full name of the file to read. + * @return Returns true on success. If false, str is unmodified. + */ +LL_COMMON_API bool _read_file_into_string(std::string& str, const std::string& filename); +LL_COMMON_API bool iswindividual(llwchar elem); + +/** + * Unicode support + */ + +// Make the incoming string a utf8 string. Replaces any unknown glyph +// with the UNKOWN_CHARACTER. Once any unknown glph is found, the rest +// of the data may not be recovered. +LL_COMMON_API std::string rawstr_to_utf8(const std::string& raw); + +// +// We should never use UTF16 except when communicating with Win32! +// +typedef std::basic_string<U16> llutf16string; + +LL_COMMON_API LLWString utf16str_to_wstring(const llutf16string &utf16str, S32 len); +LL_COMMON_API LLWString utf16str_to_wstring(const llutf16string &utf16str); + +LL_COMMON_API llutf16string wstring_to_utf16str(const LLWString &utf32str, S32 len); +LL_COMMON_API llutf16string wstring_to_utf16str(const LLWString &utf32str); + +LL_COMMON_API llutf16string utf8str_to_utf16str ( const std::string& utf8str, S32 len); +LL_COMMON_API llutf16string utf8str_to_utf16str ( const std::string& utf8str ); + +LL_COMMON_API LLWString utf8str_to_wstring(const std::string &utf8str, S32 len); +LL_COMMON_API LLWString utf8str_to_wstring(const std::string &utf8str); +// Same function, better name. JC +inline LLWString utf8string_to_wstring(const std::string& utf8_string) { return utf8str_to_wstring(utf8_string); } + +// +LL_COMMON_API S32 wchar_to_utf8chars(llwchar inchar, char* outchars); + +LL_COMMON_API std::string wstring_to_utf8str(const LLWString &utf32str, S32 len); +LL_COMMON_API std::string wstring_to_utf8str(const LLWString &utf32str); + +LL_COMMON_API std::string utf16str_to_utf8str(const llutf16string &utf16str, S32 len); +LL_COMMON_API std::string utf16str_to_utf8str(const llutf16string &utf16str); + +// Length of this UTF32 string in bytes when transformed to UTF8 +LL_COMMON_API S32 wstring_utf8_length(const LLWString& wstr);  + +// Length in bytes of this wide char in a UTF8 string +LL_COMMON_API S32 wchar_utf8_length(const llwchar wc);  + +LL_COMMON_API std::string utf8str_tolower(const std::string& utf8str); + +// Length in llwchar (UTF-32) of the first len units (16 bits) of the given UTF-16 string. +LL_COMMON_API S32 utf16str_wstring_length(const llutf16string &utf16str, S32 len); + +// Length in utf16string (UTF-16) of wlen wchars beginning at woffset. +LL_COMMON_API S32 wstring_utf16_length(const LLWString & wstr, S32 woffset, S32 wlen); + +// Length in wstring (i.e., llwchar count) of a part of a wstring specified by utf16 length (i.e., utf16 units.) +LL_COMMON_API S32 wstring_wstring_length_from_utf16_length(const LLWString & wstr, S32 woffset, S32 utf16_length, BOOL *unaligned = NULL); + +/** + * @brief Properly truncate a utf8 string to a maximum byte count. + *  + * The returned string may be less than max_len if the truncation + * happens in the middle of a glyph. If max_len is longer than the + * string passed in, the return value == utf8str. + * @param utf8str A valid utf8 string to truncate. + * @param max_len The maximum number of bytes in the return value. + * @return Returns a valid utf8 string with byte count <= max_len. + */ +LL_COMMON_API std::string utf8str_truncate(const std::string& utf8str, const S32 max_len); + +LL_COMMON_API std::string utf8str_trim(const std::string& utf8str); + +LL_COMMON_API S32 utf8str_compare_insensitive( +	const std::string& lhs, +	const std::string& rhs); + +/** + * @brief Replace all occurences of target_char with replace_char + * + * @param utf8str A utf8 string to process. + * @param target_char The wchar to be replaced + * @param replace_char The wchar which is written on replace + */ +LL_COMMON_API std::string utf8str_substChar( +	const std::string& utf8str, +	const llwchar target_char, +	const llwchar replace_char); + +LL_COMMON_API std::string utf8str_makeASCII(const std::string& utf8str); + +// Hack - used for evil notecards. +LL_COMMON_API std::string mbcsstring_makeASCII(const std::string& str);  + +LL_COMMON_API std::string utf8str_removeCRLF(const std::string& utf8str); + + +#if LL_WINDOWS +/* @name Windows string helpers + */ +//@{ + +/** + * @brief Implementation the expected snprintf interface. + * + * If the size of the passed in buffer is not large enough to hold the string, + * two bad things happen: + * 1. resulting formatted string is NOT null terminated + * 2. Depending on the platform, the return value could be a) the required + *    size of the buffer to copy the entire formatted string or b) -1. + *    On Windows with VS.Net 2003, it returns -1 e.g.  + * + * safe_snprintf always adds a NULL terminator so that the caller does not + * need to check for return value or need to add the NULL terminator. + * It does not, however change the return value - to let the caller know + * that the passed in buffer size was not large enough to hold the + * formatted string. + * + */ + +// Deal with the differeneces on Windows +namespace snprintf_hack +{ +	LL_COMMON_API int snprintf(char *str, size_t size, const char *format, ...); +} + +using snprintf_hack::snprintf; + +/** + * @brief Convert a wide string to std::string + * + * This replaces the unsafe W2A macro from ATL. + */ +LL_COMMON_API std::string ll_convert_wide_to_string(const wchar_t* in); + +//@} +#endif // LL_WINDOWS + +/** + * Many of the 'strip' and 'replace' methods of LLStringUtilBase need + * specialization to work with the signed char type. + * Sadly, it is not possible (AFAIK) to specialize a single method of + * a template class. + * That stuff should go here. + */ +namespace LLStringFn +{ +	/** +	 * @brief Replace all non-printable characters with replacement in +	 * string. +	 * NOTE - this will zap non-ascii +	 * +	 * @param [in,out] string the to modify. out value is the string +	 * with zero non-printable characters. +	 * @param The replacement character. use LL_UNKNOWN_CHAR if unsure. +	 */ +	LL_COMMON_API void replace_nonprintable_in_ascii( +		std::basic_string<char>& string, +		char replacement); + + +	/** +	 * @brief Replace all non-printable characters and pipe characters +	 * with replacement in a string. +	 * NOTE - this will zap non-ascii +	 * +	 * @param [in,out] the string to modify. out value is the string +	 * with zero non-printable characters and zero pipe characters. +	 * @param The replacement character. use LL_UNKNOWN_CHAR if unsure. +	 */ +	LL_COMMON_API void replace_nonprintable_and_pipe_in_ascii(std::basic_string<char>& str, +									   char replacement); + + +	/** +	 * @brief Remove all characters that are not allowed in XML 1.0. +	 * Returns a copy of the string with those characters removed. +	 * Works with US ASCII and UTF-8 encoded strings.  JC +	 */ +	LL_COMMON_API std::string strip_invalid_xml(const std::string& input); + + +	/** +	 * @brief Replace all control characters (0 <= c < 0x20) with replacement in +	 * string.   This is safe for utf-8 +	 * +	 * @param [in,out] string the to modify. out value is the string +	 * with zero non-printable characters. +	 * @param The replacement character. use LL_UNKNOWN_CHAR if unsure. +	 */ +	LL_COMMON_API void replace_ascii_controlchars( +		std::basic_string<char>& string, +		char replacement); +} + +//////////////////////////////////////////////////////////// +// NOTE: LLStringUtil::format, getTokens, and support functions moved to llstring.cpp. +// There is no LLWStringUtil::format implementation currently. +// Calling thse for anything other than LLStringUtil will produce link errors. + +//////////////////////////////////////////////////////////// + + +// static +template<class T>  +S32 LLStringUtilBase<T>::compareStrings(const T* lhs, const T* rhs) +{	 +	S32 result; +	if( lhs == rhs ) +	{ +		result = 0; +	} +	else +	if ( !lhs || !lhs[0] ) +	{ +		result = ((!rhs || !rhs[0]) ? 0 : 1); +	} +	else +	if ( !rhs || !rhs[0]) +	{ +		result = -1; +	} +	else +	{ +		result = LLStringOps::collate(lhs, rhs); +	} +	return result; +} + +//static  +template<class T>  +S32 LLStringUtilBase<T>::compareStrings(const std::basic_string<T>& lhs, const std::basic_string<T>& rhs) +{ +	return LLStringOps::collate(lhs.c_str(), rhs.c_str()); +} + +// static +template<class T>  +S32 LLStringUtilBase<T>::compareInsensitive(const T* lhs, const T* rhs ) +{ +	S32 result; +	if( lhs == rhs ) +	{ +		result = 0; +	} +	else +	if ( !lhs || !lhs[0] ) +	{ +		result = ((!rhs || !rhs[0]) ? 0 : 1); +	} +	else +	if ( !rhs || !rhs[0] ) +	{ +		result = -1; +	} +	else +	{ +		std::basic_string<T> lhs_string(lhs); +		std::basic_string<T> rhs_string(rhs); +		LLStringUtilBase<T>::toUpper(lhs_string); +		LLStringUtilBase<T>::toUpper(rhs_string); +		result = LLStringOps::collate(lhs_string.c_str(), rhs_string.c_str()); +	} +	return result; +} + +//static  +template<class T>  +S32 LLStringUtilBase<T>::compareInsensitive(const std::basic_string<T>& lhs, const std::basic_string<T>& rhs) +{ +	std::basic_string<T> lhs_string(lhs); +	std::basic_string<T> rhs_string(rhs); +	LLStringUtilBase<T>::toUpper(lhs_string); +	LLStringUtilBase<T>::toUpper(rhs_string); +	return LLStringOps::collate(lhs_string.c_str(), rhs_string.c_str()); +} + +// Case sensitive comparison with good handling of numbers.  Does not use current locale. +// a.k.a. strdictcmp() + +//static  +template<class T> +S32 LLStringUtilBase<T>::compareDict(const std::basic_string<T>& astr, const std::basic_string<T>& bstr) +{ +	const T* a = astr.c_str(); +	const T* b = bstr.c_str(); +	T ca, cb; +	S32 ai, bi, cnt = 0; +	S32 bias = 0; + +	ca = *(a++); +	cb = *(b++); +	while( ca && cb ){ +		if( bias==0 ){ +			if( LLStringOps::isUpper(ca) ){ ca = LLStringOps::toLower(ca); bias--; } +			if( LLStringOps::isUpper(cb) ){ cb = LLStringOps::toLower(cb); bias++; } +		}else{ +			if( LLStringOps::isUpper(ca) ){ ca = LLStringOps::toLower(ca); } +			if( LLStringOps::isUpper(cb) ){ cb = LLStringOps::toLower(cb); } +		} +		if( LLStringOps::isDigit(ca) ){ +			if( cnt-->0 ){ +				if( cb!=ca ) break; +			}else{ +				if( !LLStringOps::isDigit(cb) ) break; +				for(ai=0; LLStringOps::isDigit(a[ai]); ai++); +				for(bi=0; LLStringOps::isDigit(b[bi]); bi++); +				if( ai<bi ){ ca=0; break; } +				if( bi<ai ){ cb=0; break; } +				if( ca!=cb ) break; +				cnt = ai; +			} +		}else if( ca!=cb ){   break; +		} +		ca = *(a++); +		cb = *(b++); +	} +	if( ca==cb ) ca += bias; +	return ca-cb; +} + +// static +template<class T> +S32 LLStringUtilBase<T>::compareDictInsensitive(const std::basic_string<T>& astr, const std::basic_string<T>& bstr) +{ +	const T* a = astr.c_str(); +	const T* b = bstr.c_str(); +	T ca, cb; +	S32 ai, bi, cnt = 0; + +	ca = *(a++); +	cb = *(b++); +	while( ca && cb ){ +		if( LLStringOps::isUpper(ca) ){ ca = LLStringOps::toLower(ca); } +		if( LLStringOps::isUpper(cb) ){ cb = LLStringOps::toLower(cb); } +		if( LLStringOps::isDigit(ca) ){ +			if( cnt-->0 ){ +				if( cb!=ca ) break; +			}else{ +				if( !LLStringOps::isDigit(cb) ) break; +				for(ai=0; LLStringOps::isDigit(a[ai]); ai++); +				for(bi=0; LLStringOps::isDigit(b[bi]); bi++); +				if( ai<bi ){ ca=0; break; } +				if( bi<ai ){ cb=0; break; } +				if( ca!=cb ) break; +				cnt = ai; +			} +		}else if( ca!=cb ){   break; +		} +		ca = *(a++); +		cb = *(b++); +	} +	return ca-cb; +} + +// Puts compareDict() in a form appropriate for LL container classes to use for sorting. +// static  +template<class T>  +BOOL LLStringUtilBase<T>::precedesDict( const std::basic_string<T>& a, const std::basic_string<T>& b ) +{ +	if( a.size() && b.size() ) +	{ +		return (LLStringUtilBase<T>::compareDict(a.c_str(), b.c_str()) < 0); +	} +	else +	{ +		return (!b.empty()); +	} +} + +//static +template<class T>  +void LLStringUtilBase<T>::toUpper(std::basic_string<T>& string)	 +{  +	if( !string.empty() ) +	{  +		std::transform( +			string.begin(), +			string.end(), +			string.begin(), +			(T(*)(T)) &LLStringOps::toUpper); +	} +} + +//static +template<class T>  +void LLStringUtilBase<T>::toLower(std::basic_string<T>& string) +{  +	if( !string.empty() ) +	{  +		std::transform( +			string.begin(), +			string.end(), +			string.begin(), +			(T(*)(T)) &LLStringOps::toLower); +	} +} + +//static +template<class T>  +void LLStringUtilBase<T>::trimHead(std::basic_string<T>& string) +{			 +	if( !string.empty() ) +	{ +		size_type i = 0; +		while( i < string.length() && LLStringOps::isSpace( string[i] ) ) +		{ +			i++; +		} +		string.erase(0, i); +	} +} + +//static +template<class T>  +void LLStringUtilBase<T>::trimTail(std::basic_string<T>& string) +{			 +	if( string.size() ) +	{ +		size_type len = string.length(); +		size_type i = len; +		while( i > 0 && LLStringOps::isSpace( string[i-1] ) ) +		{ +			i--; +		} + +		string.erase( i, len - i ); +	} +} + + +// Replace line feeds with carriage return-line feed pairs. +//static +template<class T> +void LLStringUtilBase<T>::addCRLF(std::basic_string<T>& string) +{ +	const T LF = 10; +	const T CR = 13; + +	// Count the number of line feeds +	size_type count = 0; +	size_type len = string.size(); +	size_type i; +	for( i = 0; i < len; i++ ) +	{ +		if( string[i] == LF ) +		{ +			count++; +		} +	} + +	// Insert a carriage return before each line feed +	if( count ) +	{ +		size_type size = len + count; +		T *t = new T[size]; +		size_type j = 0; +		for( i = 0; i < len; ++i ) +		{ +			if( string[i] == LF ) +			{ +				t[j] = CR; +				++j; +			} +			t[j] = string[i]; +			++j; +		} + +		string.assign(t, size); +	} +} + +// Remove all carriage returns +//static +template<class T>  +void LLStringUtilBase<T>::removeCRLF(std::basic_string<T>& string) +{ +	const T CR = 13; + +	size_type cr_count = 0; +	size_type len = string.size(); +	size_type i; +	for( i = 0; i < len - cr_count; i++ ) +	{ +		if( string[i+cr_count] == CR ) +		{ +			cr_count++; +		} + +		string[i] = string[i+cr_count]; +	} +	string.erase(i, cr_count); +} + +//static +template<class T>  +void LLStringUtilBase<T>::replaceChar( std::basic_string<T>& string, T target, T replacement ) +{ +	size_type found_pos = 0; +	while( (found_pos = string.find(target, found_pos)) != std::basic_string<T>::npos )  +	{ +		string[found_pos] = replacement; +		found_pos++; // avoid infinite defeat if target == replacement +	} +} + +//static +template<class T>  +void LLStringUtilBase<T>::replaceString( std::basic_string<T>& string, std::basic_string<T> target, std::basic_string<T> replacement ) +{ +	size_type found_pos = 0; +	while( (found_pos = string.find(target, found_pos)) != std::basic_string<T>::npos ) +	{ +		string.replace( found_pos, target.length(), replacement ); +		found_pos += replacement.length(); // avoid infinite defeat if replacement contains target +	} +} + +//static +template<class T>  +void LLStringUtilBase<T>::replaceNonstandardASCII( std::basic_string<T>& string, T replacement ) +{ +	const char LF = 10; +	const S8 MIN = 32; +//	const S8 MAX = 127; + +	size_type len = string.size(); +	for( size_type i = 0; i < len; i++ ) +	{ +		// No need to test MAX < mText[i] because we treat mText[i] as a signed char, +		// which has a max value of 127. +		if( ( S8(string[i]) < MIN ) && (string[i] != LF) ) +		{ +			string[i] = replacement; +		} +	} +} + +//static +template<class T>  +void LLStringUtilBase<T>::replaceTabsWithSpaces( std::basic_string<T>& str, size_type spaces_per_tab ) +{ +	const T TAB = '\t'; +	const T SPACE = ' '; + +	std::basic_string<T> out_str; +	// Replace tabs with spaces +	for (size_type i = 0; i < str.length(); i++) +	{ +		if (str[i] == TAB) +		{ +			for (size_type j = 0; j < spaces_per_tab; j++) +				out_str += SPACE; +		} +		else +		{ +			out_str += str[i]; +		} +	} +	str = out_str; +} + +//static +template<class T>  +BOOL LLStringUtilBase<T>::containsNonprintable(const std::basic_string<T>& string) +{ +	const char MIN = 32; +	BOOL rv = FALSE; +	for (size_type i = 0; i < string.size(); i++) +	{ +		if(string[i] < MIN) +		{ +			rv = TRUE; +			break; +		} +	} +	return rv; +} + +//static +template<class T>  +void LLStringUtilBase<T>::stripNonprintable(std::basic_string<T>& string) +{ +	const char MIN = 32; +	size_type j = 0; +	if (string.empty()) +	{ +		return; +	} +	size_t src_size = string.size(); +	char* c_string = new char[src_size + 1]; +	if(c_string == NULL) +	{ +		return; +	} +	copy(c_string, string.c_str(), src_size+1); +	char* write_head = &c_string[0]; +	for (size_type i = 0; i < src_size; i++) +	{ +		char* read_head = &string[i]; +		write_head = &c_string[j]; +		if(!(*read_head < MIN)) +		{ +			*write_head = *read_head; +			++j; +		} +	} +	c_string[j]= '\0'; +	string = c_string; +	delete []c_string; +} + +template<class T>  +void LLStringUtilBase<T>::_makeASCII(std::basic_string<T>& string) +{ +	// Replace non-ASCII chars with LL_UNKNOWN_CHAR +	for (size_type i = 0; i < string.length(); i++) +	{ +		if (string[i] > 0x7f) +		{ +			string[i] = LL_UNKNOWN_CHAR; +		} +	} +} + +// static +template<class T>  +void LLStringUtilBase<T>::copy( T* dst, const T* src, size_type dst_size ) +{ +	if( dst_size > 0 ) +	{ +		size_type min_len = 0; +		if( src ) +		{ +			min_len = llmin( dst_size - 1, strlen( src ) );  /* Flawfinder: ignore */ +			memcpy(dst, src, min_len * sizeof(T));		/* Flawfinder: ignore */ +		} +		dst[min_len] = '\0'; +	} +} + +// static +template<class T>  +void LLStringUtilBase<T>::copyInto(std::basic_string<T>& dst, const std::basic_string<T>& src, size_type offset) +{ +	if ( offset == dst.length() ) +	{ +		// special case - append to end of string and avoid expensive +		// (when strings are large) string manipulations +		dst += src; +	} +	else +	{ +		std::basic_string<T> tail = dst.substr(offset); + +		dst = dst.substr(0, offset); +		dst += src; +		dst += tail; +	}; +} + +// True if this is the head of s. +//static +template<class T>  +BOOL LLStringUtilBase<T>::isHead( const std::basic_string<T>& string, const T* s )  +{  +	if( string.empty() ) +	{ +		// Early exit +		return FALSE; +	} +	else +	{ +		return (strncmp( s, string.c_str(), string.size() ) == 0); +	} +} + +// static +template<class T>  +bool LLStringUtilBase<T>::startsWith( +	const std::basic_string<T>& string, +	const std::basic_string<T>& substr) +{ +	if(string.empty() || (substr.empty())) return false; +	if(0 == string.find(substr)) return true; +	return false; +} + +// static +template<class T>  +bool LLStringUtilBase<T>::endsWith( +	const std::basic_string<T>& string, +	const std::basic_string<T>& substr) +{ +	if(string.empty() || (substr.empty())) return false; +	std::string::size_type idx = string.rfind(substr); +	if(std::string::npos == idx) return false; +	return (idx == (string.size() - substr.size())); +} + + +template<class T>  +BOOL LLStringUtilBase<T>::convertToBOOL(const std::basic_string<T>& string, BOOL& value) +{ +	if( string.empty() ) +	{ +		return FALSE; +	} + +	std::basic_string<T> temp( string ); +	trim(temp); +	if(  +		(temp == "1") ||  +		(temp == "T") ||  +		(temp == "t") ||  +		(temp == "TRUE") ||  +		(temp == "true") ||  +		(temp == "True") ) +	{ +		value = TRUE; +		return TRUE; +	} +	else +	if(  +		(temp == "0") ||  +		(temp == "F") ||  +		(temp == "f") ||  +		(temp == "FALSE") ||  +		(temp == "false") ||  +		(temp == "False") ) +	{ +		value = FALSE; +		return TRUE; +	} + +	return FALSE; +} + +template<class T>  +BOOL LLStringUtilBase<T>::convertToU8(const std::basic_string<T>& string, U8& value)  +{ +	S32 value32 = 0; +	BOOL success = convertToS32(string, value32); +	if( success && (U8_MIN <= value32) && (value32 <= U8_MAX) ) +	{ +		value = (U8) value32; +		return TRUE; +	} +	return FALSE; +} + +template<class T>  +BOOL LLStringUtilBase<T>::convertToS8(const std::basic_string<T>& string, S8& value)  +{ +	S32 value32 = 0; +	BOOL success = convertToS32(string, value32); +	if( success && (S8_MIN <= value32) && (value32 <= S8_MAX) ) +	{ +		value = (S8) value32; +		return TRUE; +	} +	return FALSE; +} + +template<class T>  +BOOL LLStringUtilBase<T>::convertToS16(const std::basic_string<T>& string, S16& value)  +{ +	S32 value32 = 0; +	BOOL success = convertToS32(string, value32); +	if( success && (S16_MIN <= value32) && (value32 <= S16_MAX) ) +	{ +		value = (S16) value32; +		return TRUE; +	} +	return FALSE; +} + +template<class T>  +BOOL LLStringUtilBase<T>::convertToU16(const std::basic_string<T>& string, U16& value)  +{ +	S32 value32 = 0; +	BOOL success = convertToS32(string, value32); +	if( success && (U16_MIN <= value32) && (value32 <= U16_MAX) ) +	{ +		value = (U16) value32; +		return TRUE; +	} +	return FALSE; +} + +template<class T>  +BOOL LLStringUtilBase<T>::convertToU32(const std::basic_string<T>& string, U32& value)  +{ +	if( string.empty() ) +	{ +		return FALSE; +	} + +	std::basic_string<T> temp( string ); +	trim(temp); +	U32 v; +	std::basic_istringstream<T> i_stream((std::basic_string<T>)temp); +	if(i_stream >> v) +	{ +		value = v; +		return TRUE; +	} +	return FALSE; +} + +template<class T>  +BOOL LLStringUtilBase<T>::convertToS32(const std::basic_string<T>& string, S32& value)  +{ +	if( string.empty() ) +	{ +		return FALSE; +	} + +	std::basic_string<T> temp( string ); +	trim(temp); +	S32 v; +	std::basic_istringstream<T> i_stream((std::basic_string<T>)temp); +	if(i_stream >> v) +	{ +		//TODO: figure out overflow and underflow reporting here +		//if((LONG_MAX == v) || (LONG_MIN == v)) +		//{ +		//	// Underflow or overflow +		//	return FALSE; +		//} + +		value = v; +		return TRUE; +	} +	return FALSE; +} + +template<class T>  +BOOL LLStringUtilBase<T>::convertToF32(const std::basic_string<T>& string, F32& value)  +{ +	F64 value64 = 0.0; +	BOOL success = convertToF64(string, value64); +	if( success && (-F32_MAX <= value64) && (value64 <= F32_MAX) ) +	{ +		value = (F32) value64; +		return TRUE; +	} +	return FALSE; +} + +template<class T>  +BOOL LLStringUtilBase<T>::convertToF64(const std::basic_string<T>& string, F64& value) +{ +	if( string.empty() ) +	{ +		return FALSE; +	} + +	std::basic_string<T> temp( string ); +	trim(temp); +	F64 v; +	std::basic_istringstream<T> i_stream((std::basic_string<T>)temp); +	if(i_stream >> v) +	{ +		//TODO: figure out overflow and underflow reporting here +		//if( ((-HUGE_VAL == v) || (HUGE_VAL == v))) ) +		//{ +		//	// Underflow or overflow +		//	return FALSE; +		//} + +		value = v; +		return TRUE; +	} +	return FALSE; +} + +template<class T>  +void LLStringUtilBase<T>::truncate(std::basic_string<T>& string, size_type count) +{ +	size_type cur_size = string.size(); +	string.resize(count < cur_size ? count : cur_size); +} + +#endif  // LL_STRING_H diff --git a/indra/llcommon/llthread.h b/indra/llcommon/llthread.h index c3d7650bd9..932d96d940 100644 --- a/indra/llcommon/llthread.h +++ b/indra/llcommon/llthread.h @@ -33,9 +33,7 @@  #ifndef LL_LLTHREAD_H  #define LL_LLTHREAD_H -#include "llapr.h"  #include "llapp.h" -  #include "apr_thread_cond.h"  class LLThread; diff --git a/indra/llcommon/llversionserver.h b/indra/llcommon/llversionserver.h index 71c6fc0591..0f1e59a18c 100644 --- a/indra/llcommon/llversionserver.h +++ b/indra/llcommon/llversionserver.h @@ -36,7 +36,7 @@  const S32 LL_VERSION_MAJOR = 1;  const S32 LL_VERSION_MINOR = 31;  const S32 LL_VERSION_PATCH = 0; -const S32 LL_VERSION_BUILD = 3256; +const S32 LL_VERSION_BUILD = 200030;  const char * const LL_CHANNEL = "Second Life Server"; diff --git a/indra/llcommon/llversionviewer.h b/indra/llcommon/llversionviewer.h index 082d054ba2..540aea4252 100644 --- a/indra/llcommon/llversionviewer.h +++ b/indra/llcommon/llversionviewer.h @@ -36,7 +36,7 @@  const S32 LL_VERSION_MAJOR = 2;  const S32 LL_VERSION_MINOR = 0;  const S32 LL_VERSION_PATCH = 0; -const S32 LL_VERSION_BUILD = 3256; +const S32 LL_VERSION_BUILD = 200030;  const char * const LL_CHANNEL = "Second Life Developer"; diff --git a/indra/llcommon/llworkerthread.cpp b/indra/llcommon/llworkerthread.cpp index 5dda600755..82c736266d 100644 --- a/indra/llcommon/llworkerthread.cpp +++ b/indra/llcommon/llworkerthread.cpp @@ -201,6 +201,7 @@ LLWorkerClass::~LLWorkerClass()  {  	llassert_always(!(mWorkFlags & WCF_WORKING));  	llassert_always(mWorkFlags & WCF_DELETE_REQUESTED); +	llassert_always(!mMutex.isLocked());  	if (mRequestHandle != LLWorkerThread::nullHandle())  	{  		LLWorkerThread::WorkRequest* workreq = (LLWorkerThread::WorkRequest*)mWorkerThread->getRequest(mRequestHandle); diff --git a/indra/llcommon/llworkerthread.h b/indra/llcommon/llworkerthread.h index a12bd52a64..a1e85d2ecc 100644 --- a/indra/llcommon/llworkerthread.h +++ b/indra/llcommon/llworkerthread.h @@ -52,6 +52,7 @@ class LLWorkerClass;  class LL_COMMON_API LLWorkerThread : public LLQueuedThread  { +	friend class LLWorkerClass;  public:  	class WorkRequest : public LLQueuedThread::QueuedRequest  	{ @@ -92,8 +93,11 @@ public:  	handle_t addWorkRequest(LLWorkerClass* workerclass, S32 param, U32 priority = PRIORITY_NORMAL); -	void deleteWorker(LLWorkerClass* workerclass); // schedule for deletion  	S32 getNumDeletes() { return (S32)mDeleteList.size(); } // debug + +private: +	void deleteWorker(LLWorkerClass* workerclass); // schedule for deletion +	  };  //============================================================================  | 
