diff options
Diffstat (limited to 'indra/llcommon')
187 files changed, 9295 insertions, 16948 deletions
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index e4b27c15af..81ccb756e0 100755 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -26,22 +26,20 @@ include_directories( # ${LLCOMMON_LIBRARIES}) set(llcommon_SOURCE_FILES - imageids.cpp indra_constants.cpp llallocator.cpp llallocator_heap_profile.cpp llapp.cpp llapr.cpp llassettype.cpp - llavatarname.cpp llbase32.cpp llbase64.cpp + llbitpack.cpp llcommon.cpp llcommonutils.cpp llcoros.cpp llcrc.cpp llcriticaldamp.cpp - llcursortypes.cpp lldate.cpp lldeadmantimer.cpp lldependencies.cpp @@ -59,7 +57,6 @@ set(llcommon_SOURCE_FILES llfile.cpp llfindlocale.cpp llfixedbuffer.cpp - llfoldertype.cpp llformat.cpp llframetimer.cpp llheartbeat.cpp @@ -69,15 +66,15 @@ set(llcommon_SOURCE_FILES llleaplistener.cpp llliveappconfig.cpp lllivefile.cpp - lllog.cpp llmd5.cpp llmemory.cpp llmemorystream.cpp llmetrics.cpp llmetricperformancetester.cpp llmortician.cpp - lloptioninterface.cpp + llmutex.cpp llptrto.cpp + llpredicate.cpp llprocess.cpp llprocessor.cpp llprocinfo.cpp @@ -90,9 +87,7 @@ set(llcommon_SOURCE_FILES llsdserialize.cpp llsdserialize_xml.cpp llsdutil.cpp - llsecondlifeurls.cpp llsingleton.cpp - llstat.cpp llstacktrace.cpp llstreamqueue.cpp llstreamtools.cpp @@ -100,14 +95,16 @@ set(llcommon_SOURCE_FILES llstringtable.cpp llsys.cpp llthread.cpp + llthreadlocalstorage.cpp llthreadsafequeue.cpp lltimer.cpp + lltrace.cpp + lltraceaccumulators.cpp + lltracerecording.cpp + lltracethreadrecorder.cpp lluri.cpp lluuid.cpp llworkerthread.cpp - metaclass.cpp - metaproperty.cpp - reflective.cpp timing.cpp u64.cpp ) @@ -115,53 +112,35 @@ set(llcommon_SOURCE_FILES set(llcommon_HEADER_FILES CMakeLists.txt - bitpack.h ctype_workaround.h - doublelinkedlist.h fix_macros.h - imageids.h indra_constants.h linden_common.h - linked_lists.h - llaccountingcost.h llalignedarray.h llallocator.h llallocator_heap_profile.h - llagentconstants.h - llavatarname.h llapp.h llapr.h llassettype.h - llassoclist.h - llavatarconstants.h llbase32.h llbase64.h + llbitpack.h llboost.h - llchat.h - llclickaction.h llcommon.h llcommonutils.h llcoros.h llcrc.h llcriticaldamp.h - llcursortypes.h - lldarray.h - lldarrayptr.h lldate.h lldeadmantimer.h lldefs.h lldependencies.h - lldeleteutils.h lldepthstack.h lldictionary.h - lldlinked.h lldoubledispatch.h - lldqueueptr.h llendianswizzle.h - llenum.h llerror.h llerrorcontrol.h - llerrorlegacy.h llerrorthread.h llevent.h lleventapi.h @@ -170,33 +149,25 @@ set(llcommon_HEADER_FILES lleventfilter.h llevents.h lleventemitter.h - llextendedstatus.h llfasttimer.h llfile.h llfindlocale.h llfixedbuffer.h - llfoldertype.h llformat.h llframetimer.h llhandle.h llhash.h llheartbeat.h llhttpstatuscodes.h - llindexedqueue.h + llindexedvector.h llinitparam.h llinstancetracker.h llkeythrottle.h - lllazy.h llleap.h llleaplistener.h lllistenerwrapper.h - lllinkedqueue.h llliveappconfig.h lllivefile.h - lllocalidhashmap.h - lllog.h - lllslconstants.h - llmap.h llmd5.h llmemory.h llmemorystream.h @@ -204,15 +175,13 @@ set(llcommon_HEADER_FILES llmetricperformancetester.h llmortician.h llnametable.h - lloptioninterface.h llpointer.h + llpredicate.h llpreprocessor.h llpriqueuemap.h llprocess.h llprocessor.h llprocinfo.h - llptrskiplist.h - llptrskipmap.h llptrto.h llqueuedthread.h llrand.h @@ -226,16 +195,9 @@ set(llcommon_HEADER_FILES llsdserialize.h llsdserialize_xml.h llsdutil.h - llsecondlifeurls.h llsimplehash.h llsingleton.h - llskiplist.h - llskipmap.h - llsortedvector.h - llstack.h llstacktrace.h - llstat.h - llstatenums.h llstl.h llstreamqueue.h llstreamtools.h @@ -245,29 +207,24 @@ set(llcommon_HEADER_FILES llstaticstringtable.h llsys.h llthread.h + llthreadlocalstorage.h llthreadsafequeue.h lltimer.h + lltrace.h + lltraceaccumulators.h + lltracerecording.h + lltracethreadrecorder.h lltreeiterators.h - lltypeinfolookup.h + llunits.h + llunittype.h lluri.h lluuid.h - lluuidhashmap.h - llversionserver.h + llwin32headers.h + llwin32headerslean.h llworkerthread.h - ll_template_cast.h - metaclass.h - metaclasst.h - metaproperty.h - metapropertyt.h - reflective.h - reflectivet.h - roles_constants.h - stdenums.h stdtypes.h - string_table.h stringize.h timer.h - timing.h u64.h ) @@ -333,16 +290,16 @@ if (LL_TESTS) LL_ADD_INTEGRATION_TEST(llerror "" "${test_libs}") LL_ADD_INTEGRATION_TEST(llframetimer "" "${test_libs}") LL_ADD_INTEGRATION_TEST(llinstancetracker "" "${test_libs}") - LL_ADD_INTEGRATION_TEST(lllazy "" "${test_libs}") LL_ADD_INTEGRATION_TEST(llprocessor "" "${test_libs}") LL_ADD_INTEGRATION_TEST(llprocinfo "" "${test_libs}") LL_ADD_INTEGRATION_TEST(llrand "" "${test_libs}") LL_ADD_INTEGRATION_TEST(llsdserialize "" "${test_libs}") LL_ADD_INTEGRATION_TEST(llsingleton "" "${test_libs}") LL_ADD_INTEGRATION_TEST(llstring "" "${test_libs}") + LL_ADD_INTEGRATION_TEST(lltrace "" "${test_libs}") LL_ADD_INTEGRATION_TEST(lltreeiterators "" "${test_libs}") LL_ADD_INTEGRATION_TEST(lluri "" "${test_libs}") - LL_ADD_INTEGRATION_TEST(reflection "" "${test_libs}") + LL_ADD_INTEGRATION_TEST(llunits "" "${test_libs}") LL_ADD_INTEGRATION_TEST(stringize "" "${test_libs}") LL_ADD_INTEGRATION_TEST(lleventdispatcher "" "${test_libs}") LL_ADD_INTEGRATION_TEST(lleventcoro "" "${test_libs};${BOOST_CONTEXT_LIBRARY};${BOOST_COROUTINE_LIBRARY};${BOOST_SYSTEM_LIBRARY}") diff --git a/indra/llcommon/doublelinkedlist.h b/indra/llcommon/doublelinkedlist.h deleted file mode 100755 index 0aeaa69df3..0000000000 --- a/indra/llcommon/doublelinkedlist.h +++ /dev/null @@ -1,1397 +0,0 @@ -/** - * @file doublelinkedlist.h - * @brief Provides a standard doubly linked list for fun and profit. - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_DOUBLELINKEDLIST_H -#define LL_DOUBLELINKEDLIST_H - -#include "llerror.h" -#include "llrand.h" - -// node that actually contains the data -template <class DATA_TYPE> class LLDoubleLinkedNode -{ -public: - DATA_TYPE *mDatap; - LLDoubleLinkedNode *mNextp; - LLDoubleLinkedNode *mPrevp; - - -public: - // assign the mDatap pointer - LLDoubleLinkedNode(DATA_TYPE *data); - - // destructor does not, by default, destroy associated data - // however, the mDatap must be NULL to ensure that we aren't causing memory leaks - ~LLDoubleLinkedNode(); - - // delete associated data and NULL out pointer - void deleteData(); - - // remove associated data and NULL out pointer - void removeData(); -}; - - -const U32 LLDOUBLE_LINKED_LIST_STATE_STACK_DEPTH = 4; - -template <class DATA_TYPE> class LLDoubleLinkedList -{ -private: - LLDoubleLinkedNode<DATA_TYPE> mHead; // head node - LLDoubleLinkedNode<DATA_TYPE> mTail; // tail node - LLDoubleLinkedNode<DATA_TYPE> *mQueuep; // The node in the batter's box - LLDoubleLinkedNode<DATA_TYPE> *mCurrentp; // The node we're talking about - - // The state stack allows nested exploration of the LLDoubleLinkedList - // but should be used with great care - LLDoubleLinkedNode<DATA_TYPE> *mQueuepStack[LLDOUBLE_LINKED_LIST_STATE_STACK_DEPTH]; - LLDoubleLinkedNode<DATA_TYPE> *mCurrentpStack[LLDOUBLE_LINKED_LIST_STATE_STACK_DEPTH]; - U32 mStateStackDepth; - U32 mCount; - - // mInsertBefore is a pointer to a user-set function that returns - // TRUE if "first" should be located before "second" - // NOTE: mInsertBefore() should never return TRUE when ("first" == "second") - // or never-ending loops can occur - BOOL (*mInsertBefore)(DATA_TYPE *first, DATA_TYPE *second); - -public: - LLDoubleLinkedList(); - - // destructor destroys list and nodes, but not data in nodes - ~LLDoubleLinkedList(); - - // put data into a node and stick it at the front of the list - // set mCurrentp to mQueuep - void addData(DATA_TYPE *data); - - // put data into a node and stick it at the end of the list - // set mCurrentp to mQueuep - void addDataAtEnd(DATA_TYPE *data); - - S32 getLength() const; - // search the list starting at mHead.mNextp and remove the link with mDatap == data - // set mCurrentp to mQueuep - // return TRUE if found, FALSE if not found - BOOL removeData(const DATA_TYPE *data); - - // search the list starting at mHead.mNextp and delete the link with mDatap == data - // set mCurrentp to mQueuep - // return TRUE if found, FALSE if not found - BOOL deleteData(DATA_TYPE *data); - - // remove all nodes from the list and delete the associated data - void deleteAllData(); - - // remove all nodes from the list but do not delete data - void removeAllNodes(); - - BOOL isEmpty(); - - // check to see if data is in list - // set mCurrentp and mQueuep to the target of search if found, otherwise set mCurrentp to mQueuep - // return TRUE if found, FALSE if not found - BOOL checkData(const DATA_TYPE *data); - - // NOTE: This next two funtions are only included here - // for those too familiar with the LLLinkedList template class. - // They are depreciated. resetList() is unecessary while - // getCurrentData() is identical to getNextData() and has - // a misleading name. - // - // The recommended way to loop through a list is as follows: - // - // datap = list.getFirstData(); - // while (datap) - // { - // /* do stuff */ - // datap = list.getNextData(); - // } - - // place mQueuep on mHead node - void resetList(); - - // return the data currently pointed to, - // set mCurrentp to that node and bump mQueuep down the list - // NOTE: this function is identical to getNextData() - DATA_TYPE *getCurrentData(); - - - // reset the list and return the data currently pointed to, - // set mCurrentp to that node and bump mQueuep down the list - DATA_TYPE *getFirstData(); - - - // reset the list and return the data at position n, set mCurentp - // to that node and bump mQueuep down the list - // Note: n=0 will behave like getFirstData() - DATA_TYPE *getNthData(U32 n); - - // reset the list and return the last data in it, - // set mCurrentp to that node and bump mQueuep up the list - DATA_TYPE *getLastData(); - - // return data in mQueuep, - // set mCurrentp mQueuep and bump mQueuep down the list - DATA_TYPE *getNextData(); - - // return the data in mQueuep, - // set mCurrentp to mQueuep and bump mQueuep up the list - DATA_TYPE *getPreviousData(); - - // remove the Node at mCurrentp - // set mCurrentp to mQueuep - void removeCurrentData(); - - // delete the Node at mCurrentp - // set mCurrentp to mQueuep - void deleteCurrentData(); - - // remove the Node at mCurrentp and insert it into newlist - // set mCurrentp to mQueuep - void moveCurrentData(LLDoubleLinkedList<DATA_TYPE> *newlist); - - // insert the node in front of mCurrentp - // set mCurrentp to mQueuep - void insertNode(LLDoubleLinkedNode<DATA_TYPE> *node); - - // insert the data in front of mCurrentp - // set mCurrentp to mQueuep - void insertData(DATA_TYPE *data); - - // if mCurrentp has a previous node then : - // * swaps mCurrentp with its previous - // * set mCurrentp to mQueuep - // (convenient for forward bubble-sort) - // otherwise does nothing - void swapCurrentWithPrevious(); - - // if mCurrentp has a next node then : - // * swaps mCurrentp with its next - // * set mCurrentp to mQueuep - // (convenient for backwards bubble-sort) - // otherwise does nothing - void swapCurrentWithNext(); - - // move mCurrentp to the front of the list - // set mCurrentp to mQueuep - void moveCurrentToFront(); - - // move mCurrentp to the end of the list - // set mCurrentp to mQueuep - void moveCurrentToEnd(); - - // set mInsertBefore - void setInsertBefore(BOOL (*insert_before)(DATA_TYPE *first, DATA_TYPE *second)); - - // add data in front of first node for which mInsertBefore(datap, node->mDatap) returns TRUE - // set mCurrentp to mQueuep - BOOL addDataSorted(DATA_TYPE *datap); - - // sort the list using bubble-sort - // Yes, this is a different name than the same function in LLLinkedList. - // When it comes time for a name consolidation hopefully this one will win. - BOOL bubbleSort(); - - // does a single bubble sort pass on the list - BOOL lazyBubbleSort(); - - // returns TRUE if state successfully pushed (state stack not full) - BOOL pushState(); - - // returns TRUE if state successfully popped (state stack not empty) - BOOL popState(); - - // empties the state stack - void clearStateStack(); - - // randomly move the the links in the list for debug or (Discordian) purposes - // sets mCurrentp and mQueuep to top of list - void scramble(); - -private: - // add node to beginning of list - // set mCurrentp to mQueuep - void addNode(LLDoubleLinkedNode<DATA_TYPE> *node); - - // add node to end of list - // set mCurrentp to mQueuep - void addNodeAtEnd(LLDoubleLinkedNode<DATA_TYPE> *node); -}; - -//#endif - -//////////////////////////////////////////////////////////////////////////////////////////// - -// doublelinkedlist.cpp -// LLDoubleLinkedList template class implementation file. -// Provides a standard doubly linked list for fun and profit. -// -// Copyright 2001, Linden Research, Inc. - -//#include "llerror.h" -//#include "doublelinkedlist.h" - -////////////////////////////////////////////////////////////////////////////////////////// -// LLDoubleLinkedNode -////////////////////////////////////////////////////////////////////////////////////////// - - -// assign the mDatap pointer -template <class DATA_TYPE> -LLDoubleLinkedNode<DATA_TYPE>::LLDoubleLinkedNode(DATA_TYPE *data) : - mDatap(data), mNextp(NULL), mPrevp(NULL) -{ -} - - -// destructor does not, by default, destroy associated data -// however, the mDatap must be NULL to ensure that we aren't causing memory leaks -template <class DATA_TYPE> -LLDoubleLinkedNode<DATA_TYPE>::~LLDoubleLinkedNode() -{ - if (mDatap) - { - llerror("Attempting to call LLDoubleLinkedNode destructor with a non-null mDatap!", 1); - } -} - - -// delete associated data and NULL out pointer -template <class DATA_TYPE> -void LLDoubleLinkedNode<DATA_TYPE>::deleteData() -{ - delete mDatap; - mDatap = NULL; -} - - -template <class DATA_TYPE> -void LLDoubleLinkedNode<DATA_TYPE>::removeData() -{ - mDatap = NULL; -} - - -////////////////////////////////////////////////////////////////////////////////////// -// LLDoubleLinkedList -////////////////////////////////////////////////////////////////////////////////////// - -// <------- up ------- -// -// mCurrentp -// mQueuep | -// | | -// | | -// .------. .------. .------. .------. -// | |---->| |---->| |----->| |-----> NULL -// NULL <-----| |<----| |<----| |<-----| | -// _'------' '------' '------' '------:_ -// .------. /| | | |\ .------. -// NULL <-----|mHead |/ | mQueuep \|mTail |-----> NULL -// | | mCurrentp | | -// '------' '------' -// -------- down ---------> - -template <class DATA_TYPE> -LLDoubleLinkedList<DATA_TYPE>::LLDoubleLinkedList() -: mHead(NULL), mTail(NULL), mQueuep(NULL) -{ - mCurrentp = mHead.mNextp; - mQueuep = mHead.mNextp; - mStateStackDepth = 0; - mCount = 0; - mInsertBefore = NULL; -} - - -// destructor destroys list and nodes, but not data in nodes -template <class DATA_TYPE> -LLDoubleLinkedList<DATA_TYPE>::~LLDoubleLinkedList() -{ - removeAllNodes(); -} - - -// put data into a node and stick it at the front of the list -// doesn't change mCurrentp nor mQueuep -template <class DATA_TYPE> -void LLDoubleLinkedList<DATA_TYPE>::addData(DATA_TYPE *data) -{ - // don't allow NULL to be passed to addData - if (!data) - { - llerror("NULL pointer passed to LLDoubleLinkedList::addData()", 0); - } - - // make the new node - LLDoubleLinkedNode<DATA_TYPE> *temp = new LLDoubleLinkedNode<DATA_TYPE> (data); - - // add the node to the front of the list - temp->mPrevp = NULL; - temp->mNextp = mHead.mNextp; - mHead.mNextp = temp; - - // if there's something in the list, fix its back pointer - if (temp->mNextp) - { - temp->mNextp->mPrevp = temp; - } - // otherwise, fix the tail of the list - else - { - mTail.mPrevp = temp; - } - - mCount++; -} - - -// put data into a node and stick it at the end of the list -template <class DATA_TYPE> -void LLDoubleLinkedList<DATA_TYPE>::addDataAtEnd(DATA_TYPE *data) -{ - // don't allow NULL to be passed to addData - if (!data) - { - llerror("NULL pointer passed to LLDoubleLinkedList::addData()", 0); - } - - // make the new node - LLDoubleLinkedNode<DATA_TYPE> *nodep = new LLDoubleLinkedNode<DATA_TYPE>(data); - - addNodeAtEnd(nodep); - mCount++; -} - - -// search the list starting at mHead.mNextp and remove the link with mDatap == data -// set mCurrentp to mQueuep, or NULL if mQueuep points to node with mDatap == data -// return TRUE if found, FALSE if not found -template <class DATA_TYPE> -BOOL LLDoubleLinkedList<DATA_TYPE>::removeData(const DATA_TYPE *data) -{ - BOOL b_found = FALSE; - // don't allow NULL to be passed to addData - if (!data) - { - llerror("NULL pointer passed to LLDoubleLinkedList::removeData()", 0); - } - - mCurrentp = mHead.mNextp; - - while (mCurrentp) - { - if (mCurrentp->mDatap == data) - { - b_found = TRUE; - - // if there is a next one, fix it - if (mCurrentp->mNextp) - { - mCurrentp->mNextp->mPrevp = mCurrentp->mPrevp; - } - else // we are at end of list - { - mTail.mPrevp = mCurrentp->mPrevp; - } - - // if there is a previous one, fix it - if (mCurrentp->mPrevp) - { - mCurrentp->mPrevp->mNextp = mCurrentp->mNextp; - } - else // we are at beginning of list - { - mHead.mNextp = mCurrentp->mNextp; - } - - // remove the node - mCurrentp->removeData(); - delete mCurrentp; - mCount--; - break; - } - mCurrentp = mCurrentp->mNextp; - } - - // reset the list back to where it was - if (mCurrentp == mQueuep) - { - mCurrentp = mQueuep = NULL; - } - else - { - mCurrentp = mQueuep; - } - - return b_found; -} - - -// search the list starting at mHead.mNextp and delete the link with mDatap == data -// set mCurrentp to mQueuep, or NULL if mQueuep points to node with mDatap == data -// return TRUE if found, FALSE if not found -template <class DATA_TYPE> -BOOL LLDoubleLinkedList<DATA_TYPE>::deleteData(DATA_TYPE *data) -{ - BOOL b_found = FALSE; - // don't allow NULL to be passed to addData - if (!data) - { - llerror("NULL pointer passed to LLDoubleLinkedList::deleteData()", 0); - } - - mCurrentp = mHead.mNextp; - - while (mCurrentp) - { - if (mCurrentp->mDatap == data) - { - b_found = TRUE; - - // if there is a next one, fix it - if (mCurrentp->mNextp) - { - mCurrentp->mNextp->mPrevp = mCurrentp->mPrevp; - } - else // we are at end of list - { - mTail.mPrevp = mCurrentp->mPrevp; - } - - // if there is a previous one, fix it - if (mCurrentp->mPrevp) - { - mCurrentp->mPrevp->mNextp = mCurrentp->mNextp; - } - else // we are at beginning of list - { - mHead.mNextp = mCurrentp->mNextp; - } - - // remove the node - mCurrentp->deleteData(); - delete mCurrentp; - mCount--; - break; - } - mCurrentp = mCurrentp->mNextp; - } - - // reset the list back to where it was - if (mCurrentp == mQueuep) - { - mCurrentp = mQueuep = NULL; - } - else - { - mCurrentp = mQueuep; - } - - return b_found; -} - - -// remove all nodes from the list and delete the associated data -template <class DATA_TYPE> -void LLDoubleLinkedList<DATA_TYPE>::deleteAllData() -{ - mCurrentp = mHead.mNextp; - - while (mCurrentp) - { - mQueuep = mCurrentp->mNextp; - mCurrentp->deleteData(); - delete mCurrentp; - mCurrentp = mQueuep; - } - - // reset mHead and mQueuep - mHead.mNextp = NULL; - mTail.mPrevp = NULL; - mCurrentp = mHead.mNextp; - mQueuep = mHead.mNextp; - mStateStackDepth = 0; - mCount = 0; -} - - -// remove all nodes from the list but do not delete associated data -template <class DATA_TYPE> -void LLDoubleLinkedList<DATA_TYPE>::removeAllNodes() -{ - mCurrentp = mHead.mNextp; - - while (mCurrentp) - { - mQueuep = mCurrentp->mNextp; - mCurrentp->removeData(); - delete mCurrentp; - mCurrentp = mQueuep; - } - - // reset mHead and mCurrentp - mHead.mNextp = NULL; - mTail.mPrevp = NULL; - mCurrentp = mHead.mNextp; - mQueuep = mHead.mNextp; - mStateStackDepth = 0; - mCount = 0; -} - -template <class DATA_TYPE> -S32 LLDoubleLinkedList<DATA_TYPE>::getLength() const -{ -// U32 length = 0; -// for (LLDoubleLinkedNode<DATA_TYPE>* temp = mHead.mNextp; temp != NULL; temp = temp->mNextp) -// { -// length++; -// } - return mCount; -} - -// check to see if data is in list -// set mCurrentp and mQueuep to the target of search if found, otherwise set mCurrentp to mQueuep -// return TRUE if found, FALSE if not found -template <class DATA_TYPE> -BOOL LLDoubleLinkedList<DATA_TYPE>::checkData(const DATA_TYPE *data) -{ - mCurrentp = mHead.mNextp; - - while (mCurrentp) - { - if (mCurrentp->mDatap == data) - { - mQueuep = mCurrentp; - return TRUE; - } - mCurrentp = mCurrentp->mNextp; - } - - mCurrentp = mQueuep; - return FALSE; -} - -// NOTE: This next two funtions are only included here -// for those too familiar with the LLLinkedList template class. -// They are depreciated. resetList() is unecessary while -// getCurrentData() is identical to getNextData() and has -// a misleading name. -// -// The recommended way to loop through a list is as follows: -// -// datap = list.getFirstData(); -// while (datap) -// { -// /* do stuff */ -// datap = list.getNextData(); -// } - - // place mCurrentp and mQueuep on first node - template <class DATA_TYPE> - void LLDoubleLinkedList<DATA_TYPE>::resetList() - { - mCurrentp = mHead.mNextp; - mQueuep = mHead.mNextp; - mStateStackDepth = 0; - } - - - // return the data currently pointed to, - // set mCurrentp to that node and bump mQueuep down the list - template <class DATA_TYPE> - DATA_TYPE* LLDoubleLinkedList<DATA_TYPE>::getCurrentData() - { - if (mQueuep) - { - mCurrentp = mQueuep; - mQueuep = mQueuep->mNextp; - return mCurrentp->mDatap; - } - else - { - return NULL; - } - } - - -// reset the list and return the data currently pointed to, -// set mCurrentp to that node and bump mQueuep down the list -template <class DATA_TYPE> -DATA_TYPE* LLDoubleLinkedList<DATA_TYPE>::getFirstData() -{ - mQueuep = mHead.mNextp; - mCurrentp = mQueuep; - if (mQueuep) - { - mQueuep = mQueuep->mNextp; - return mCurrentp->mDatap; - } - else - { - return NULL; - } -} - - -// reset the list and return the data at position n, set mCurentp -// to that node and bump mQueuep down the list -// Note: n=0 will behave like getFirstData() -template <class DATA_TYPE> -DATA_TYPE* LLDoubleLinkedList<DATA_TYPE>::getNthData(U32 n) -{ - mCurrentp = mHead.mNextp; - - if (mCurrentp) - { - for (U32 i=0; i<n; i++) - { - mCurrentp = mCurrentp->mNextp; - if (!mCurrentp) - { - break; - } - } - } - - if (mCurrentp) - { - // bump mQueuep down the list - mQueuep = mCurrentp->mNextp; - return mCurrentp->mDatap; - } - else - { - mQueuep = NULL; - return NULL; - } -} - - -// reset the list and return the last data in it, -// set mCurrentp to that node and bump mQueuep up the list -template <class DATA_TYPE> -DATA_TYPE* LLDoubleLinkedList<DATA_TYPE>::getLastData() -{ - mQueuep = mTail.mPrevp; - mCurrentp = mQueuep; - if (mQueuep) - { - mQueuep = mQueuep->mPrevp; - return mCurrentp->mDatap; - } - else - { - return NULL; - } -} - - -// return the data in mQueuep, -// set mCurrentp to mQueuep and bump mQueuep down the list -template <class DATA_TYPE> -DATA_TYPE* LLDoubleLinkedList<DATA_TYPE>::getNextData() -{ - if (mQueuep) - { - mCurrentp = mQueuep; - mQueuep = mQueuep->mNextp; - return mCurrentp->mDatap; - } - else - { - return NULL; - } -} - - -// return the data in mQueuep, -// set mCurrentp to mQueuep and bump mQueuep up the list -template <class DATA_TYPE> -DATA_TYPE* LLDoubleLinkedList<DATA_TYPE>::getPreviousData() -{ - if (mQueuep) - { - mCurrentp = mQueuep; - mQueuep = mQueuep->mPrevp; - return mCurrentp->mDatap; - } - else - { - return NULL; - } -} - - -// remove the Node at mCurrentp -// set mCurrentp to mQueuep, or NULL if (mCurrentp == mQueuep) -template <class DATA_TYPE> -void LLDoubleLinkedList<DATA_TYPE>::removeCurrentData() -{ - if (mCurrentp) - { - // if there is a next one, fix it - if (mCurrentp->mNextp) - { - mCurrentp->mNextp->mPrevp = mCurrentp->mPrevp; - } - else // otherwise we are at end of list - { - mTail.mPrevp = mCurrentp->mPrevp; - } - - // if there is a previous one, fix it - if (mCurrentp->mPrevp) - { - mCurrentp->mPrevp->mNextp = mCurrentp->mNextp; - } - else // otherwise we are at beginning of list - { - mHead.mNextp = mCurrentp->mNextp; - } - - // remove the node - mCurrentp->removeData(); - delete mCurrentp; - mCount--; - - // check for redundant pointing - if (mCurrentp == mQueuep) - { - mCurrentp = mQueuep = NULL; - } - else - { - mCurrentp = mQueuep; - } - } -} - - -// delete the Node at mCurrentp -// set mCurrentp to mQueuep, or NULL if (mCurrentp == mQueuep) -template <class DATA_TYPE> -void LLDoubleLinkedList<DATA_TYPE>::deleteCurrentData() -{ - if (mCurrentp) - { - // remove the node - // if there is a next one, fix it - if (mCurrentp->mNextp) - { - mCurrentp->mNextp->mPrevp = mCurrentp->mPrevp; - } - else // otherwise we are at end of list - { - mTail.mPrevp = mCurrentp->mPrevp; - } - - // if there is a previous one, fix it - if (mCurrentp->mPrevp) - { - mCurrentp->mPrevp->mNextp = mCurrentp->mNextp; - } - else // otherwise we are at beginning of list - { - mHead.mNextp = mCurrentp->mNextp; - } - - // remove the LLDoubleLinkedNode - mCurrentp->deleteData(); - delete mCurrentp; - mCount--; - - // check for redundant pointing - if (mCurrentp == mQueuep) - { - mCurrentp = mQueuep = NULL; - } - else - { - mCurrentp = mQueuep; - } - } -} - - -// remove the Node at mCurrentp and insert it into newlist -// set mCurrentp to mQueuep, or NULL if (mCurrentp == mQueuep) -template <class DATA_TYPE> -void LLDoubleLinkedList<DATA_TYPE>::moveCurrentData(LLDoubleLinkedList<DATA_TYPE> *newlist) -{ - if (mCurrentp) - { - // remove the node - // if there is a next one, fix it - if (mCurrentp->mNextp) - { - mCurrentp->mNextp->mPrevp = mCurrentp->mPrevp; - } - else // otherwise we are at end of list - { - mTail.mPrevp = mCurrentp->mPrevp; - } - - // if there is a previous one, fix it - if (mCurrentp->mPrevp) - { - mCurrentp->mPrevp->mNextp = mCurrentp->mNextp; - } - else // otherwise we are at beginning of list - { - mHead.mNextp = mCurrentp->mNextp; - } - - // move the node to the new list - newlist->addNode(mCurrentp); - - // check for redundant pointing - if (mCurrentp == mQueuep) - { - mCurrentp = mQueuep = NULL; - } - else - { - mCurrentp = mQueuep; - } - } -} - - -// Inserts the node previous to mCurrentp -// set mCurrentp to mQueuep -template <class DATA_TYPE> -void LLDoubleLinkedList<DATA_TYPE>::insertNode(LLDoubleLinkedNode<DATA_TYPE> *nodep) -{ - // don't allow pointer to NULL to be passed - if (!nodep) - { - llerror("NULL pointer passed to LLDoubleLinkedList::insertNode()", 0); - } - if (!nodep->mDatap) - { - llerror("NULL data pointer passed to LLDoubleLinkedList::insertNode()", 0); - } - - if (mCurrentp) - { - if (mCurrentp->mPrevp) - { - nodep->mPrevp = mCurrentp->mPrevp; - nodep->mNextp = mCurrentp; - mCurrentp->mPrevp->mNextp = nodep; - mCurrentp->mPrevp = nodep; - } - else // at beginning of list - { - nodep->mPrevp = NULL; - nodep->mNextp = mCurrentp; - mHead.mNextp = nodep; - mCurrentp->mPrevp = nodep; - } - mCurrentp = mQueuep; - } - else // add to front of list - { - addNode(nodep); - } -} - - -// insert the data in front of mCurrentp -// set mCurrentp to mQueuep -template <class DATA_TYPE> -void LLDoubleLinkedList<DATA_TYPE>::insertData(DATA_TYPE *data) -{ - if (!data) - { - llerror("NULL data pointer passed to LLDoubleLinkedList::insertNode()", 0); - } - LLDoubleLinkedNode<DATA_TYPE> *node = new LLDoubleLinkedNode<DATA_TYPE>(data); - insertNode(node); - mCount++; -} - - -// if mCurrentp has a previous node then : -// * swaps mCurrentp with its previous -// * set mCurrentp to mQueuep -// otherwise does nothing -template <class DATA_TYPE> -void LLDoubleLinkedList<DATA_TYPE>::swapCurrentWithPrevious() -{ - if (mCurrentp) - { - if (mCurrentp->mPrevp) - { - // Pull mCurrentp out of list - mCurrentp->mPrevp->mNextp = mCurrentp->mNextp; - if (mCurrentp->mNextp) - { - mCurrentp->mNextp->mPrevp = mCurrentp->mPrevp; - } - else // mCurrentp was at end of list - { - mTail.mPrevp = mCurrentp->mPrevp; - } - - // Fix mCurrentp's pointers - mCurrentp->mNextp = mCurrentp->mPrevp; - mCurrentp->mPrevp = mCurrentp->mNextp->mPrevp; - mCurrentp->mNextp->mPrevp = mCurrentp; - - if (mCurrentp->mPrevp) - { - // Fix the backward pointer of mCurrentp's new previous - mCurrentp->mPrevp->mNextp = mCurrentp; - } - else // mCurrentp is now at beginning of list - { - mHead.mNextp = mCurrentp; - } - - // Set the list back to the way it was - mCurrentp = mQueuep; - } - } -} - - -// if mCurrentp has a next node then : -// * swaps mCurrentp with its next -// * set mCurrentp to mQueuep -// otherwise does nothing -template <class DATA_TYPE> -void LLDoubleLinkedList<DATA_TYPE>::swapCurrentWithNext() -{ - if (mCurrentp) - { - if (mCurrentp->mNextp) - { - // Pull mCurrentp out of list - mCurrentp->mNextp->mPrevp = mCurrentp->mPrevp; - if (mCurrentp->mPrevp) - { - mCurrentp->mPrevp->mNextp = mCurrentp->mNextp; - } - else // mCurrentp was at beginning of list - { - mHead.mNextp = mCurrentp->mNextp; - } - - // Fix mCurrentp's pointers - mCurrentp->mPrevp = mCurrentp->mNextp; - mCurrentp->mNextp = mCurrentp->mPrevp->mNextp; - mCurrentp->mPrevp->mNextp = mCurrentp; - - if (mCurrentp->mNextp) - { - // Fix the back pointer of mCurrentp's new next - mCurrentp->mNextp->mPrevp = mCurrentp; - } - else // mCurrentp is now at end of list - { - mTail.mPrevp = mCurrentp; - } - - // Set the list back to the way it was - mCurrentp = mQueuep; - } - } -} - -// move mCurrentp to the front of the list -// set mCurrentp to mQueuep -template <class DATA_TYPE> -void LLDoubleLinkedList<DATA_TYPE>::moveCurrentToFront() -{ - if (mCurrentp) - { - // if there is a previous one, fix it - if (mCurrentp->mPrevp) - { - mCurrentp->mPrevp->mNextp = mCurrentp->mNextp; - } - else // otherwise we are at beginning of list - { - // check for redundant pointing - if (mCurrentp == mQueuep) - { - mCurrentp = mQueuep = NULL; - } - else - { - mCurrentp = mQueuep; - } - return; - } - - // if there is a next one, fix it - if (mCurrentp->mNextp) - { - mCurrentp->mNextp->mPrevp = mCurrentp->mPrevp; - } - else // otherwise we are at end of list - { - mTail.mPrevp = mCurrentp->mPrevp; - } - - // add mCurrentp to beginning of list - mCurrentp->mNextp = mHead.mNextp; - mHead.mNextp->mPrevp = mCurrentp; // mHead.mNextp MUST be valid, - // or the list had only one node - // and we would have returned already - mCurrentp->mPrevp = NULL; - mHead.mNextp = mCurrentp; - - // check for redundant pointing - if (mCurrentp == mQueuep) - { - mCurrentp = mQueuep = NULL; - } - else - { - mCurrentp = mQueuep; - } - } - -} - -// move mCurrentp to the end of the list -// set mCurrentp to mQueuep -template <class DATA_TYPE> -void LLDoubleLinkedList<DATA_TYPE>::moveCurrentToEnd() -{ - if (mCurrentp) - { - // if there is a next one, fix it - if (mCurrentp->mNextp) - { - mCurrentp->mNextp->mPrevp = mCurrentp->mPrevp; - } - else // otherwise we are at end of list and we're done - { - // check for redundant pointing - if (mCurrentp == mQueuep) - { - mCurrentp = mQueuep = NULL; - } - else - { - mCurrentp = mQueuep; - } - return; - } - - // if there is a previous one, fix it - if (mCurrentp->mPrevp) - { - mCurrentp->mPrevp->mNextp = mCurrentp->mNextp; - } - else // otherwise we are at beginning of list - { - mHead.mNextp = mCurrentp->mNextp; - } - - // add mCurrentp to end of list - mCurrentp->mPrevp = mTail.mPrevp; - mTail.mPrevp->mNextp = mCurrentp; // mTail.mPrevp MUST be valid, - // or the list had only one node - // and we would have returned already - mCurrentp->mNextp = NULL; - mTail.mPrevp = mCurrentp; - - // check for redundant pointing - if (mCurrentp == mQueuep) - { - mCurrentp = mQueuep = NULL; - } - else - { - mCurrentp = mQueuep; - } - } -} - - -template <class DATA_TYPE> -void LLDoubleLinkedList<DATA_TYPE>::setInsertBefore(BOOL (*insert_before)(DATA_TYPE *first, DATA_TYPE *second) ) -{ - mInsertBefore = insert_before; -} - - -// add data in front of the first node for which mInsertBefore(datap, node->mDatap) returns TRUE -// set mCurrentp to mQueuep -template <class DATA_TYPE> -BOOL LLDoubleLinkedList<DATA_TYPE>::addDataSorted(DATA_TYPE *datap) -{ - // don't allow NULL to be passed to addData() - if (!datap) - { - llerror("NULL pointer passed to LLDoubleLinkedList::addDataSorted()", 0); - } - - // has mInsertBefore not been set? - if (!mInsertBefore) - { - addData(datap); - return FALSE; - } - - // is the list empty? - if (!mHead.mNextp) - { - addData(datap); - return TRUE; - } - - // Note: this step has been added so that the behavior of LLDoubleLinkedList - // is as rigorous as the LLLinkedList class about adding duplicate nodes. - // Duplicate nodes can cause a problem when sorting if mInsertBefore(foo, foo) - // returns TRUE. However, if mInsertBefore(foo, foo) returns FALSE, then there - // shouldn't be any reason to exclude duplicate nodes (as we do here). - if (checkData(datap)) - { - return FALSE; - } - - mCurrentp = mHead.mNextp; - while (mCurrentp) - { - // check to see if datap is already in the list - if (datap == mCurrentp->mDatap) - { - return FALSE; - } - else if (mInsertBefore(datap, mCurrentp->mDatap)) - { - insertData(datap); - return TRUE; - } - mCurrentp = mCurrentp->mNextp; - } - - addDataAtEnd(datap); - return TRUE; -} - - -// bubble-sort until sorted and return TRUE if anything was sorted -// leaves mQueuep pointing at last node that was swapped with its mNextp -// -// NOTE: if you find this function looping for really long times, then you -// probably need to check your implementation of mInsertBefore(a,b) and make -// sure it does not return TRUE when (a == b)! -template <class DATA_TYPE> -BOOL LLDoubleLinkedList<DATA_TYPE>::bubbleSort() -{ - BOOL b_swapped = FALSE; - U32 count = 0; - while (lazyBubbleSort()) - { - b_swapped = TRUE; - if (count++ > 0x7FFFFFFF) - { - llwarning("LLDoubleLinkedList::bubbleSort() : too many passes...", 1); - llwarning(" make sure the mInsertBefore(a, b) does not return TRUE for a == b", 1); - break; - } - } - return b_swapped; -} - - -// do a single bubble-sort pass and return TRUE if anything was sorted -// leaves mQueuep pointing at last node that was swapped with its mNextp -template <class DATA_TYPE> -BOOL LLDoubleLinkedList<DATA_TYPE>::lazyBubbleSort() -{ - // has mInsertBefore been set? - if (!mInsertBefore) - { - return FALSE; - } - - // is list empty? - mCurrentp = mHead.mNextp; - if (!mCurrentp) - { - return FALSE; - } - - BOOL b_swapped = FALSE; - - // the sort will exit after 0x7FFFFFFF nodes or the end of the list, whichever is first - S32 length = 0x7FFFFFFF; - S32 count = 0; - - while (mCurrentp && mCurrentp->mNextp && count<length) - { - if (mInsertBefore(mCurrentp->mNextp->mDatap, mCurrentp->mDatap)) - { - b_swapped = TRUE; - mQueuep = mCurrentp; - swapCurrentWithNext(); // sets mCurrentp to mQueuep - } - count++; - mCurrentp = mCurrentp->mNextp; - } - - return b_swapped; -} - - -template <class DATA_TYPE> -BOOL LLDoubleLinkedList<DATA_TYPE>::pushState() -{ - if (mStateStackDepth < LLDOUBLE_LINKED_LIST_STATE_STACK_DEPTH) - { - *(mQueuepStack + mStateStackDepth) = mQueuep; - *(mCurrentpStack + mStateStackDepth) = mCurrentp; - mStateStackDepth++; - return TRUE; - } - return FALSE; -} - - -template <class DATA_TYPE> -BOOL LLDoubleLinkedList<DATA_TYPE>::popState() -{ - if (mStateStackDepth > 0) - { - mStateStackDepth--; - mQueuep = *(mQueuepStack + mStateStackDepth); - mCurrentp = *(mCurrentpStack + mStateStackDepth); - return TRUE; - } - return FALSE; -} - - -template <class DATA_TYPE> -void LLDoubleLinkedList<DATA_TYPE>::clearStateStack() -{ - mStateStackDepth = 0; -} - -////////////////////////////////////////////////////////////////////////////////////////// -// private members -////////////////////////////////////////////////////////////////////////////////////////// - -// add node to beginning of list -// set mCurrentp to mQueuep -template <class DATA_TYPE> -void LLDoubleLinkedList<DATA_TYPE>::addNode(LLDoubleLinkedNode<DATA_TYPE> *nodep) -{ - // add the node to the front of the list - nodep->mPrevp = NULL; - nodep->mNextp = mHead.mNextp; - mHead.mNextp = nodep; - - // if there's something in the list, fix its back pointer - if (nodep->mNextp) - { - nodep->mNextp->mPrevp = nodep; - } - else // otherwise fix the tail node - { - mTail.mPrevp = nodep; - } - - mCurrentp = mQueuep; -} - - -// add node to end of list -// set mCurrentp to mQueuep -template <class DATA_TYPE> -void LLDoubleLinkedList<DATA_TYPE>::addNodeAtEnd(LLDoubleLinkedNode<DATA_TYPE> *node) -{ - // add the node to the end of the list - node->mNextp = NULL; - node->mPrevp = mTail.mPrevp; - mTail.mPrevp = node; - - // if there's something in the list, fix its back pointer - if (node->mPrevp) - { - node->mPrevp->mNextp = node; - } - else // otherwise fix the head node - { - mHead.mNextp = node; - } - - mCurrentp = mQueuep; -} - - -// randomly move nodes in the list for DEBUG (or Discordian) purposes -// sets mCurrentp and mQueuep to top of list -template <class DATA_TYPE> -void LLDoubleLinkedList<DATA_TYPE>::scramble() -{ - S32 random_number; - DATA_TYPE *datap = getFirstData(); - while(datap) - { - random_number = ll_rand(5); - - if (0 == random_number) - { - removeCurrentData(); - addData(datap); - } - else if (1 == random_number) - { - removeCurrentData(); - addDataAtEnd(datap); - } - else if (2 == random_number) - { - swapCurrentWithPrevious(); - } - else if (3 == random_number) - { - swapCurrentWithNext(); - } - datap = getNextData(); - } - mQueuep = mHead.mNextp; - mCurrentp = mQueuep; -} - -template <class DATA_TYPE> -BOOL LLDoubleLinkedList<DATA_TYPE>::isEmpty() -{ - return (mCount == 0); -} - - -#endif diff --git a/indra/llcommon/imageids.cpp b/indra/llcommon/imageids.cpp deleted file mode 100755 index 7d647e5c36..0000000000 --- a/indra/llcommon/imageids.cpp +++ /dev/null @@ -1,73 +0,0 @@ -/** - * @file imageids.cpp - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" - -#include "imageids.h" - -#include "lluuid.h" - -// -// USE OF THIS FILE IS DEPRECATED -// -// Please use viewerart.ini and the standard -// art import path. // indicates if file is only - // on dataserver, or also - // pre-cached on viewer - -// Grass Images -const LLUUID IMG_SMOKE ("b4ba225c-373f-446d-9f7e-6cb7b5cf9b3d"); // VIEWER - -const LLUUID IMG_DEFAULT ("d2114404-dd59-4a4d-8e6c-49359e91bbf0"); // VIEWER - -const LLUUID IMG_SUN ("cce0f112-878f-4586-a2e2-a8f104bba271"); // dataserver -const LLUUID IMG_MOON ("d07f6eed-b96a-47cd-b51d-400ad4a1c428"); // dataserver -const LLUUID IMG_CLOUD_POOF ("fc4b9f0b-d008-45c6-96a4-01dd947ac621"); // dataserver -const LLUUID IMG_SHOT ("35f217a3-f618-49cf-bbca-c86d486551a9"); // dataserver -const LLUUID IMG_SPARK ("d2e75ac1-d0fb-4532-820e-a20034ac814d"); // dataserver -const LLUUID IMG_FIRE ("aca40aa8-44cf-44ca-a0fa-93e1a2986f82"); // dataserver -const LLUUID IMG_FACE_SELECT ("a85ac674-cb75-4af6-9499-df7c5aaf7a28"); // face selector -const LLUUID IMG_DEFAULT_AVATAR ("c228d1cf-4b5d-4ba8-84f4-899a0796aa97"); // dataserver -const LLUUID IMG_INVISIBLE ("3a367d1c-bef1-6d43-7595-e88c1e3aadb3"); // dataserver - -const LLUUID IMG_EXPLOSION ("68edcf47-ccd7-45b8-9f90-1649d7f12806"); // On dataserver -const LLUUID IMG_EXPLOSION_2 ("21ce046c-83fe-430a-b629-c7660ac78d7c"); // On dataserver -const LLUUID IMG_EXPLOSION_3 ("fedea30a-1be8-47a6-bc06-337a04a39c4b"); // On dataserver -const LLUUID IMG_EXPLOSION_4 ("abf0d56b-82e5-47a2-a8ad-74741bb2c29e"); // On dataserver -const LLUUID IMG_SMOKE_POOF ("1e63e323-5fe0-452e-92f8-b98bd0f764e3"); // On dataserver - -const LLUUID IMG_BIG_EXPLOSION_1 ("5e47a0dc-97bf-44e0-8b40-de06718cee9d"); // On dataserver -const LLUUID IMG_BIG_EXPLOSION_2 ("9c8eca51-53d5-42a7-bb58-cef070395db8"); // On dataserver - -const LLUUID IMG_BLOOM1 ("3c59f7fe-9dc8-47f9-8aaf-a9dd1fbc3bef"); // VIEWER -const LLUUID TERRAIN_DIRT_DETAIL ("0bc58228-74a0-7e83-89bc-5c23464bcec5"); // VIEWER -const LLUUID TERRAIN_GRASS_DETAIL ("63338ede-0037-c4fd-855b-015d77112fc8"); // VIEWER -const LLUUID TERRAIN_MOUNTAIN_DETAIL ("303cd381-8560-7579-23f1-f0a880799740"); // VIEWER -const LLUUID TERRAIN_ROCK_DETAIL ("53a2f406-4895-1d13-d541-d2e3b86bc19c"); // VIEWER - -const LLUUID DEFAULT_WATER_NORMAL ("822ded49-9a6c-f61c-cb89-6df54f42cdf4"); // VIEWER - -const LLUUID IMG_CHECKERBOARD_RGBA ("2585a0f3-4163-6dd1-0f34-ad48cb909e25"); // dataserver - diff --git a/indra/llcommon/imageids.h b/indra/llcommon/imageids.h deleted file mode 100755 index 18c8ecb074..0000000000 --- a/indra/llcommon/imageids.h +++ /dev/null @@ -1,70 +0,0 @@ -/** - * @file imageids.h - * @brief Temporary holder for image IDs - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_IMAGEIDS_H -#define LL_IMAGEIDS_H - -// -// USE OF THIS FILE IS DEPRECATED -// -// Please use viewerart.ini and the standard -// art import path. - -class LLUUID; - -LL_COMMON_API extern const LLUUID IMG_SMOKE; - -LL_COMMON_API extern const LLUUID IMG_DEFAULT; - -LL_COMMON_API extern const LLUUID IMG_SUN; -LL_COMMON_API extern const LLUUID IMG_MOON; -LL_COMMON_API extern const LLUUID IMG_CLOUD_POOF; -LL_COMMON_API extern const LLUUID IMG_SHOT; -LL_COMMON_API extern const LLUUID IMG_SPARK; -LL_COMMON_API extern const LLUUID IMG_FIRE; -LL_COMMON_API extern const LLUUID IMG_FACE_SELECT; -LL_COMMON_API extern const LLUUID IMG_DEFAULT_AVATAR; -LL_COMMON_API extern const LLUUID IMG_INVISIBLE; - -LL_COMMON_API extern const LLUUID IMG_EXPLOSION; -LL_COMMON_API extern const LLUUID IMG_EXPLOSION_2; -LL_COMMON_API extern const LLUUID IMG_EXPLOSION_3; -LL_COMMON_API extern const LLUUID IMG_EXPLOSION_4; -LL_COMMON_API extern const LLUUID IMG_SMOKE_POOF; - -LL_COMMON_API extern const LLUUID IMG_BIG_EXPLOSION_1; -LL_COMMON_API extern const LLUUID IMG_BIG_EXPLOSION_2; - -LL_COMMON_API extern const LLUUID IMG_BLOOM1; -LL_COMMON_API extern const LLUUID TERRAIN_DIRT_DETAIL; -LL_COMMON_API extern const LLUUID TERRAIN_GRASS_DETAIL; -LL_COMMON_API extern const LLUUID TERRAIN_MOUNTAIN_DETAIL; -LL_COMMON_API extern const LLUUID TERRAIN_ROCK_DETAIL; - -LL_COMMON_API extern const LLUUID DEFAULT_WATER_NORMAL; - -LL_COMMON_API extern const LLUUID IMG_CHECKERBOARD_RGBA; -#endif diff --git a/indra/llcommon/indra_constants.cpp b/indra/llcommon/indra_constants.cpp index d32ae6c041..f3989ee1d0 100755 --- a/indra/llcommon/indra_constants.cpp +++ b/indra/llcommon/indra_constants.cpp @@ -35,6 +35,35 @@ const LLUUID LL_UUID_ALL_AGENTS("44e87126-e794-4ded-05b3-7c42da3d5cdb"); // Governor Linden's agent id. const LLUUID ALEXANDRIA_LINDEN_ID("ba2a564a-f0f1-4b82-9c61-b7520bfcd09f"); const LLUUID GOVERNOR_LINDEN_ID("3d6181b0-6a4b-97ef-18d8-722652995cf1"); -const LLUUID REALESTATE_LINDEN_ID("3d6181b0-6a4b-97ef-18d8-722652995cf1"); // Maintenance's group id. const LLUUID MAINTENANCE_GROUP_ID("dc7b21cd-3c89-fcaa-31c8-25f9ffd224cd"); +// Grass Images +const LLUUID IMG_SMOKE ("b4ba225c-373f-446d-9f7e-6cb7b5cf9b3d"); // VIEWER + +const LLUUID IMG_DEFAULT ("d2114404-dd59-4a4d-8e6c-49359e91bbf0"); // VIEWER + +const LLUUID IMG_SUN ("cce0f112-878f-4586-a2e2-a8f104bba271"); // dataserver +const LLUUID IMG_MOON ("d07f6eed-b96a-47cd-b51d-400ad4a1c428"); // dataserver +const LLUUID IMG_SHOT ("35f217a3-f618-49cf-bbca-c86d486551a9"); // dataserver +const LLUUID IMG_SPARK ("d2e75ac1-d0fb-4532-820e-a20034ac814d"); // dataserver +const LLUUID IMG_FIRE ("aca40aa8-44cf-44ca-a0fa-93e1a2986f82"); // dataserver +const LLUUID IMG_FACE_SELECT ("a85ac674-cb75-4af6-9499-df7c5aaf7a28"); // face selector +const LLUUID IMG_DEFAULT_AVATAR ("c228d1cf-4b5d-4ba8-84f4-899a0796aa97"); // dataserver +const LLUUID IMG_INVISIBLE ("3a367d1c-bef1-6d43-7595-e88c1e3aadb3"); // dataserver + +const LLUUID IMG_EXPLOSION ("68edcf47-ccd7-45b8-9f90-1649d7f12806"); // On dataserver +const LLUUID IMG_EXPLOSION_2 ("21ce046c-83fe-430a-b629-c7660ac78d7c"); // On dataserver +const LLUUID IMG_EXPLOSION_3 ("fedea30a-1be8-47a6-bc06-337a04a39c4b"); // On dataserver +const LLUUID IMG_EXPLOSION_4 ("abf0d56b-82e5-47a2-a8ad-74741bb2c29e"); // On dataserver +const LLUUID IMG_SMOKE_POOF ("1e63e323-5fe0-452e-92f8-b98bd0f764e3"); // On dataserver + +const LLUUID IMG_BIG_EXPLOSION_1 ("5e47a0dc-97bf-44e0-8b40-de06718cee9d"); // On dataserver +const LLUUID IMG_BIG_EXPLOSION_2 ("9c8eca51-53d5-42a7-bb58-cef070395db8"); // On dataserver + +const LLUUID IMG_BLOOM1 ("3c59f7fe-9dc8-47f9-8aaf-a9dd1fbc3bef"); // VIEWER +const LLUUID TERRAIN_DIRT_DETAIL ("0bc58228-74a0-7e83-89bc-5c23464bcec5"); // VIEWER +const LLUUID TERRAIN_GRASS_DETAIL ("63338ede-0037-c4fd-855b-015d77112fc8"); // VIEWER +const LLUUID TERRAIN_MOUNTAIN_DETAIL ("303cd381-8560-7579-23f1-f0a880799740"); // VIEWER +const LLUUID TERRAIN_ROCK_DETAIL ("53a2f406-4895-1d13-d541-d2e3b86bc19c"); // VIEWER + +const LLUUID DEFAULT_WATER_NORMAL ("822ded49-9a6c-f61c-cb89-6df54f42cdf4"); // VIEWER diff --git a/indra/llcommon/indra_constants.h b/indra/llcommon/indra_constants.h index 0da83720bd..02f063f5e8 100755 --- a/indra/llcommon/indra_constants.h +++ b/indra/llcommon/indra_constants.h @@ -31,122 +31,28 @@ class LLUUID; -// At 45 Hz collisions seem stable and objects seem -// to settle down at a reasonable rate. -// JC 3/18/2003 - -// const F32 PHYSICS_TIMESTEP = 1.f / 45.f; -// This must be a #define due to anal retentive restrictions on const expressions -// CG 2008-06-05 -#define PHYSICS_TIMESTEP (1.f / 45.f) - -const F32 COLLISION_TOLERANCE = 0.1f; -const F32 HALF_COLLISION_TOLERANCE = 0.05f; - -// Time constants -const U32 HOURS_PER_LINDEN_DAY = 4; -const U32 DAYS_PER_LINDEN_YEAR = 11; - -const U32 SEC_PER_LINDEN_DAY = HOURS_PER_LINDEN_DAY * 60 * 60; -const U32 SEC_PER_LINDEN_YEAR = DAYS_PER_LINDEN_YEAR * SEC_PER_LINDEN_DAY; - static const F32 REGION_WIDTH_METERS = 256.f; static const S32 REGION_WIDTH_UNITS = 256; static const U32 REGION_WIDTH_U32 = 256; const F32 REGION_HEIGHT_METERS = 4096.f; -// Bits for simulator performance query flags -enum LAND_STAT_FLAGS -{ - STAT_FILTER_BY_PARCEL = 0x00000001, - STAT_FILTER_BY_OWNER = 0x00000002, - STAT_FILTER_BY_OBJECT = 0x00000004, - STAT_FILTER_BY_PARCEL_NAME = 0x00000008, - STAT_REQUEST_LAST_ENTRY = 0x80000000, -}; - -enum LAND_STAT_REPORT_TYPE -{ - STAT_REPORT_TOP_SCRIPTS = 0, - STAT_REPORT_TOP_COLLIDERS -}; - -const U32 STAT_FILTER_MASK = 0x1FFFFFFF; - -// Region absolute limits -static const S32 REGION_AGENT_COUNT_MIN = 1; -static const S32 REGION_AGENT_COUNT_MAX = 200; // Must fit in U8 for the moment (RegionInfo msg) -static const S32 REGION_PRIM_COUNT_MIN = 0; -static const S32 REGION_PRIM_COUNT_MAX = 40000; -static const F32 REGION_PRIM_BONUS_MIN = 1.0; -static const F32 REGION_PRIM_BONUS_MAX = 10.0; - -// Default maximum number of tasks/prims per region. -const U32 DEFAULT_MAX_REGION_WIDE_PRIM_COUNT = 15000; - -const F32 MIN_AGENT_DEPTH = 0.30f; const F32 DEFAULT_AGENT_DEPTH = 0.45f; -const F32 MAX_AGENT_DEPTH = 0.60f; - -const F32 MIN_AGENT_WIDTH = 0.40f; const F32 DEFAULT_AGENT_WIDTH = 0.60f; -const F32 MAX_AGENT_WIDTH = 0.80f; - -const F32 MIN_AGENT_HEIGHT = 1.1f; const F32 DEFAULT_AGENT_HEIGHT = 1.9f; -const F32 MAX_AGENT_HEIGHT = 2.45f; - -// For linked sets -const S32 MAX_CHILDREN_PER_TASK = 255; -const S32 MAX_CHILDREN_PER_PHYSICAL_TASK = 32; - -const S32 MAX_JOINTS_PER_OBJECT = 1; // limiting to 1 until Havok 2.x - -const char* const DEFAULT_DMZ_SPACE_SERVER = "192.168.0.140"; -const char* const DEFAULT_DMZ_USER_SERVER = "192.168.0.140"; -const char* const DEFAULT_DMZ_DATA_SERVER = "192.168.0.140"; -const char* const DEFAULT_DMZ_ASSET_SERVER = "http://asset.dmz.lindenlab.com:80"; - -const char* const DEFAULT_AGNI_SPACE_SERVER = "63.211.139.100"; -const char* const DEFAULT_AGNI_USER_SERVER = "63.211.139.100"; -const char* const DEFAULT_AGNI_DATA_SERVER = "63.211.139.100"; -const char* const DEFAULT_AGNI_ASSET_SERVER = "http://asset.agni.lindenlab.com:80"; - -// Information about what ports are for what services is in the wiki Name Space Ports page -// https://wiki.lindenlab.com/wiki/Name_Space_Ports -const char* const DEFAULT_LOCAL_ASSET_SERVER = "http://localhost:12041/asset/tmp"; -const char* const LOCAL_ASSET_URL_FORMAT = "http://%s:12041/asset"; - -const U32 DEFAULT_LAUNCHER_PORT = 12029; -//const U32 DEFAULT_BIGBOARD_PORT = 12030; // Deprecated -//const U32 DEFAULT_QUERYSIM_PORT = 12031; // Deprecated -const U32 DEFAULT_DATA_SERVER_PORT = 12032; -const U32 DEFAULT_SPACE_SERVER_PORT = 12033; -const U32 DEFAULT_VIEWER_PORT = 12034; -const U32 DEFAULT_SIMULATOR_PORT = 12035; -const U32 DEFAULT_USER_SERVER_PORT = 12036; -const U32 DEFAULT_RPC_SERVER_PORT = 12037; -const U32 DEFAULT_LOG_DATA_SERVER_PORT = 12039; -const U32 DEFAULT_BACKBONE_PORT = 12040; -const U32 DEFAULT_LOCAL_ASSET_PORT = 12041; -//const U32 DEFAULT_BACKBONE_CAP_PORT = 12042; // Deprecated -const U32 DEFAULT_CAP_PROXY_PORT = 12043; -const U32 DEFAULT_INV_DATA_SERVER_PORT = 12044; -const U32 DEFAULT_CGI_SERVICES_PORT = 12045; - -// Mapserver uses ports 12124 - 12139 to allow multiple mapservers to run -// on a single host for map tile generation. JC -const U32 DEFAULT_MAPSERVER_PORT = 12124; - -// For automatic port discovery when running multiple viewers on one host -const U32 PORT_DISCOVERY_RANGE_MIN = 13000; -const U32 PORT_DISCOVERY_RANGE_MAX = PORT_DISCOVERY_RANGE_MIN + 50; - -const char LAND_LAYER_CODE = 'L'; -const char WATER_LAYER_CODE = 'W'; -const char WIND_LAYER_CODE = '7'; -const char CLOUD_LAYER_CODE = '8'; + +enum ETerrainBrushType +{ + // the valid brush numbers cannot be reordered, because they + // are used in the binary LSL format as arguments to llModifyLand() + E_LANDBRUSH_LEVEL = 0, + E_LANDBRUSH_RAISE = 1, + E_LANDBRUSH_LOWER = 2, + E_LANDBRUSH_SMOOTH = 3, + E_LANDBRUSH_NOISE = 4, + E_LANDBRUSH_REVERT = 5, + E_LANDBRUSH_INVALID = 6 +}; // keys // Bit masks for various keyboard modifier keys. @@ -265,89 +171,43 @@ LL_COMMON_API extern const LLUUID LL_UUID_ALL_AGENTS; LL_COMMON_API extern const LLUUID ALEXANDRIA_LINDEN_ID; LL_COMMON_API extern const LLUUID GOVERNOR_LINDEN_ID; -LL_COMMON_API extern const LLUUID REALESTATE_LINDEN_ID; // Maintenance's group id. LL_COMMON_API extern const LLUUID MAINTENANCE_GROUP_ID; -// Flags for kick message -const U32 KICK_FLAGS_DEFAULT = 0x0; -const U32 KICK_FLAGS_FREEZE = 1 << 0; -const U32 KICK_FLAGS_UNFREEZE = 1 << 1; - -const U8 UPD_NONE = 0x00; -const U8 UPD_POSITION = 0x01; -const U8 UPD_ROTATION = 0x02; -const U8 UPD_SCALE = 0x04; -const U8 UPD_LINKED_SETS = 0x08; -const U8 UPD_UNIFORM = 0x10; // used with UPD_SCALE - -// Agent Update Flags (U8) -const U8 AU_FLAGS_NONE = 0x00; -const U8 AU_FLAGS_HIDETITLE = 0x01; -const U8 AU_FLAGS_CLIENT_AUTOPILOT = 0x02; - -// start location constants -const U32 START_LOCATION_ID_LAST = 0; -const U32 START_LOCATION_ID_HOME = 1; -const U32 START_LOCATION_ID_DIRECT = 2; // for direct teleport -const U32 START_LOCATION_ID_PARCEL = 3; // for teleports to a parcel -const U32 START_LOCATION_ID_TELEHUB = 4; // for teleports to a spawnpoint -const U32 START_LOCATION_ID_URL = 5; -const U32 START_LOCATION_ID_COUNT = 6; - -// group constants -const U32 GROUP_MIN_SIZE = 2; - -// gMaxAgentGroups is now sent by login.cgi, which -// looks it up from globals.xml. -// -// For now we need an old default value however, -// so the viewer can be deployed ahead of login.cgi. -// -const S32 DEFAULT_MAX_AGENT_GROUPS = 25; +// image ids +LL_COMMON_API extern const LLUUID IMG_SMOKE; -// radius within which a chat message is fully audible -const F32 CHAT_WHISPER_RADIUS = 10.f; -const F32 CHAT_NORMAL_RADIUS = 20.f; -const F32 CHAT_SHOUT_RADIUS = 100.f; -const F32 CHAT_MAX_RADIUS = CHAT_SHOUT_RADIUS; -const F32 CHAT_MAX_RADIUS_BY_TWO = CHAT_MAX_RADIUS / 2.f; +LL_COMMON_API extern const LLUUID IMG_DEFAULT; -// squared editions of the above for distance checks -const F32 CHAT_WHISPER_RADIUS_SQUARED = CHAT_WHISPER_RADIUS * CHAT_WHISPER_RADIUS; -const F32 CHAT_NORMAL_RADIUS_SQUARED = CHAT_NORMAL_RADIUS * CHAT_NORMAL_RADIUS; -const F32 CHAT_SHOUT_RADIUS_SQUARED = CHAT_SHOUT_RADIUS * CHAT_SHOUT_RADIUS; -const F32 CHAT_MAX_RADIUS_SQUARED = CHAT_SHOUT_RADIUS_SQUARED; -const F32 CHAT_MAX_RADIUS_BY_TWO_SQUARED = CHAT_MAX_RADIUS_BY_TWO * CHAT_MAX_RADIUS_BY_TWO; +LL_COMMON_API extern const LLUUID IMG_SUN; +LL_COMMON_API extern const LLUUID IMG_MOON; +LL_COMMON_API extern const LLUUID IMG_SHOT; +LL_COMMON_API extern const LLUUID IMG_SPARK; +LL_COMMON_API extern const LLUUID IMG_FIRE; +LL_COMMON_API extern const LLUUID IMG_FACE_SELECT; +LL_COMMON_API extern const LLUUID IMG_DEFAULT_AVATAR; +LL_COMMON_API extern const LLUUID IMG_INVISIBLE; +LL_COMMON_API extern const LLUUID IMG_EXPLOSION; +LL_COMMON_API extern const LLUUID IMG_EXPLOSION_2; +LL_COMMON_API extern const LLUUID IMG_EXPLOSION_3; +LL_COMMON_API extern const LLUUID IMG_EXPLOSION_4; +LL_COMMON_API extern const LLUUID IMG_SMOKE_POOF; -// this times above gives barely audible radius -const F32 CHAT_BARELY_AUDIBLE_FACTOR = 2.0f; +LL_COMMON_API extern const LLUUID IMG_BIG_EXPLOSION_1; +LL_COMMON_API extern const LLUUID IMG_BIG_EXPLOSION_2; -// distance in front of speaking agent the sphere is centered -const F32 CHAT_WHISPER_OFFSET = 5.f; -const F32 CHAT_NORMAL_OFFSET = 10.f; -const F32 CHAT_SHOUT_OFFSET = 50.f; +LL_COMMON_API extern const LLUUID IMG_BLOOM1; +LL_COMMON_API extern const LLUUID TERRAIN_DIRT_DETAIL; +LL_COMMON_API extern const LLUUID TERRAIN_GRASS_DETAIL; +LL_COMMON_API extern const LLUUID TERRAIN_MOUNTAIN_DETAIL; +LL_COMMON_API extern const LLUUID TERRAIN_ROCK_DETAIL; -// first clean starts at 3 AM -const S32 SANDBOX_FIRST_CLEAN_HOUR = 3; -// clean every <n> hours -const S32 SANDBOX_CLEAN_FREQ = 12; +LL_COMMON_API extern const LLUUID DEFAULT_WATER_NORMAL; -const F32 WIND_SCALE_HACK = 2.0f; // hack to make wind speeds more realistic -enum ETerrainBrushType -{ - // the valid brush numbers cannot be reordered, because they - // are used in the binary LSL format as arguments to llModifyLand() - E_LANDBRUSH_LEVEL = 0, - E_LANDBRUSH_RAISE = 1, - E_LANDBRUSH_LOWER = 2, - E_LANDBRUSH_SMOOTH = 3, - E_LANDBRUSH_NOISE = 4, - E_LANDBRUSH_REVERT = 5, - E_LANDBRUSH_INVALID = 6 -}; +// radius within which a chat message is fully audible +const F32 CHAT_NORMAL_RADIUS = 20.f; // media commands const U32 PARCEL_MEDIA_COMMAND_STOP = 0; @@ -365,51 +225,101 @@ const U32 PARCEL_MEDIA_COMMAND_SIZE = 11; const U32 PARCEL_MEDIA_COMMAND_DESC = 12; const U32 PARCEL_MEDIA_COMMAND_LOOP_SET = 13; -// map item types -const U32 MAP_ITEM_TELEHUB = 0x01; -const U32 MAP_ITEM_PG_EVENT = 0x02; -const U32 MAP_ITEM_MATURE_EVENT = 0x03; -//const U32 MAP_ITEM_POPULAR = 0x04; // No longer supported, 2009-03-02 KLW -//const U32 MAP_ITEM_AGENT_COUNT = 0x05; -const U32 MAP_ITEM_AGENT_LOCATIONS = 0x06; -const U32 MAP_ITEM_LAND_FOR_SALE = 0x07; -const U32 MAP_ITEM_CLASSIFIED = 0x08; -const U32 MAP_ITEM_ADULT_EVENT = 0x09; -const U32 MAP_ITEM_LAND_FOR_SALE_ADULT = 0x0a; - -// Region map layer numbers -const S32 MAP_SIM_OBJECTS = 0; -const S32 MAP_SIM_TERRAIN = 1; -const S32 MAP_SIM_LAND_FOR_SALE = 2; // Transparent alpha overlay of land for sale -const S32 MAP_SIM_IMAGE_TYPES = 3; // Number of map layers -const S32 MAP_SIM_INFO_MASK = 0x00FFFFFF; // Agent access may be stuffed into upper byte -const S32 MAP_SIM_LAYER_MASK = 0x0000FFFF; // Layer info is in lower 16 bits -const S32 MAP_SIM_RETURN_NULL_SIMS = 0x00010000; -const S32 MAP_SIM_PRELUDE = 0x00020000; - -// Crash reporter behavior -const S32 CRASH_BEHAVIOR_ASK = 0; -const S32 CRASH_BEHAVIOR_ALWAYS_SEND = 1; -const S32 CRASH_BEHAVIOR_NEVER_SEND = 2; - -// Export/Import return values -const S32 EXPORT_SUCCESS = 0; -const S32 EXPORT_ERROR_PERMISSIONS = -1; -const S32 EXPORT_ERROR_UNKNOWN = -2; - -// This is how long the sim will try to teleport you before giving up. -const F32 TELEPORT_EXPIRY = 15.0f; -// Additional time (in seconds) to wait per attachment -const F32 TELEPORT_EXPIRY_PER_ATTACHMENT = 3.f; - -// The maximum size of an object extra parameters binary (packed) block -#define MAX_OBJECT_PARAMS_SIZE 1024 - const S32 CHAT_CHANNEL_DEBUG = S32_MAX; -// PLEASE don't add constants here. Every dev will have to do -// a complete rebuild. Try to find another shared header file, -// like llregionflags.h, lllslconstants.h, llagentconstants.h, -// or create a new one. JC +// agent constants +const U32 CONTROL_AT_POS_INDEX = 0; +const U32 CONTROL_AT_NEG_INDEX = 1; +const U32 CONTROL_LEFT_POS_INDEX = 2; +const U32 CONTROL_LEFT_NEG_INDEX = 3; +const U32 CONTROL_UP_POS_INDEX = 4; +const U32 CONTROL_UP_NEG_INDEX = 5; +const U32 CONTROL_PITCH_POS_INDEX = 6; +const U32 CONTROL_PITCH_NEG_INDEX = 7; +const U32 CONTROL_YAW_POS_INDEX = 8; +const U32 CONTROL_YAW_NEG_INDEX = 9; +const U32 CONTROL_FAST_AT_INDEX = 10; +const U32 CONTROL_FAST_LEFT_INDEX = 11; +const U32 CONTROL_FAST_UP_INDEX = 12; +const U32 CONTROL_FLY_INDEX = 13; +const U32 CONTROL_STOP_INDEX = 14; +const U32 CONTROL_FINISH_ANIM_INDEX = 15; +const U32 CONTROL_STAND_UP_INDEX = 16; +const U32 CONTROL_SIT_ON_GROUND_INDEX = 17; +const U32 CONTROL_MOUSELOOK_INDEX = 18; +const U32 CONTROL_NUDGE_AT_POS_INDEX = 19; +const U32 CONTROL_NUDGE_AT_NEG_INDEX = 20; +const U32 CONTROL_NUDGE_LEFT_POS_INDEX = 21; +const U32 CONTROL_NUDGE_LEFT_NEG_INDEX = 22; +const U32 CONTROL_NUDGE_UP_POS_INDEX = 23; +const U32 CONTROL_NUDGE_UP_NEG_INDEX = 24; +const U32 CONTROL_TURN_LEFT_INDEX = 25; +const U32 CONTROL_TURN_RIGHT_INDEX = 26; +const U32 CONTROL_AWAY_INDEX = 27; +const U32 CONTROL_LBUTTON_DOWN_INDEX = 28; +const U32 CONTROL_LBUTTON_UP_INDEX = 29; +const U32 CONTROL_ML_LBUTTON_DOWN_INDEX = 30; +const U32 CONTROL_ML_LBUTTON_UP_INDEX = 31; +const U32 TOTAL_CONTROLS = 32; + +const U32 AGENT_CONTROL_AT_POS = 0x1 << CONTROL_AT_POS_INDEX; // 0x00000001 +const U32 AGENT_CONTROL_AT_NEG = 0x1 << CONTROL_AT_NEG_INDEX; // 0x00000002 +const U32 AGENT_CONTROL_LEFT_POS = 0x1 << CONTROL_LEFT_POS_INDEX; // 0x00000004 +const U32 AGENT_CONTROL_LEFT_NEG = 0x1 << CONTROL_LEFT_NEG_INDEX; // 0x00000008 +const U32 AGENT_CONTROL_UP_POS = 0x1 << CONTROL_UP_POS_INDEX; // 0x00000010 +const U32 AGENT_CONTROL_UP_NEG = 0x1 << CONTROL_UP_NEG_INDEX; // 0x00000020 +const U32 AGENT_CONTROL_PITCH_POS = 0x1 << CONTROL_PITCH_POS_INDEX; // 0x00000040 +const U32 AGENT_CONTROL_PITCH_NEG = 0x1 << CONTROL_PITCH_NEG_INDEX; // 0x00000080 +const U32 AGENT_CONTROL_YAW_POS = 0x1 << CONTROL_YAW_POS_INDEX; // 0x00000100 +const U32 AGENT_CONTROL_YAW_NEG = 0x1 << CONTROL_YAW_NEG_INDEX; // 0x00000200 + +const U32 AGENT_CONTROL_FAST_AT = 0x1 << CONTROL_FAST_AT_INDEX; // 0x00000400 +const U32 AGENT_CONTROL_FAST_LEFT = 0x1 << CONTROL_FAST_LEFT_INDEX; // 0x00000800 +const U32 AGENT_CONTROL_FAST_UP = 0x1 << CONTROL_FAST_UP_INDEX; // 0x00001000 + +const U32 AGENT_CONTROL_FLY = 0x1 << CONTROL_FLY_INDEX; // 0x00002000 +const U32 AGENT_CONTROL_STOP = 0x1 << CONTROL_STOP_INDEX; // 0x00004000 +const U32 AGENT_CONTROL_FINISH_ANIM = 0x1 << CONTROL_FINISH_ANIM_INDEX; // 0x00008000 +const U32 AGENT_CONTROL_STAND_UP = 0x1 << CONTROL_STAND_UP_INDEX; // 0x00010000 +const U32 AGENT_CONTROL_SIT_ON_GROUND = 0x1 << CONTROL_SIT_ON_GROUND_INDEX; // 0x00020000 +const U32 AGENT_CONTROL_MOUSELOOK = 0x1 << CONTROL_MOUSELOOK_INDEX; // 0x00040000 + +const U32 AGENT_CONTROL_NUDGE_AT_POS = 0x1 << CONTROL_NUDGE_AT_POS_INDEX; // 0x00080000 +const U32 AGENT_CONTROL_NUDGE_AT_NEG = 0x1 << CONTROL_NUDGE_AT_NEG_INDEX; // 0x00100000 +const U32 AGENT_CONTROL_NUDGE_LEFT_POS = 0x1 << CONTROL_NUDGE_LEFT_POS_INDEX; // 0x00200000 +const U32 AGENT_CONTROL_NUDGE_LEFT_NEG = 0x1 << CONTROL_NUDGE_LEFT_NEG_INDEX; // 0x00400000 +const U32 AGENT_CONTROL_NUDGE_UP_POS = 0x1 << CONTROL_NUDGE_UP_POS_INDEX; // 0x00800000 +const U32 AGENT_CONTROL_NUDGE_UP_NEG = 0x1 << CONTROL_NUDGE_UP_NEG_INDEX; // 0x01000000 +const U32 AGENT_CONTROL_TURN_LEFT = 0x1 << CONTROL_TURN_LEFT_INDEX; // 0x02000000 +const U32 AGENT_CONTROL_TURN_RIGHT = 0x1 << CONTROL_TURN_RIGHT_INDEX; // 0x04000000 + +const U32 AGENT_CONTROL_AWAY = 0x1 << CONTROL_AWAY_INDEX; // 0x08000000 + +const U32 AGENT_CONTROL_LBUTTON_DOWN = 0x1 << CONTROL_LBUTTON_DOWN_INDEX; // 0x10000000 +const U32 AGENT_CONTROL_LBUTTON_UP = 0x1 << CONTROL_LBUTTON_UP_INDEX; // 0x20000000 +const U32 AGENT_CONTROL_ML_LBUTTON_DOWN = 0x1 << CONTROL_ML_LBUTTON_DOWN_INDEX; // 0x40000000 +const U32 AGENT_CONTROL_ML_LBUTTON_UP = ((U32)0x1) << CONTROL_ML_LBUTTON_UP_INDEX; // 0x80000000 + +// move these up so that we can hide them in "State" for object updates +// (for now) +const U32 AGENT_ATTACH_OFFSET = 4; +const U32 AGENT_ATTACH_MASK = 0xf << AGENT_ATTACH_OFFSET; + +// RN: this method swaps the upper and lower nibbles to maintain backward +// compatibility with old objects that only used the upper nibble +#define ATTACHMENT_ID_FROM_STATE(state) ((S32)((((U8)state & AGENT_ATTACH_MASK) >> 4) | (((U8)state & ~AGENT_ATTACH_MASK) << 4))) + +// DO NOT CHANGE THE SEQUENCE OF THIS LIST!! +const U8 CLICK_ACTION_NONE = 0; +const U8 CLICK_ACTION_TOUCH = 0; +const U8 CLICK_ACTION_SIT = 1; +const U8 CLICK_ACTION_BUY = 2; +const U8 CLICK_ACTION_PAY = 3; +const U8 CLICK_ACTION_OPEN = 4; +const U8 CLICK_ACTION_PLAY = 5; +const U8 CLICK_ACTION_OPEN_MEDIA = 6; +const U8 CLICK_ACTION_ZOOM = 7; +// DO NOT CHANGE THE SEQUENCE OF THIS LIST!! + #endif diff --git a/indra/llcommon/linked_lists.h b/indra/llcommon/linked_lists.h deleted file mode 100755 index 6b25295b7b..0000000000 --- a/indra/llcommon/linked_lists.h +++ /dev/null @@ -1,937 +0,0 @@ -/** - * @file linked_lists.h - * @brief LLLinkedList class header amd implementation file. - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_LINKED_LISTS_H -#define LL_LINKED_LISTS_H - -/** - * Provides a standard doubly linked list for fun and profit - * Utilizes a neat trick off of Flipcode where the back pointer is a - * pointer to a pointer, allowing easier transfer of nodes between lists, &c - * And a template class, of course - */ - -#include "llerror.h" - - -template <class DATA_TYPE> class LLLinkedList -{ -public: - friend class LLLinkNode; - // External interface - - // basic constructor - LLLinkedList() : mHead(NULL), mCurrentp(NULL), mInsertBefore(NULL) - { - mCurrentp = mHead.mNextp; - mCurrentOperatingp = mHead.mNextp; - mCount = 0; - } - - // basic constructor - LLLinkedList(BOOL (*insert_before)(DATA_TYPE *data_new, DATA_TYPE *data_tested)) : mHead(NULL), mCurrentp(NULL), mInsertBefore(insert_before) - { - mCurrentp = mHead.mNextp; - mCurrentOperatingp = mHead.mNextp; - mCount = 0; - } - - // destructor destroys list and nodes, but not data in nodes - ~LLLinkedList() - { - removeAllNodes(); - } - - // set mInsertBefore - void setInsertBefore(BOOL (*insert_before)(DATA_TYPE *data_new, DATA_TYPE *data_tested)) - { - mInsertBefore = insert_before; - } - - // - // WARNING!!!!!!! - // addData and addDataSorted are NOT O(1) operations, but O(n) because they check - // for existence of the data in the linked list first. Why, I don't know - djs - // If you don't care about dupes, use addDataNoCheck - // - - // put data into a node and stick it at the front of the list - inline BOOL addData(DATA_TYPE *data); - - // put data into a node and sort into list by mInsertBefore() - // calls normal add if mInsertBefore isn't set - inline BOOL addDataSorted(DATA_TYPE *data); - - inline BOOL addDataNoCheck(DATA_TYPE *data); - - // bubbleSortList - // does an improved bubble sort of the list . . . works best with almost sorted data - // does nothing if mInsertBefore isn't set - // Nota Bene: Swaps are accomplished by swapping data pointers - inline void bubbleSortList(); - - // put data into a node and stick it at the end of the list - inline BOOL addDataAtEnd(DATA_TYPE *data); - - // returns number of items in the list - inline S32 getLength() const; - - inline BOOL isEmpty(); - - // search the list starting at mHead.mNextp and remove the link with mDatap == data - // leave mCurrentp and mCurrentOperatingp on the next entry - // return TRUE if found, FALSE if not found - inline BOOL removeData(DATA_TYPE *data); - - // search the list starting at mHead.mNextp and delete the link with mDatap == data - // leave mCurrentp and mCurrentOperatingp on the next entry - // return TRUE if found, FALSE if not found - inline BOOL deleteData(DATA_TYPE *data); - - // remove all nodes from the list and delete the associated data - inline void deleteAllData(); - - // remove all nodes from the list but do not delete data - inline void removeAllNodes(); - - // check to see if data is in list - // if TRUE then mCurrentp and mCurrentOperatingp point to data - inline BOOL checkData(DATA_TYPE *data); - - // place mCurrentp on first node - inline void resetList(); - - // return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp - inline DATA_TYPE *getCurrentData(); - - // same as getCurrentData() but a more intuitive name for the operation - inline DATA_TYPE *getNextData(); - - // reset the list and return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp - inline DATA_TYPE *getFirstData(); - - // reset the list and return the data at position n, set mCurentOperatingp to that node and bump mCurrentp - // Note: n is zero-based - inline DATA_TYPE *getNthData( U32 n); - - // reset the list and return the last data in it, set mCurentOperatingp to that node and bump mCurrentp - inline DATA_TYPE *getLastData(); - - // remove the Node at mCurentOperatingp - // leave mCurrentp and mCurentOperatingp on the next entry - inline void removeCurrentData(); - - // remove the Node at mCurentOperatingp and add it to newlist - // leave mCurrentp and mCurentOperatingp on the next entry - void moveCurrentData(LLLinkedList *newlist, BOOL b_sort); - - BOOL moveData(DATA_TYPE *data, LLLinkedList *newlist, BOOL b_sort); - - // delete the Node at mCurentOperatingp - // leave mCurrentp anf mCurentOperatingp on the next entry - void deleteCurrentData(); - -private: - // node that actually contains the data - class LLLinkNode - { - public: - // assign the mDatap pointer - LLLinkNode(DATA_TYPE *data) : mDatap(data), mNextp(NULL), mPrevpp(NULL) - { - } - - // destructor does not, by default, destroy associated data - // however, the mDatap must be NULL to ensure that we aren't causing memory leaks - ~LLLinkNode() - { - if (mDatap) - { - llerror("Attempting to call LLLinkNode destructor with a non-null mDatap!", 1); - } - } - - // delete associated data and NULL out pointer - void deleteData() - { - delete mDatap; - mDatap = NULL; - } - - // NULL out pointer - void removeData() - { - mDatap = NULL; - } - - DATA_TYPE *mDatap; - LLLinkNode *mNextp; - LLLinkNode **mPrevpp; - }; - - // add a node at the front of the list - void addData(LLLinkNode *node) - { - // don't allow NULL to be passed to addData - if (!node) - { - llerror("NULL pointer passed to LLLinkedList::addData", 0); - } - - // add the node to the front of the list - node->mPrevpp = &mHead.mNextp; - node->mNextp = mHead.mNextp; - - // if there's something in the list, fix its back pointer - if (node->mNextp) - { - node->mNextp->mPrevpp = &node->mNextp; - } - - mHead.mNextp = node; - } - - LLLinkNode mHead; // fake head node. . . makes pointer operations faster and easier - LLLinkNode *mCurrentp; // mCurrentp is the Node that getCurrentData returns - LLLinkNode *mCurrentOperatingp; // this is the node that the various mumbleCurrentData functions act on - BOOL (*mInsertBefore)(DATA_TYPE *data_new, DATA_TYPE *data_tested); // user function set to allow sorted lists - U32 mCount; -}; - -template <class DATA_TYPE> -BOOL LLLinkedList<DATA_TYPE>::addData(DATA_TYPE *data) -{ - // don't allow NULL to be passed to addData - if (!data) - { - llerror("NULL pointer passed to LLLinkedList::addData", 0); - } - - LLLinkNode *tcurr = mCurrentp; - LLLinkNode *tcurrop = mCurrentOperatingp; - - if ( checkData(data)) - { - mCurrentp = tcurr; - mCurrentOperatingp = tcurrop; - return FALSE; - } - - // make the new node - LLLinkNode *temp = new LLLinkNode(data); - - // add the node to the front of the list - temp->mPrevpp = &mHead.mNextp; - temp->mNextp = mHead.mNextp; - - // if there's something in the list, fix its back pointer - if (temp->mNextp) - { - temp->mNextp->mPrevpp = &temp->mNextp; - } - - mHead.mNextp = temp; - mCurrentp = tcurr; - mCurrentOperatingp = tcurrop; - mCount++; - return TRUE; -} - - -template <class DATA_TYPE> -BOOL LLLinkedList<DATA_TYPE>::addDataNoCheck(DATA_TYPE *data) -{ - // don't allow NULL to be passed to addData - if (!data) - { - llerror("NULL pointer passed to LLLinkedList::addData", 0); - } - - LLLinkNode *tcurr = mCurrentp; - LLLinkNode *tcurrop = mCurrentOperatingp; - - // make the new node - LLLinkNode *temp = new LLLinkNode(data); - - // add the node to the front of the list - temp->mPrevpp = &mHead.mNextp; - temp->mNextp = mHead.mNextp; - - // if there's something in the list, fix its back pointer - if (temp->mNextp) - { - temp->mNextp->mPrevpp = &temp->mNextp; - } - - mHead.mNextp = temp; - mCurrentp = tcurr; - mCurrentOperatingp = tcurrop; - mCount++; - return TRUE; -} - - -template <class DATA_TYPE> -BOOL LLLinkedList<DATA_TYPE>::addDataSorted(DATA_TYPE *data) -{ - LLLinkNode *tcurr = mCurrentp; - LLLinkNode *tcurrop = mCurrentOperatingp; - // don't allow NULL to be passed to addData - if (!data) - { - llerror("NULL pointer passed to LLLinkedList::addDataSorted", 0); - } - - if (checkData(data)) - { - // restore - mCurrentp = tcurr; - mCurrentOperatingp = tcurrop; - return FALSE; - } - - // mInsertBefore not set? - if (!mInsertBefore) - { - addData(data); - // restore - mCurrentp = tcurr; - mCurrentOperatingp = tcurrop; - return FALSE; - } - - // empty list? - if (!mHead.mNextp) - { - addData(data); - // restore - mCurrentp = tcurr; - mCurrentOperatingp = tcurrop; - return TRUE; - } - - // make the new node - LLLinkNode *temp = new LLLinkNode(data); - - // walk the list until mInsertBefore returns true - mCurrentp = mHead.mNextp; - while (mCurrentp->mNextp) - { - if (mInsertBefore(data, mCurrentp->mDatap)) - { - // insert before the current one - temp->mPrevpp = mCurrentp->mPrevpp; - temp->mNextp = mCurrentp; - *(temp->mPrevpp) = temp; - mCurrentp->mPrevpp = &temp->mNextp; - // restore - mCurrentp = tcurr; - mCurrentOperatingp = tcurrop; - mCount++; - return TRUE; - } - else - { - mCurrentp = mCurrentp->mNextp; - } - } - - // on the last element, add before? - if (mInsertBefore(data, mCurrentp->mDatap)) - { - // insert before the current one - temp->mPrevpp = mCurrentp->mPrevpp; - temp->mNextp = mCurrentp; - *(temp->mPrevpp) = temp; - mCurrentp->mPrevpp = &temp->mNextp; - // restore - mCurrentp = tcurr; - mCurrentOperatingp = tcurrop; - } - else // insert after - { - temp->mPrevpp = &mCurrentp->mNextp; - temp->mNextp = NULL; - mCurrentp->mNextp = temp; - - // restore - mCurrentp = tcurr; - mCurrentOperatingp = tcurrop; - } - mCount++; - return TRUE; -} - -template <class DATA_TYPE> -void LLLinkedList<DATA_TYPE>::bubbleSortList() -{ - // mInsertBefore not set - if (!mInsertBefore) - { - return; - } - - LLLinkNode *tcurr = mCurrentp; - LLLinkNode *tcurrop = mCurrentOperatingp; - - BOOL b_swapped = FALSE; - DATA_TYPE *temp; - - // Nota Bene: This will break if more than 0x7FFFFFFF members in list! - S32 length = 0x7FFFFFFF; - S32 count = 0; - do - { - b_swapped = FALSE; - mCurrentp = mHead.mNextp; - count = 0; - while ( (count + 1 < length) - &&(mCurrentp)) - { - if (mCurrentp->mNextp) - { - if (!mInsertBefore(mCurrentp->mDatap, mCurrentp->mNextp->mDatap)) - { - // swap data pointers! - temp = mCurrentp->mDatap; - mCurrentp->mDatap = mCurrentp->mNextp->mDatap; - mCurrentp->mNextp->mDatap = temp; - b_swapped = TRUE; - } - } - else - { - break; - } - count++; - mCurrentp = mCurrentp->mNextp; - } - length = count; - } while (b_swapped); - - // restore - mCurrentp = tcurr; - mCurrentOperatingp = tcurrop; -} - - -template <class DATA_TYPE> -BOOL LLLinkedList<DATA_TYPE>::addDataAtEnd(DATA_TYPE *data) -{ - LLLinkNode *tcurr = mCurrentp; - LLLinkNode *tcurrop = mCurrentOperatingp; - - // don't allow NULL to be passed to addData - if (!data) - { - llerror("NULL pointer passed to LLLinkedList::addData", 0); - } - - if (checkData(data)) - { - mCurrentp = tcurr; - mCurrentOperatingp = tcurrop; - return FALSE; - } - - // make the new node - LLLinkNode *temp = new LLLinkNode(data); - - // add the node to the end of the list - - // if empty, add to the front and be done with it - if (!mHead.mNextp) - { - temp->mPrevpp = &mHead.mNextp; - temp->mNextp = NULL; - mHead.mNextp = temp; - } - else - { - // otherwise, walk to the end of the list - mCurrentp = mHead.mNextp; - while (mCurrentp->mNextp) - { - mCurrentp = mCurrentp->mNextp; - } - temp->mPrevpp = &mCurrentp->mNextp; - temp->mNextp = NULL; - mCurrentp->mNextp = temp; - } - - // restore - mCurrentp = tcurr; - mCurrentOperatingp = tcurrop; - mCount++; - return TRUE; -} - - -// returns number of items in the list -template <class DATA_TYPE> -S32 LLLinkedList<DATA_TYPE>::getLength() const -{ -// S32 length = 0; -// for (LLLinkNode* temp = mHead.mNextp; temp != NULL; temp = temp->mNextp) -// { -// length++; -// } - return mCount; -} - - -template <class DATA_TYPE> -BOOL LLLinkedList<DATA_TYPE>::isEmpty() -{ - return (mCount == 0); -} - - -// search the list starting at mHead.mNextp and remove the link with mDatap == data -// leave mCurrentp and mCurrentOperatingp on the next entry -// return TRUE if found, FALSE if not found -template <class DATA_TYPE> -BOOL LLLinkedList<DATA_TYPE>::removeData(DATA_TYPE *data) -{ - BOOL b_found = FALSE; - // don't allow NULL to be passed to addData - if (!data) - { - llerror("NULL pointer passed to LLLinkedList::removeData", 0); - } - - LLLinkNode *tcurr = mCurrentp; - LLLinkNode *tcurrop = mCurrentOperatingp; - - mCurrentp = mHead.mNextp; - mCurrentOperatingp = mHead.mNextp; - - while (mCurrentOperatingp) - { - if (mCurrentOperatingp->mDatap == data) - { - b_found = TRUE; - - // remove the node - - // if there is a next one, fix it - if (mCurrentOperatingp->mNextp) - { - mCurrentOperatingp->mNextp->mPrevpp = mCurrentOperatingp->mPrevpp; - } - *(mCurrentOperatingp->mPrevpp) = mCurrentOperatingp->mNextp; - - // remove the LLLinkNode - - // if we were on the one we want to delete, bump the cached copies - if (mCurrentOperatingp == tcurrop) - { - tcurrop = tcurr = mCurrentOperatingp->mNextp; - } - else if (mCurrentOperatingp == tcurr) - { - tcurrop = tcurr = mCurrentOperatingp->mNextp; - } - - mCurrentp = mCurrentOperatingp->mNextp; - - mCurrentOperatingp->removeData(); - delete mCurrentOperatingp; - mCurrentOperatingp = mCurrentp; - mCount--; - break; - } - mCurrentOperatingp = mCurrentOperatingp->mNextp; - } - // restore - mCurrentp = tcurr; - mCurrentOperatingp = tcurrop; - return b_found; -} - -// search the list starting at mHead.mNextp and delete the link with mDatap == data -// leave mCurrentp and mCurrentOperatingp on the next entry -// return TRUE if found, FALSE if not found -template <class DATA_TYPE> -BOOL LLLinkedList<DATA_TYPE>::deleteData(DATA_TYPE *data) -{ - BOOL b_found = FALSE; - // don't allow NULL to be passed to addData - if (!data) - { - llerror("NULL pointer passed to LLLinkedList::removeData", 0); - } - - LLLinkNode *tcurr = mCurrentp; - LLLinkNode *tcurrop = mCurrentOperatingp; - - mCurrentp = mHead.mNextp; - mCurrentOperatingp = mHead.mNextp; - - while (mCurrentOperatingp) - { - if (mCurrentOperatingp->mDatap == data) - { - b_found = TRUE; - - // remove the node - // if there is a next one, fix it - if (mCurrentOperatingp->mNextp) - { - mCurrentOperatingp->mNextp->mPrevpp = mCurrentOperatingp->mPrevpp; - } - *(mCurrentOperatingp->mPrevpp) = mCurrentOperatingp->mNextp; - - // delete the LLLinkNode - // if we were on the one we want to delete, bump the cached copies - if (mCurrentOperatingp == tcurrop) - { - tcurrop = tcurr = mCurrentOperatingp->mNextp; - } - - // and delete the associated data - llassert(mCurrentOperatingp); - mCurrentp = mCurrentOperatingp->mNextp; - mCurrentOperatingp->deleteData(); - delete mCurrentOperatingp; - mCurrentOperatingp = mCurrentp; - mCount--; - break; - } - mCurrentOperatingp = mCurrentOperatingp->mNextp; - } - // restore - mCurrentp = tcurr; - mCurrentOperatingp = tcurrop; - return b_found; -} - - // remove all nodes from the list and delete the associated data -template <class DATA_TYPE> -void LLLinkedList<DATA_TYPE>::deleteAllData() -{ - LLLinkNode *temp; - // reset mCurrentp - mCurrentp = mHead.mNextp; - - while (mCurrentp) - { - temp = mCurrentp->mNextp; - mCurrentp->deleteData(); - delete mCurrentp; - mCurrentp = temp; - } - - // reset mHead and mCurrentp - mHead.mNextp = NULL; - mCurrentp = mHead.mNextp; - mCurrentOperatingp = mHead.mNextp; - mCount = 0; -} - -// remove all nodes from the list but do not delete data -template <class DATA_TYPE> -void LLLinkedList<DATA_TYPE>::removeAllNodes() -{ - LLLinkNode *temp; - // reset mCurrentp - mCurrentp = mHead.mNextp; - - while (mCurrentp) - { - temp = mCurrentp->mNextp; - mCurrentp->removeData(); - delete mCurrentp; - mCurrentp = temp; - } - - // reset mHead and mCurrentp - mHead.mNextp = NULL; - mCurrentp = mHead.mNextp; - mCurrentOperatingp = mHead.mNextp; - mCount = 0; -} - -// check to see if data is in list -// if TRUE then mCurrentp and mCurrentOperatingp point to data -template <class DATA_TYPE> -BOOL LLLinkedList<DATA_TYPE>::checkData(DATA_TYPE *data) -{ - // reset mCurrentp - mCurrentp = mHead.mNextp; - - while (mCurrentp) - { - if (mCurrentp->mDatap == data) - { - mCurrentOperatingp = mCurrentp; - return TRUE; - } - mCurrentp = mCurrentp->mNextp; - } - mCurrentOperatingp = mCurrentp; - return FALSE; -} - -// place mCurrentp on first node -template <class DATA_TYPE> -void LLLinkedList<DATA_TYPE>::resetList() -{ - mCurrentp = mHead.mNextp; - mCurrentOperatingp = mHead.mNextp; -} - -// return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp -template <class DATA_TYPE> -DATA_TYPE *LLLinkedList<DATA_TYPE>::getCurrentData() -{ - if (mCurrentp) - { - mCurrentOperatingp = mCurrentp; - mCurrentp = mCurrentp->mNextp; - return mCurrentOperatingp->mDatap; - } - else - { - return NULL; - } -} - -// same as getCurrentData() but a more intuitive name for the operation -template <class DATA_TYPE> -DATA_TYPE *LLLinkedList<DATA_TYPE>::getNextData() -{ - if (mCurrentp) - { - mCurrentOperatingp = mCurrentp; - mCurrentp = mCurrentp->mNextp; - return mCurrentOperatingp->mDatap; - } - else - { - return NULL; - } -} - -// reset the list and return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp -template <class DATA_TYPE> -DATA_TYPE *LLLinkedList<DATA_TYPE>::getFirstData() -{ - mCurrentp = mHead.mNextp; - mCurrentOperatingp = mHead.mNextp; - if (mCurrentp) - { - mCurrentOperatingp = mCurrentp; - mCurrentp = mCurrentp->mNextp; - return mCurrentOperatingp->mDatap; - } - else - { - return NULL; - } -} - -// Note: n is zero-based -template <class DATA_TYPE> -DATA_TYPE *LLLinkedList<DATA_TYPE>::getNthData( U32 n ) -{ - mCurrentOperatingp = mHead.mNextp; - - // if empty, return NULL - if (!mCurrentOperatingp) - { - return NULL; - } - - for( U32 i = 0; i < n; i++ ) - { - mCurrentOperatingp = mCurrentOperatingp->mNextp; - if( !mCurrentOperatingp ) - { - return NULL; - } - } - - mCurrentp = mCurrentOperatingp->mNextp; - return mCurrentOperatingp->mDatap; -} - - -// reset the list and return the last data in it, set mCurentOperatingp to that node and bump mCurrentp -template <class DATA_TYPE> -DATA_TYPE *LLLinkedList<DATA_TYPE>::getLastData() -{ - mCurrentOperatingp = mHead.mNextp; - - // if empty, return NULL - if (!mCurrentOperatingp) - return NULL; - - // walk until we're pointing at the last entry - while (mCurrentOperatingp->mNextp) - { - mCurrentOperatingp = mCurrentOperatingp->mNextp; - } - mCurrentp = mCurrentOperatingp->mNextp; - return mCurrentOperatingp->mDatap; -} - -// remove the Node at mCurentOperatingp -// leave mCurrentp and mCurentOperatingp on the next entry -// return TRUE if found, FALSE if not found -template <class DATA_TYPE> -void LLLinkedList<DATA_TYPE>::removeCurrentData() -{ - if (mCurrentOperatingp) - { - // remove the node - // if there is a next one, fix it - if (mCurrentOperatingp->mNextp) - { - mCurrentOperatingp->mNextp->mPrevpp = mCurrentOperatingp->mPrevpp; - } - *(mCurrentOperatingp->mPrevpp) = mCurrentOperatingp->mNextp; - - // remove the LLLinkNode - mCurrentp = mCurrentOperatingp->mNextp; - - mCurrentOperatingp->removeData(); - delete mCurrentOperatingp; - mCount--; - mCurrentOperatingp = mCurrentp; - } -} - -// remove the Node at mCurentOperatingp and add it to newlist -// leave mCurrentp and mCurentOperatingp on the next entry -// return TRUE if found, FALSE if not found -template <class DATA_TYPE> -void LLLinkedList<DATA_TYPE>::moveCurrentData(LLLinkedList *newlist, BOOL b_sort) -{ - if (mCurrentOperatingp) - { - // remove the node - // if there is a next one, fix it - if (mCurrentOperatingp->mNextp) - { - mCurrentOperatingp->mNextp->mPrevpp = mCurrentOperatingp->mPrevpp; - } - *(mCurrentOperatingp->mPrevpp) = mCurrentOperatingp->mNextp; - - // remove the LLLinkNode - mCurrentp = mCurrentOperatingp->mNextp; - // move the node to the new list - newlist->addData(mCurrentOperatingp); - if (b_sort) - bubbleSortList(); - mCurrentOperatingp = mCurrentp; - } -} - -template <class DATA_TYPE> -BOOL LLLinkedList<DATA_TYPE>::moveData(DATA_TYPE *data, LLLinkedList *newlist, BOOL b_sort) -{ - BOOL b_found = FALSE; - // don't allow NULL to be passed to addData - if (!data) - { - llerror("NULL pointer passed to LLLinkedList::removeData", 0); - } - - LLLinkNode *tcurr = mCurrentp; - LLLinkNode *tcurrop = mCurrentOperatingp; - - mCurrentp = mHead.mNextp; - mCurrentOperatingp = mHead.mNextp; - - while (mCurrentOperatingp) - { - if (mCurrentOperatingp->mDatap == data) - { - b_found = TRUE; - - // remove the node - - // if there is a next one, fix it - if (mCurrentOperatingp->mNextp) - { - mCurrentOperatingp->mNextp->mPrevpp = mCurrentOperatingp->mPrevpp; - } - *(mCurrentOperatingp->mPrevpp) = mCurrentOperatingp->mNextp; - - // if we were on the one we want to delete, bump the cached copies - if ( (mCurrentOperatingp == tcurrop) - ||(mCurrentOperatingp == tcurr)) - { - tcurrop = tcurr = mCurrentOperatingp->mNextp; - } - - // remove the LLLinkNode - mCurrentp = mCurrentOperatingp->mNextp; - // move the node to the new list - newlist->addData(mCurrentOperatingp); - if (b_sort) - newlist->bubbleSortList(); - mCurrentOperatingp = mCurrentp; - break; - } - mCurrentOperatingp = mCurrentOperatingp->mNextp; - } - // restore - mCurrentp = tcurr; - mCurrentOperatingp = tcurrop; - return b_found; -} - -// delete the Node at mCurentOperatingp -// leave mCurrentp anf mCurentOperatingp on the next entry -// return TRUE if found, FALSE if not found -template <class DATA_TYPE> -void LLLinkedList<DATA_TYPE>::deleteCurrentData() -{ - if (mCurrentOperatingp) - { - // remove the node - // if there is a next one, fix it - if (mCurrentOperatingp->mNextp) - { - mCurrentOperatingp->mNextp->mPrevpp = mCurrentOperatingp->mPrevpp; - } - *(mCurrentOperatingp->mPrevpp) = mCurrentOperatingp->mNextp; - - // remove the LLLinkNode - mCurrentp = mCurrentOperatingp->mNextp; - - mCurrentOperatingp->deleteData(); - if (mCurrentOperatingp->mDatap) - llerror("This is impossible!", 0); - delete mCurrentOperatingp; - mCurrentOperatingp = mCurrentp; - mCount--; - } -} - -#endif diff --git a/indra/llcommon/ll_template_cast.h b/indra/llcommon/ll_template_cast.h deleted file mode 100755 index c8f9a2f7eb..0000000000 --- a/indra/llcommon/ll_template_cast.h +++ /dev/null @@ -1,177 +0,0 @@ -/** - * @file ll_template_cast.h - * @author Nat Goodspeed - * @date 2009-11-21 - * @brief Define ll_template_cast function - * - * $LicenseInfo:firstyear=2009&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#if ! defined(LL_LL_TEMPLATE_CAST_H) -#define LL_LL_TEMPLATE_CAST_H - -/** - * Implementation for ll_template_cast() (q.v.). - * - * Default implementation: trying to cast two completely unrelated types - * returns 0. Typically you'd specify T and U as pointer types, but in fact T - * can be any type that can be initialized with 0. - */ -template <typename T, typename U> -struct ll_template_cast_impl -{ - T operator()(U) - { - return 0; - } -}; - -/** - * ll_template_cast<T>(some_value) is for use in a template function when - * some_value might be of arbitrary type, but you want to recognize type T - * specially. - * - * It's designed for use with pointer types. Example: - * @code - * struct SpecialClass - * { - * void someMethod(const std::string&) const; - * }; - * - * template <class REALCLASS> - * void somefunc(const REALCLASS& instance) - * { - * const SpecialClass* ptr = ll_template_cast<const SpecialClass*>(&instance); - * if (ptr) - * { - * ptr->someMethod("Call method only available on SpecialClass"); - * } - * } - * @endcode - * - * Why is this better than dynamic_cast<>? Because unless OtherClass is - * polymorphic, the following won't even compile (gcc 4.0.1): - * @code - * OtherClass other; - * SpecialClass* ptr = dynamic_cast<SpecialClass*>(&other); - * @endcode - * to say nothing of this: - * @code - * void function(int); - * SpecialClass* ptr = dynamic_cast<SpecialClass*>(&function); - * @endcode - * ll_template_cast handles these kinds of cases by returning 0. - */ -template <typename T, typename U> -T ll_template_cast(U value) -{ - return ll_template_cast_impl<T, U>()(value); -} - -/** - * Implementation for ll_template_cast() (q.v.). - * - * Implementation for identical types: return same value. - */ -template <typename T> -struct ll_template_cast_impl<T, T> -{ - T operator()(T value) - { - return value; - } -}; - -/** - * LL_TEMPLATE_CONVERTIBLE(dest, source) asserts that, for a value @c s of - * type @c source, <tt>ll_template_cast<dest>(s)</tt> will return @c s -- - * presuming that @c source can be converted to @c dest by the normal rules of - * C++. - * - * By default, <tt>ll_template_cast<dest>(s)</tt> will return 0 unless @c s's - * type is literally identical to @c dest. (This is because of the - * straightforward application of template specialization rules.) That can - * lead to surprising results, e.g.: - * - * @code - * Foo myFoo; - * const Foo* fooptr = ll_template_cast<const Foo*>(&myFoo); - * @endcode - * - * Here @c fooptr will be 0 because <tt>&myFoo</tt> is of type <tt>Foo*</tt> - * -- @em not <tt>const Foo*</tt>. (Declaring <tt>const Foo myFoo;</tt> would - * force the compiler to do the right thing.) - * - * More disappointingly: - * @code - * struct Base {}; - * struct Subclass: public Base {}; - * Subclass object; - * Base* ptr = ll_template_cast<Base*>(&object); - * @endcode - * - * Here @c ptr will be 0 because <tt>&object</tt> is of type - * <tt>Subclass*</tt> rather than <tt>Base*</tt>. We @em want this cast to - * succeed, but without our help ll_template_cast can't recognize it. - * - * The following would suffice: - * @code - * LL_TEMPLATE_CONVERTIBLE(Base*, Subclass*); - * ... - * Base* ptr = ll_template_cast<Base*>(&object); - * @endcode - * - * However, as noted earlier, this is easily fooled: - * @code - * const Base* ptr = ll_template_cast<const Base*>(&object); - * @endcode - * would still produce 0 because we haven't yet seen: - * @code - * LL_TEMPLATE_CONVERTIBLE(const Base*, Subclass*); - * @endcode - * - * @TODO - * This macro should use Boost type_traits facilities for stripping and - * re-adding @c const and @c volatile qualifiers so that invoking - * LL_TEMPLATE_CONVERTIBLE(dest, source) will automatically generate all - * permitted permutations. It's really not fair to the coder to require - * separate: - * @code - * LL_TEMPLATE_CONVERTIBLE(Base*, Subclass*); - * LL_TEMPLATE_CONVERTIBLE(const Base*, Subclass*); - * LL_TEMPLATE_CONVERTIBLE(const Base*, const Subclass*); - * @endcode - * - * (Naturally we omit <tt>LL_TEMPLATE_CONVERTIBLE(Base*, const Subclass*)</tt> - * because that's not permitted by normal C++ assignment anyway.) - */ -#define LL_TEMPLATE_CONVERTIBLE(DEST, SOURCE) \ -template <> \ -struct ll_template_cast_impl<DEST, SOURCE> \ -{ \ - DEST operator()(SOURCE wrapper) \ - { \ - return wrapper; \ - } \ -} - -#endif /* ! defined(LL_LL_TEMPLATE_CAST_H) */ diff --git a/indra/llcommon/llaccountingcost.h b/indra/llcommon/llaccountingcost.h deleted file mode 100755 index 0ef3b50c6d..0000000000 --- a/indra/llcommon/llaccountingcost.h +++ /dev/null @@ -1,86 +0,0 @@ -/** - * @file llaccountingcost.h - * @ - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2011, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_ACCOUNTINGQUOTA_H -#define LL_ACCOUNTINGQUOTA_H - -struct ParcelQuota -{ - ParcelQuota( F32 ownerRenderCost, F32 ownerPhysicsCost, F32 ownerNetworkCost, F32 ownerSimulationCost, - F32 groupRenderCost, F32 groupPhysicsCost, F32 groupNetworkCost, F32 groupSimulationCost, - F32 otherRenderCost, F32 otherPhysicsCost, F32 otherNetworkCost, F32 otherSimulationCost, - F32 tempRenderCost, F32 tempPhysicsCost, F32 tempNetworkCost, F32 tempSimulationCost, - F32 selectedRenderCost, F32 selectedPhysicsCost, F32 selectedNetworkCost, F32 selectedSimulationCost, - F32 parcelCapacity ) - : mOwnerRenderCost( ownerRenderCost ), mOwnerPhysicsCost( ownerPhysicsCost ) - , mOwnerNetworkCost( ownerNetworkCost ), mOwnerSimulationCost( ownerSimulationCost ) - , mGroupRenderCost( groupRenderCost ), mGroupPhysicsCost( groupPhysicsCost ) - , mGroupNetworkCost( groupNetworkCost ), mGroupSimulationCost( groupSimulationCost ) - , mOtherRenderCost( otherRenderCost ), mOtherPhysicsCost( otherPhysicsCost ) - , mOtherNetworkCost( otherNetworkCost ), mOtherSimulationCost( otherSimulationCost ) - , mTempRenderCost( tempRenderCost ), mTempPhysicsCost( tempPhysicsCost ) - , mTempNetworkCost( tempNetworkCost ), mTempSimulationCost( tempSimulationCost ) - , mSelectedRenderCost( tempRenderCost ), mSelectedPhysicsCost( tempPhysicsCost ) - , mSelectedNetworkCost( tempNetworkCost ), mSelectedSimulationCost( selectedSimulationCost ) - , mParcelCapacity( parcelCapacity ) - { - } - - ParcelQuota(){} - F32 mOwnerRenderCost, mOwnerPhysicsCost, mOwnerNetworkCost, mOwnerSimulationCost; - F32 mGroupRenderCost, mGroupPhysicsCost, mGroupNetworkCost, mGroupSimulationCost; - F32 mOtherRenderCost, mOtherPhysicsCost, mOtherNetworkCost, mOtherSimulationCost; - F32 mTempRenderCost, mTempPhysicsCost, mTempNetworkCost, mTempSimulationCost; - F32 mSelectedRenderCost, mSelectedPhysicsCost, mSelectedNetworkCost, mSelectedSimulationCost; - F32 mParcelCapacity; -}; - -//SelectionQuota atm does not require a id -struct SelectionCost -{ - SelectionCost( /*LLTransactionID transactionId, */ F32 physicsCost, F32 networkCost, F32 simulationCost ) - //: mTransactionId( transactionId) - : mPhysicsCost( physicsCost ) - , mNetworkCost( networkCost ) - , mSimulationCost( simulationCost ) - { - } - SelectionCost() - : mPhysicsCost( 0.0f ) - , mNetworkCost( 0.0f ) - , mSimulationCost( 0.0f ) - {} - - F32 mPhysicsCost, mNetworkCost, mSimulationCost; - //LLTransactionID mTransactionId; -}; - -typedef enum { Roots = 0 , Prims } eSelectionType; - -#endif - - - diff --git a/indra/llcommon/llagentconstants.h b/indra/llcommon/llagentconstants.h deleted file mode 100755 index cd237da4eb..0000000000 --- a/indra/llcommon/llagentconstants.h +++ /dev/null @@ -1,159 +0,0 @@ -/** - * @file llagentconstants.h - * @author James Cook, Andrew Meadows, Richard Nelson - * @brief Shared constants through the system for agents. - * - * $LicenseInfo:firstyear=2006&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_LLAGENTCONSTANTS_H -#define LL_LLAGENTCONSTANTS_H - -const U32 CONTROL_AT_POS_INDEX = 0; -const U32 CONTROL_AT_NEG_INDEX = 1; -const U32 CONTROL_LEFT_POS_INDEX = 2; -const U32 CONTROL_LEFT_NEG_INDEX = 3; -const U32 CONTROL_UP_POS_INDEX = 4; -const U32 CONTROL_UP_NEG_INDEX = 5; -const U32 CONTROL_PITCH_POS_INDEX = 6; -const U32 CONTROL_PITCH_NEG_INDEX = 7; -const U32 CONTROL_YAW_POS_INDEX = 8; -const U32 CONTROL_YAW_NEG_INDEX = 9; -const U32 CONTROL_FAST_AT_INDEX = 10; -const U32 CONTROL_FAST_LEFT_INDEX = 11; -const U32 CONTROL_FAST_UP_INDEX = 12; -const U32 CONTROL_FLY_INDEX = 13; -const U32 CONTROL_STOP_INDEX = 14; -const U32 CONTROL_FINISH_ANIM_INDEX = 15; -const U32 CONTROL_STAND_UP_INDEX = 16; -const U32 CONTROL_SIT_ON_GROUND_INDEX = 17; -const U32 CONTROL_MOUSELOOK_INDEX = 18; -const U32 CONTROL_NUDGE_AT_POS_INDEX = 19; -const U32 CONTROL_NUDGE_AT_NEG_INDEX = 20; -const U32 CONTROL_NUDGE_LEFT_POS_INDEX = 21; -const U32 CONTROL_NUDGE_LEFT_NEG_INDEX = 22; -const U32 CONTROL_NUDGE_UP_POS_INDEX = 23; -const U32 CONTROL_NUDGE_UP_NEG_INDEX = 24; -const U32 CONTROL_TURN_LEFT_INDEX = 25; -const U32 CONTROL_TURN_RIGHT_INDEX = 26; -const U32 CONTROL_AWAY_INDEX = 27; -const U32 CONTROL_LBUTTON_DOWN_INDEX = 28; -const U32 CONTROL_LBUTTON_UP_INDEX = 29; -const U32 CONTROL_ML_LBUTTON_DOWN_INDEX = 30; -const U32 CONTROL_ML_LBUTTON_UP_INDEX = 31; -const U32 TOTAL_CONTROLS = 32; - -const U32 AGENT_CONTROL_AT_POS = 0x1 << CONTROL_AT_POS_INDEX; // 0x00000001 -const U32 AGENT_CONTROL_AT_NEG = 0x1 << CONTROL_AT_NEG_INDEX; // 0x00000002 -const U32 AGENT_CONTROL_LEFT_POS = 0x1 << CONTROL_LEFT_POS_INDEX; // 0x00000004 -const U32 AGENT_CONTROL_LEFT_NEG = 0x1 << CONTROL_LEFT_NEG_INDEX; // 0x00000008 -const U32 AGENT_CONTROL_UP_POS = 0x1 << CONTROL_UP_POS_INDEX; // 0x00000010 -const U32 AGENT_CONTROL_UP_NEG = 0x1 << CONTROL_UP_NEG_INDEX; // 0x00000020 -const U32 AGENT_CONTROL_PITCH_POS = 0x1 << CONTROL_PITCH_POS_INDEX; // 0x00000040 -const U32 AGENT_CONTROL_PITCH_NEG = 0x1 << CONTROL_PITCH_NEG_INDEX; // 0x00000080 -const U32 AGENT_CONTROL_YAW_POS = 0x1 << CONTROL_YAW_POS_INDEX; // 0x00000100 -const U32 AGENT_CONTROL_YAW_NEG = 0x1 << CONTROL_YAW_NEG_INDEX; // 0x00000200 - -const U32 AGENT_CONTROL_FAST_AT = 0x1 << CONTROL_FAST_AT_INDEX; // 0x00000400 -const U32 AGENT_CONTROL_FAST_LEFT = 0x1 << CONTROL_FAST_LEFT_INDEX; // 0x00000800 -const U32 AGENT_CONTROL_FAST_UP = 0x1 << CONTROL_FAST_UP_INDEX; // 0x00001000 - -const U32 AGENT_CONTROL_FLY = 0x1 << CONTROL_FLY_INDEX; // 0x00002000 -const U32 AGENT_CONTROL_STOP = 0x1 << CONTROL_STOP_INDEX; // 0x00004000 -const U32 AGENT_CONTROL_FINISH_ANIM = 0x1 << CONTROL_FINISH_ANIM_INDEX; // 0x00008000 -const U32 AGENT_CONTROL_STAND_UP = 0x1 << CONTROL_STAND_UP_INDEX; // 0x00010000 -const U32 AGENT_CONTROL_SIT_ON_GROUND = 0x1 << CONTROL_SIT_ON_GROUND_INDEX; // 0x00020000 -const U32 AGENT_CONTROL_MOUSELOOK = 0x1 << CONTROL_MOUSELOOK_INDEX; // 0x00040000 - -const U32 AGENT_CONTROL_NUDGE_AT_POS = 0x1 << CONTROL_NUDGE_AT_POS_INDEX; // 0x00080000 -const U32 AGENT_CONTROL_NUDGE_AT_NEG = 0x1 << CONTROL_NUDGE_AT_NEG_INDEX; // 0x00100000 -const U32 AGENT_CONTROL_NUDGE_LEFT_POS = 0x1 << CONTROL_NUDGE_LEFT_POS_INDEX; // 0x00200000 -const U32 AGENT_CONTROL_NUDGE_LEFT_NEG = 0x1 << CONTROL_NUDGE_LEFT_NEG_INDEX; // 0x00400000 -const U32 AGENT_CONTROL_NUDGE_UP_POS = 0x1 << CONTROL_NUDGE_UP_POS_INDEX; // 0x00800000 -const U32 AGENT_CONTROL_NUDGE_UP_NEG = 0x1 << CONTROL_NUDGE_UP_NEG_INDEX; // 0x01000000 -const U32 AGENT_CONTROL_TURN_LEFT = 0x1 << CONTROL_TURN_LEFT_INDEX; // 0x02000000 -const U32 AGENT_CONTROL_TURN_RIGHT = 0x1 << CONTROL_TURN_RIGHT_INDEX; // 0x04000000 - -const U32 AGENT_CONTROL_AWAY = 0x1 << CONTROL_AWAY_INDEX; // 0x08000000 - -const U32 AGENT_CONTROL_LBUTTON_DOWN = 0x1 << CONTROL_LBUTTON_DOWN_INDEX; // 0x10000000 -const U32 AGENT_CONTROL_LBUTTON_UP = 0x1 << CONTROL_LBUTTON_UP_INDEX; // 0x20000000 -const U32 AGENT_CONTROL_ML_LBUTTON_DOWN = 0x1 << CONTROL_ML_LBUTTON_DOWN_INDEX; // 0x40000000 -const U32 AGENT_CONTROL_ML_LBUTTON_UP = ((U32)0x1) << CONTROL_ML_LBUTTON_UP_INDEX; // 0x80000000 - -const U32 AGENT_CONTROL_AT = AGENT_CONTROL_AT_POS - | AGENT_CONTROL_AT_NEG - | AGENT_CONTROL_NUDGE_AT_POS - | AGENT_CONTROL_NUDGE_AT_NEG; - -const U32 AGENT_CONTROL_LEFT = AGENT_CONTROL_LEFT_POS - | AGENT_CONTROL_LEFT_NEG - | AGENT_CONTROL_NUDGE_LEFT_POS - | AGENT_CONTROL_NUDGE_LEFT_NEG; - -const U32 AGENT_CONTROL_UP = AGENT_CONTROL_UP_POS - | AGENT_CONTROL_UP_NEG - | AGENT_CONTROL_NUDGE_UP_POS - | AGENT_CONTROL_NUDGE_UP_NEG; - -const U32 AGENT_CONTROL_HORIZONTAL = AGENT_CONTROL_AT - | AGENT_CONTROL_LEFT; - -const U32 AGENT_CONTROL_NOT_USED_BY_LSL = AGENT_CONTROL_FLY - | AGENT_CONTROL_STOP - | AGENT_CONTROL_FINISH_ANIM - | AGENT_CONTROL_STAND_UP - | AGENT_CONTROL_SIT_ON_GROUND - | AGENT_CONTROL_MOUSELOOK - | AGENT_CONTROL_AWAY; - -const U32 AGENT_CONTROL_MOVEMENT = AGENT_CONTROL_AT - | AGENT_CONTROL_LEFT - | AGENT_CONTROL_UP; - -const U32 AGENT_CONTROL_ROTATION = AGENT_CONTROL_PITCH_POS - | AGENT_CONTROL_PITCH_NEG - | AGENT_CONTROL_YAW_POS - | AGENT_CONTROL_YAW_NEG; - -const U32 AGENT_CONTROL_NUDGE = AGENT_CONTROL_NUDGE_AT_POS - | AGENT_CONTROL_NUDGE_AT_NEG - | AGENT_CONTROL_NUDGE_LEFT_POS - | AGENT_CONTROL_NUDGE_LEFT_NEG; - - -// move these up so that we can hide them in "State" for object updates -// (for now) -const U32 AGENT_ATTACH_OFFSET = 4; -const U32 AGENT_ATTACH_MASK = 0xf << AGENT_ATTACH_OFFSET; -const U32 AGENT_ATTACH_CLEAR = 0x00; - -// RN: this method swaps the upper and lower nibbles to maintain backward -// compatibility with old objects that only used the upper nibble -#define ATTACHMENT_ID_FROM_STATE(state) ((S32)((((U8)state & AGENT_ATTACH_MASK) >> 4) | (((U8)state & ~AGENT_ATTACH_MASK) << 4))) - -// test state for use in testing grabbing the camera -const U32 AGENT_CAMERA_OBJECT = 0x1 << 3; - -const F32 MAX_ATTACHMENT_DIST = 3.5f; // meters? - -#endif diff --git a/indra/llcommon/llalignedarray.h b/indra/llcommon/llalignedarray.h index ed8fd31205..b68e9e0f82 100644 --- a/indra/llcommon/llalignedarray.h +++ b/indra/llcommon/llalignedarray.h @@ -60,7 +60,7 @@ LLAlignedArray<T, alignment>::LLAlignedArray() template <class T, U32 alignment> LLAlignedArray<T, alignment>::~LLAlignedArray() { - ll_aligned_free(mArray); + ll_aligned_free<alignment>(mArray); mArray = NULL; mElementCount = 0; mCapacity = 0; @@ -74,7 +74,7 @@ void LLAlignedArray<T, alignment>::push_back(const T& elem) { mCapacity++; mCapacity *= 2; - T* new_buf = (T*) ll_aligned_malloc(mCapacity*sizeof(T), alignment); + T* new_buf = (T*) ll_aligned_malloc<alignment>(mCapacity*sizeof(T)); if (mArray) { ll_memcpy_nonaliased_aligned_16((char*)new_buf, (char*)mArray, sizeof(T)*mElementCount); @@ -86,7 +86,7 @@ void LLAlignedArray<T, alignment>::push_back(const T& elem) mArray[mElementCount++] = elem; //delete old array here to prevent error on a.push_back(a[0]) - ll_aligned_free(old_buf); + ll_aligned_free<alignment>(old_buf); } template <class T, U32 alignment> @@ -95,11 +95,11 @@ void LLAlignedArray<T, alignment>::resize(U32 size) if (mCapacity < size) { mCapacity = size+mCapacity*2; - T* new_buf = mCapacity > 0 ? (T*) ll_aligned_malloc(mCapacity*sizeof(T), alignment) : NULL; + T* new_buf = mCapacity > 0 ? (T*) ll_aligned_malloc<alignment>(mCapacity*sizeof(T)) : NULL; if (mArray) { ll_memcpy_nonaliased_aligned_16((char*) new_buf, (char*) mArray, sizeof(T)*mElementCount); - ll_aligned_free(mArray); + ll_aligned_free<alignment>(mArray); } /*for (U32 i = mElementCount; i < mCapacity; ++i) diff --git a/indra/llcommon/llallocator_heap_profile.cpp b/indra/llcommon/llallocator_heap_profile.cpp index b574ef668b..b2eafde1aa 100755 --- a/indra/llcommon/llallocator_heap_profile.cpp +++ b/indra/llcommon/llallocator_heap_profile.cpp @@ -59,7 +59,7 @@ void LLAllocatorHeapProfile::parse(std::string const & prof_text) { // *TODO - determine if there should be some better error state than // mLines being empty. -brad - llwarns << "invalid heap profile data passed into parser." << llendl; + LL_WARNS() << "invalid heap profile data passed into parser." << LL_ENDL; return; } diff --git a/indra/llcommon/llapp.cpp b/indra/llcommon/llapp.cpp index 67a98d5fb8..5a40845e7d 100755 --- a/indra/llcommon/llapp.cpp +++ b/indra/llcommon/llapp.cpp @@ -46,8 +46,8 @@ #include "llstl.h" // for DeletePointer() #include "llstring.h" #include "lleventtimer.h" - #include "google_breakpad/exception_handler.h" +#include "stringize.h" // // Signal handling @@ -55,6 +55,8 @@ // Windows uses structured exceptions, so it's handled a bit differently. // #if LL_WINDOWS +#include "windows.h" + LONG WINAPI default_windows_exception_handler(struct _EXCEPTION_POINTERS *exception_infop); BOOL ConsoleCtrlHandler(DWORD fdwCtrlType); bool windows_post_minidump_callback(const wchar_t* dump_path, @@ -71,7 +73,9 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *); #if LL_LINUX #include "google_breakpad/minidump_descriptor.h" -bool unix_minidump_callback(const google_breakpad::MinidumpDescriptor& minidump_desc, void* context, bool succeeded); +static bool unix_minidump_callback(const google_breakpad::MinidumpDescriptor& minidump_desc, + void* context, + bool succeeded); #else // Called by breakpad exception handler after the minidump has been generated. bool unix_post_minidump_callback(const char *dump_dir, @@ -109,11 +113,6 @@ BOOL LLApp::sLogInSignal = FALSE; LLApp::EAppStatus LLApp::sStatus = LLApp::APP_STATUS_STOPPED; // Keeps track of application status LLAppErrorHandler LLApp::sErrorHandler = NULL; BOOL LLApp::sErrorThreadRunning = FALSE; -#if !LL_WINDOWS -LLApp::child_map LLApp::sChildMap; -LLAtomicU32* LLApp::sSigChildCount = NULL; -LLAppChildCallback LLApp::sDefaultChildCallback = NULL; -#endif LLApp::LLApp() : mThreadErrorp(NULL) @@ -128,11 +127,6 @@ void LLApp::commonCtor() LLCommon::initClass(); -#if !LL_WINDOWS - // This must be initialized before the error handler. - sSigChildCount = new LLAtomicU32(0); -#endif - // initialize the options structure. We need to make this an array // because the structured data will not auto-allocate if we // reference an invalid location with the [] operator. @@ -149,12 +143,13 @@ void LLApp::commonCtor() // Set the application to this instance. sApplication = this; - + mExceptionHandler = 0; // initialize the buffer to write the minidump filename to // (this is used to avoid allocating memory in the crash handler) - memset(minidump_path, 0, MAX_MINDUMP_PATH_LENGTH); + memset(mMinidumpPath, 0, MAX_MINDUMP_PATH_LENGTH); + mCrashReportPipeStr = L"\\\\.\\pipe\\LLCrashReporterPipe"; } LLApp::LLApp(LLErrorThread *error_thread) : @@ -166,10 +161,6 @@ LLApp::LLApp(LLErrorThread *error_thread) : LLApp::~LLApp() { -#if !LL_WINDOWS - delete sSigChildCount; - sSigChildCount = NULL; -#endif // reclaim live file memory std::for_each(mLiveFiles.begin(), mLiveFiles.end(), DeletePointer()); @@ -218,8 +209,8 @@ bool LLApp::parseCommandOptions(int argc, char** argv) { if(argv[ii][0] != '-') { - llinfos << "Did not find option identifier while parsing token: " - << argv[ii] << llendl; + LL_INFOS() << "Did not find option identifier while parsing token: " + << argv[ii] << LL_ENDL; return false; } int offset = 1; @@ -244,6 +235,20 @@ bool LLApp::parseCommandOptions(int argc, char** argv) } ++ii; value.assign(argv[ii]); + +#if LL_WINDOWS + //Windows changed command line parsing. Deal with it. + S32 slen = value.length() - 1; + S32 start = 0; + S32 end = slen; + if (argv[ii][start]=='"')start++; + if (argv[ii][end]=='"')end--; + if (start!=0 || end!=slen) + { + value = value.substr (start,end); + } +#endif + commands[name] = value; } setOptionData(PRIORITY_COMMAND_LINE, commands); @@ -288,14 +293,43 @@ void LLApp::stepFrame() mRunner.run(); } +#if LL_WINDOWS +//The following code is needed for 32-bit apps on 64-bit windows to keep it from eating +//crashes. It is a lovely undocumented 'feature' in SP1 of Windows 7. An excellent +//in-depth article on the issue may be found here: http://randomascii.wordpress.com/2012/07/05/when-even-crashing-doesn-work/ +void EnableCrashingOnCrashes() +{ + typedef BOOL (WINAPI *tGetPolicy)(LPDWORD lpFlags); + typedef BOOL (WINAPI *tSetPolicy)(DWORD dwFlags); + const DWORD EXCEPTION_SWALLOWING = 0x1; + + HMODULE kernel32 = LoadLibraryA("kernel32.dll"); + tGetPolicy pGetPolicy = (tGetPolicy)GetProcAddress(kernel32, + "GetProcessUserModeExceptionPolicy"); + tSetPolicy pSetPolicy = (tSetPolicy)GetProcAddress(kernel32, + "SetProcessUserModeExceptionPolicy"); + if (pGetPolicy && pSetPolicy) + { + DWORD dwFlags; + if (pGetPolicy(&dwFlags)) + { + // Turn off the filter + pSetPolicy(dwFlags & ~EXCEPTION_SWALLOWING); + } + } +} +#endif -void LLApp::setupErrorHandling() +void LLApp::setupErrorHandling(bool second_instance) { // Error handling is done by starting up an error handling thread, which just sleeps and // occasionally checks to see if the app is in an error state, and sees if it needs to be run. #if LL_WINDOWS + #if LL_SEND_CRASH_REPORTS + EnableCrashingOnCrashes(); + // This sets a callback to handle w32 signals to the console window. // The viewer shouldn't be affected, sicne its a windowed app. SetConsoleCtrlHandler( (PHANDLER_ROUTINE) ConsoleCtrlHandler, TRUE); @@ -303,9 +337,57 @@ void LLApp::setupErrorHandling() // Install the Google Breakpad crash handler for Windows if(mExceptionHandler == 0) { - llwarns << "adding breakpad exception handler" << llendl; - mExceptionHandler = new google_breakpad::ExceptionHandler( - L"C:\\Temp\\", 0, windows_post_minidump_callback, 0, google_breakpad::ExceptionHandler::HANDLER_ALL); + if ( second_instance ) //BUG-5707 Firing teleport from a web browser causes second + { + mExceptionHandler = new google_breakpad::ExceptionHandler( + L"C:\\Temp\\", + 0, //No filter + windows_post_minidump_callback, + 0, + google_breakpad::ExceptionHandler::HANDLER_ALL); //No custom client info. + } + else + { + LL_WARNS() << "adding breakpad exception handler" << LL_ENDL; + + std::wstring wpipe_name; + wpipe_name = mCrashReportPipeStr + wstringize(getPid()); + + const std::wstring wdump_path(wstringize(mDumpPath)); + + int retries = 30; + for (; retries > 0; --retries) + { + if (mExceptionHandler != 0) delete mExceptionHandler; + + mExceptionHandler = new google_breakpad::ExceptionHandler( + wdump_path, + NULL, //No filter + windows_post_minidump_callback, + 0, + google_breakpad::ExceptionHandler::HANDLER_ALL, + MiniDumpNormal, //Generate a 'normal' minidump. + wpipe_name.c_str(), + NULL); //No custom client info. + if (mExceptionHandler->IsOutOfProcess()) + { + LL_INFOS("CRASHREPORT") << "Successfully attached to Out of Process exception handler." << LL_ENDL; + break; + } + else + { + LL_WARNS("CRASHREPORT") << "Unable to attach to Out of Process exception handler. " << retries << " retries remaining." << LL_ENDL; + ::Sleep(100); //Wait a tick and try again. + } + } + + if (retries == 0) LL_WARNS("CRASHREPORT") << "Unable to attach to Out of Process exception handler." << LL_ENDL; + } + + if (mExceptionHandler) + { + mExceptionHandler->set_handle_debug_exceptions(true); + } } #endif #else @@ -355,14 +437,17 @@ void LLApp::setupErrorHandling() if(installHandler && (mExceptionHandler == 0)) { - std::string dumpPath = "/tmp/"; - mExceptionHandler = new google_breakpad::ExceptionHandler(dumpPath, 0, &unix_post_minidump_callback, 0, true, 0); + mExceptionHandler = new google_breakpad::ExceptionHandler(mDumpPath, 0, &unix_post_minidump_callback, 0, true, 0); } #elif LL_LINUX if(installHandler && (mExceptionHandler == 0)) { - google_breakpad::MinidumpDescriptor desc("/tmp"); - new google_breakpad::ExceptionHandler(desc, 0, &unix_minidump_callback, 0, true, 0); + if (mDumpPath.empty()) + { + mDumpPath = "/tmp"; + } + google_breakpad::MinidumpDescriptor desc(mDumpPath); + mExceptionHandler = new google_breakpad::ExceptionHandler(desc, NULL, unix_minidump_callback, NULL, true, -1); } #endif @@ -378,7 +463,7 @@ void LLApp::startErrorThread() // if(!mThreadErrorp) { - llinfos << "Starting error thread" << llendl; + LL_INFOS() << "Starting error thread" << LL_ENDL; mThreadErrorp = new LLErrorThread(); mThreadErrorp->setUserData((void *) this); mThreadErrorp->start(); @@ -398,7 +483,7 @@ void LLApp::runErrorHandler() LLApp::sErrorHandler(); } - //llinfos << "App status now STOPPED" << llendl; + //LL_INFOS() << "App status now STOPPED" << LL_ENDL; LLApp::setStopped(); } @@ -418,19 +503,35 @@ void LLApp::setError() void LLApp::setMiniDumpDir(const std::string &path) { + if (path.empty()) + { + mDumpPath = "/tmp"; + } + else + { + mDumpPath = path; + } + if(mExceptionHandler == 0) return; #ifdef LL_WINDOWS wchar_t buffer[MAX_MINDUMP_PATH_LENGTH]; - mbstowcs(buffer, path.c_str(), MAX_MINDUMP_PATH_LENGTH); + mbstowcs(buffer, mDumpPath.c_str(), MAX_MINDUMP_PATH_LENGTH); mExceptionHandler->set_dump_path(std::wstring(buffer)); #elif LL_LINUX - google_breakpad::MinidumpDescriptor desc(path); + //google_breakpad::MinidumpDescriptor desc("/tmp"); //path works in debug fails in production inside breakpad lib so linux gets a little less stack reporting until it is patched. + google_breakpad::MinidumpDescriptor desc(mDumpPath); //path works in debug fails in production inside breakpad lib so linux gets a little less stack reporting until it is patched. mExceptionHandler->set_minidump_descriptor(desc); #else - mExceptionHandler->set_dump_path(path); + mExceptionHandler->set_dump_path(mDumpPath); #endif } +void LLApp::setDebugFileNames(const std::string &path) +{ + mStaticDebugFileName = path + "static_debug_info.log"; + mDynamicDebugFileName = path + "dynamic_debug_info.log"; +} + void LLApp::writeMiniDump() { if(mExceptionHandler == 0) return; @@ -443,7 +544,7 @@ void LLApp::setQuitting() if (!isExiting()) { // If we're already exiting, we don't want to reset our state back to quitting. - llinfos << "Setting app state to QUITTING" << llendl; + LL_INFOS() << "Setting app state to QUITTING" << LL_ENDL; setStatus(APP_STATUS_QUITTING); } } @@ -507,34 +608,11 @@ bool LLApp::isCrashloggerDisabled() return (sDisableCrashlogger == TRUE); } -#if !LL_WINDOWS -// static -U32 LLApp::getSigChildCount() -{ - if (sSigChildCount) - { - return U32(*sSigChildCount); - } - return 0; -} - -// static -void LLApp::incSigChildCount() -{ - if (sSigChildCount) - { - (*sSigChildCount)++; - } -} - -#endif - - // static int LLApp::getPid() { #if LL_WINDOWS - return 0; + return GetCurrentProcessId(); #else return getpid(); #endif @@ -551,7 +629,7 @@ LONG WINAPI default_windows_exception_handler(struct _EXCEPTION_POINTERS *except if (LLApp::isError()) { - llwarns << "Got another fatal signal while in the error handler, die now!" << llendl; + LL_WARNS() << "Got another fatal signal while in the error handler, die now!" << LL_ENDL; retval = EXCEPTION_EXECUTE_HANDLER; return retval; } @@ -597,7 +675,7 @@ BOOL ConsoleCtrlHandler(DWORD fdwCtrlType) // We're already trying to die, just ignore this signal if (LLApp::sLogInSignal) { - llinfos << "Signal handler - Already trying to quit, ignoring signal!" << llendl; + LL_INFOS() << "Signal handler - Already trying to quit, ignoring signal!" << LL_ENDL; } return TRUE; } @@ -610,43 +688,6 @@ BOOL ConsoleCtrlHandler(DWORD fdwCtrlType) } #else //!LL_WINDOWS -void LLApp::setChildCallback(pid_t pid, LLAppChildCallback callback) -{ - LLChildInfo child_info; - child_info.mCallback = callback; - LLApp::sChildMap[pid] = child_info; -} - -void LLApp::setDefaultChildCallback(LLAppChildCallback callback) -{ - LLApp::sDefaultChildCallback = callback; -} - -pid_t LLApp::fork() -{ - fflush(NULL); // flush all buffers before the child inherits them - pid_t pid = ::fork(); - if( pid < 0 ) - { - int system_error = errno; - llwarns << "Unable to fork! Operating system error code: " - << system_error << llendl; - } - else if (pid == 0) - { - // Sleep a bit to allow the parent to set up child callbacks. - ms_sleep(10); - - // We need to disable signal handling, because we don't have a - // signal handling thread anymore. - setupErrorHandling(); - } - else - { - llinfos << "Forked child process " << pid << llendl; - } - return pid; -} void setup_signals() { @@ -735,7 +776,7 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *) if (LLApp::sLogInSignal) { - llinfos << "Signal handler - Got signal " << signum << " - " << apr_signal_description_get(signum) << llendl; + LL_INFOS() << "Signal handler - Got signal " << signum << " - " << apr_signal_description_get(signum) << LL_ENDL; } @@ -744,28 +785,15 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *) case SIGCHLD: if (LLApp::sLogInSignal) { - llinfos << "Signal handler - Got SIGCHLD from " << info->si_pid << llendl; - } - - // Check result code for all child procs for which we've - // registered callbacks THIS WILL NOT WORK IF SIGCHLD IS SENT - // w/o killing the child (Go, launcher!) - // TODO: Now that we're using SIGACTION, we can actually - // implement the launcher behavior to determine who sent the - // SIGCHLD even if it doesn't result in child termination - if (LLApp::sChildMap.count(info->si_pid)) - { - LLApp::sChildMap[info->si_pid].mGotSigChild = TRUE; + LL_INFOS() << "Signal handler - Got SIGCHLD from " << info->si_pid << LL_ENDL; } - - LLApp::incSigChildCount(); return; case SIGABRT: // Abort just results in termination of the app, no funky error handling. if (LLApp::sLogInSignal) { - llwarns << "Signal handler - Got SIGABRT, terminating" << llendl; + LL_WARNS() << "Signal handler - Got SIGABRT, terminating" << LL_ENDL; } clear_signals(); raise(signum); @@ -775,7 +803,7 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *) case SIGTERM: if (LLApp::sLogInSignal) { - llwarns << "Signal handler - Got SIGINT, HUP, or TERM, exiting gracefully" << llendl; + LL_WARNS() << "Signal handler - Got SIGINT, HUP, or TERM, exiting gracefully" << LL_ENDL; } // Graceful exit // Just set our state to quitting, not error @@ -784,7 +812,7 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *) // We're already trying to die, just ignore this signal if (LLApp::sLogInSignal) { - llinfos << "Signal handler - Already trying to quit, ignoring signal!" << llendl; + LL_INFOS() << "Signal handler - Already trying to quit, ignoring signal!" << LL_ENDL; } return; } @@ -806,7 +834,7 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *) // Smackdown treated just like any other app termination, for now if (LLApp::sLogInSignal) { - llwarns << "Signal handler - Handling smackdown signal!" << llendl; + LL_WARNS() << "Signal handler - Handling smackdown signal!" << LL_ENDL; } else { @@ -820,7 +848,7 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *) if (LLApp::sLogInSignal) { - llwarns << "Signal handler - Handling fatal signal!" << llendl; + LL_WARNS() << "Signal handler - Handling fatal signal!" << LL_ENDL; } if (LLApp::isError()) { @@ -830,7 +858,7 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *) if (LLApp::sLogInSignal) { - llwarns << "Signal handler - Got another fatal signal while in the error handler, die now!" << llendl; + LL_WARNS() << "Signal handler - Got another fatal signal while in the error handler, die now!" << LL_ENDL; } raise(signum); return; @@ -838,13 +866,13 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *) if (LLApp::sLogInSignal) { - llwarns << "Signal handler - Flagging error status and waiting for shutdown" << llendl; + LL_WARNS() << "Signal handler - Flagging error status and waiting for shutdown" << LL_ENDL; } if (LLApp::isCrashloggerDisabled()) // Don't gracefully handle any signal, crash and core for a gdb post mortem { clear_signals(); - llwarns << "Fatal signal received, not handling the crash here, passing back to operating system" << llendl; + LL_WARNS() << "Fatal signal received, not handling the crash here, passing back to operating system" << LL_ENDL; raise(signum); return; } @@ -859,7 +887,7 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *) if (LLApp::sLogInSignal) { - llwarns << "Signal handler - App is stopped, reraising signal" << llendl; + LL_WARNS() << "Signal handler - App is stopped, reraising signal" << LL_ENDL; } clear_signals(); raise(signum); @@ -867,7 +895,7 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *) } else { if (LLApp::sLogInSignal) { - llinfos << "Signal handler - Unhandled signal " << signum << ", ignoring!" << llendl; + LL_INFOS() << "Signal handler - Unhandled signal " << signum << ", ignoring!" << LL_ENDL; } } } @@ -880,23 +908,28 @@ bool unix_minidump_callback(const google_breakpad::MinidumpDescriptor& minidump_ // heap allocations in a crash handler. // path format: <dump_dir>/<minidump_id>.dmp - int dirPathLength = strlen(minidump_desc.path()); + + //HACK: *path points to the buffer in getMiniDumpFilename which has already allocated space + //to avoid doing allocation during crash. + char * path = LLApp::instance()->getMiniDumpFilename(); + int dir_path_len = strlen(path); // The path must not be truncated. - llassert((dirPathLength + 5) <= LLApp::MAX_MINDUMP_PATH_LENGTH); + S32 remaining = LLApp::MAX_MINDUMP_PATH_LENGTH - dir_path_len; + + llassert( (remaining - strlen(minidump_desc.path())) > 5); - char * path = LLApp::instance()->getMiniDumpFilename(); - S32 remaining = LLApp::MAX_MINDUMP_PATH_LENGTH; - strncpy(path, minidump_desc.path(), remaining); - remaining -= dirPathLength; - path += dirPathLength; - if (remaining > 0 && dirPathLength > 0 && path[-1] != '/') + path += dir_path_len; + + if (dir_path_len > 0 && path[-1] != '/') { *path++ = '/'; --remaining; } + + strncpy(path, minidump_desc.path(), remaining); - llinfos << "generated minidump: " << LLApp::instance()->getMiniDumpFilename() << llendl; + LL_INFOS() << "generated minidump: " << LLApp::instance()->getMiniDumpFilename() << LL_ENDL; LLApp::runErrorHandler(); #ifndef LL_RELEASE_FOR_DOWNLOAD @@ -942,7 +975,7 @@ bool unix_post_minidump_callback(const char *dump_dir, strncpy(path, ".dmp", remaining); } - llinfos << "generated minidump: " << LLApp::instance()->getMiniDumpFilename() << llendl; + LL_INFOS() << "generated minidump: " << LLApp::instance()->getMiniDumpFilename() << LL_ENDL; LLApp::runErrorHandler(); #ifndef LL_RELEASE_FOR_DOWNLOAD @@ -966,6 +999,7 @@ bool windows_post_minidump_callback(const wchar_t* dump_path, S32 remaining = LLApp::MAX_MINDUMP_PATH_LENGTH; size_t bytesUsed; + LL_INFOS("MINIDUMPCALLBACK") << "Dump file was generated." << LL_ENDL; bytesUsed = wcstombs(path, dump_path, static_cast<size_t>(remaining)); remaining -= bytesUsed; path += bytesUsed; @@ -985,16 +1019,16 @@ bool windows_post_minidump_callback(const wchar_t* dump_path, strncpy(path, ".dmp", remaining); } - llinfos << "generated minidump: " << LLApp::instance()->getMiniDumpFilename() << llendl; + LL_INFOS() << "generated minidump: " << LLApp::instance()->getMiniDumpFilename() << LL_ENDL; // *NOTE:Mani - this code is stolen from LLApp, where its never actually used. //OSMessageBox("Attach Debugger Now", "Error", OSMB_OK); // *TODO: Translate the signals/exceptions into cross-platform stuff // Windows implementation - llinfos << "Entering Windows Exception Handler..." << llendl; + LL_INFOS() << "Entering Windows Exception Handler..." << LL_ENDL; if (LLApp::isError()) { - llwarns << "Got another fatal signal while in the error handler, die now!" << llendl; + LL_WARNS() << "Got another fatal signal while in the error handler, die now!" << LL_ENDL; } // Flag status to error, so thread_error starts its work diff --git a/indra/llcommon/llapp.h b/indra/llcommon/llapp.h index afa06df23e..d9933b3d36 100755 --- a/indra/llcommon/llapp.h +++ b/indra/llcommon/llapp.h @@ -30,8 +30,6 @@ #include <map> #include "llrun.h" #include "llsd.h" -#include "lloptioninterface.h" - // Forward declarations template <typename Type> class LLAtomic32; typedef LLAtomic32<U32> LLAtomicU32; @@ -42,7 +40,6 @@ class LLLiveFile; #endif typedef void (*LLAppErrorHandler)(); -typedef void (*LLAppChildCallback)(int pid, bool exited, int status); #if !LL_WINDOWS extern S32 LL_SMACKDOWN_SIGNAL; @@ -51,20 +48,13 @@ extern S32 LL_HEARTBEAT_SIGNAL; // Clear all of the signal handlers (which we want to do for the child process when we fork void clear_signals(); -class LLChildInfo -{ -public: - LLChildInfo() : mGotSigChild(FALSE), mCallback(NULL) {} - BOOL mGotSigChild; - LLAppChildCallback mCallback; -}; #endif namespace google_breakpad { class ExceptionHandler; // See exception_handler.h } -class LL_COMMON_API LLApp : public LLOptionInterface +class LL_COMMON_API LLApp { friend class LLErrorThread; public: @@ -113,7 +103,7 @@ public: * @param name The name of the option. * @return Returns the option data. */ - virtual LLSD getOption(const std::string& name) const; + LLSD getOption(const std::string& name) const; /** * @brief Parse command line options and insert them into @@ -206,10 +196,6 @@ public: static bool isQuitting(); static bool isError(); static bool isExiting(); // Either quitting or error (app is exiting, cleanly or not) -#if !LL_WINDOWS - static U32 getSigChildCount(); - static void incSigChildCount(); -#endif static int getPid(); /** @name Error handling methods */ @@ -227,7 +213,7 @@ public: * DO NOT call this method if your application has specialized * error handling code. */ - void setupErrorHandling(); + void setupErrorHandling(bool mSecondInstance=false); void setErrorHandler(LLAppErrorHandler handler); static void runErrorHandler(); // run shortly after we detect an error, ran in the relatively robust context of the LLErrorThread - preferred. @@ -238,32 +224,16 @@ public: // change the directory where Breakpad minidump files are written to void setMiniDumpDir(const std::string &path); + void setDebugFileNames(const std::string &path); // Return the Google Breakpad minidump filename after a crash. - char *getMiniDumpFilename() { return minidump_path; } + char *getMiniDumpFilename() { return mMinidumpPath; } + std::string* getStaticDebugFile() { return &mStaticDebugFileName; } + std::string* getDynamicDebugFile() { return &mDynamicDebugFileName; } // Write out a Google Breakpad minidump file. void writeMiniDump(); -#if !LL_WINDOWS - // - // Child process handling (Unix only for now) - // - // Set a callback to be run on exit of a child process - // WARNING! This callback is run from the signal handler due to - // Linux threading requiring waitpid() to be called from the thread that spawned the process. - // At some point I will make this more behaved, but I'm not going to fix this right now - djs - void setChildCallback(pid_t pid, LLAppChildCallback callback); - - // The child callback to run if no specific handler is set - void setDefaultChildCallback(LLAppChildCallback callback); - - // Fork and do the proper signal handling/error handling mojo - // *NOTE: You need to make sure your signal handling callback is - // correct after you fork, because not all threads are duplicated - // when you fork! - pid_t fork(); -#endif /** * @brief Get a reference to the application runner @@ -286,13 +256,9 @@ protected: static EAppStatus sStatus; // Reflects current application status static BOOL sErrorThreadRunning; // Set while the error thread is running static BOOL sDisableCrashlogger; // Let the OS handle crashes for us. + std::wstring mCrashReportPipeStr; //Name of pipe to use for crash reporting. -#if !LL_WINDOWS - static LLAtomicU32* sSigChildCount; // Number of SIGCHLDs received. - typedef std::map<pid_t, LLChildInfo> child_map; // Map key is a PID - static child_map sChildMap; - static LLAppChildCallback sDefaultChildCallback; -#endif + std::string mDumpPath; //output path for google breakpad. Dependency workaround. /** * @brief This method is called once a frame to do once a frame tasks. @@ -303,7 +269,10 @@ private: void startErrorThread(); // Contains the filename of the minidump file after a crash. - char minidump_path[MAX_MINDUMP_PATH_LENGTH]; + char mMinidumpPath[MAX_MINDUMP_PATH_LENGTH]; + + std::string mStaticDebugFileName; + std::string mDynamicDebugFileName; // *NOTE: On Windows, we need a routine to reset the structured // exception handler when some evil driver has taken it over for diff --git a/indra/llcommon/llapr.cpp b/indra/llcommon/llapr.cpp index b7815b0e35..a548c96002 100755 --- a/indra/llcommon/llapr.cpp +++ b/indra/llcommon/llapr.cpp @@ -29,6 +29,7 @@ #include "linden_common.h" #include "llapr.h" #include "apr_dso.h" +#include "llthreadlocalstorage.h" apr_pool_t *gAPRPoolp = NULL; // Global APR memory pool LLVolatileAPRPool *LLAPRFile::sAPRFilePoolp = NULL ; //global volatile APR memory pool. @@ -37,12 +38,15 @@ apr_thread_mutex_t *gCallStacksLogMutexp = NULL; const S32 FULL_VOLATILE_APR_POOL = 1024 ; //number of references to LLVolatileAPRPool +bool gAPRInitialized = false; + void ll_init_apr() { + // Initialize APR and create the global pool + apr_initialize(); + if (!gAPRPoolp) { - // Initialize APR and create the global pool - apr_initialize(); apr_pool_create(&gAPRPoolp, NULL); // Initialize the logging mutex @@ -54,11 +58,21 @@ void ll_init_apr() { LLAPRFile::sAPRFilePoolp = new LLVolatileAPRPool(FALSE) ; } + + LLThreadLocalPointerBase::initAllThreadLocalStorage(); + gAPRInitialized = true; } +bool ll_apr_is_initialized() +{ + return gAPRInitialized; +} + void ll_cleanup_apr() { + gAPRInitialized = false; + LL_INFOS("APR") << "Cleaning up APR" << LL_ENDL; if (gLogMutexp) @@ -77,6 +91,9 @@ void ll_cleanup_apr() apr_thread_mutex_destroy(gCallStacksLogMutexp); gCallStacksLogMutexp = NULL; } + + LLThreadLocalPointerBase::destroyAllThreadLocalStorage(); + if (gAPRPoolp) { apr_pool_destroy(gAPRPoolp); @@ -429,7 +446,7 @@ S32 LLAPRFile::read(void *buf, S32 nbytes) { if(!mFile) { - llwarns << "apr mFile is removed by somebody else. Can not read." << llendl ; + LL_WARNS() << "apr mFile is removed by somebody else. Can not read." << LL_ENDL ; return 0; } @@ -451,7 +468,7 @@ S32 LLAPRFile::write(const void *buf, S32 nbytes) { if(!mFile) { - llwarns << "apr mFile is removed by somebody else. Can not write." << llendl ; + LL_WARNS() << "apr mFile is removed by somebody else. Can not write." << LL_ENDL ; return 0; } diff --git a/indra/llcommon/llapr.h b/indra/llcommon/llapr.h index 1fe7d98472..b1b0fc4718 100755 --- a/indra/llcommon/llapr.h +++ b/indra/llcommon/llapr.h @@ -32,28 +32,34 @@ #if LL_LINUX || LL_SOLARIS #include <sys/param.h> // Need PATH_MAX in APR headers... #endif -#if LL_WINDOWS - // Limit Windows API to small and manageable set. - // If you get undefined symbols, find the appropriate - // Windows header file and include that in your .cpp file. - #define WIN32_LEAN_AND_MEAN - #include <winsock2.h> - #include <windows.h> -#endif #include <boost/noncopyable.hpp> - +#include "llwin32headerslean.h" #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; struct apr_dso_handle_t; +/** + * @brief Function which appropriately 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); +/// There's a whole other APR error-message function if you pass a DSO handle. +bool LL_COMMON_API ll_apr_warn_status(apr_status_t status, apr_dso_handle_t* handle); + +void LL_COMMON_API ll_apr_assert_status(apr_status_t status); +void LL_COMMON_API ll_apr_assert_status(apr_status_t status, apr_dso_handle_t* handle); + +extern "C" LL_COMMON_API apr_pool_t* gAPRPoolp; // Global APR memory pool /** * @brief initialize the common apr constructs -- apr itself, the @@ -66,6 +72,9 @@ void LL_COMMON_API ll_init_apr(); */ void LL_COMMON_API ll_cleanup_apr(); +bool LL_COMMON_API ll_apr_is_initialized(); + + // //LL apr_pool //manage apr_pool_t, destroy allocated apr_pool in the destruction function. @@ -263,18 +272,5 @@ public: //******************************************************************************************************************************* }; -/** - * @brief Function which appropriately 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); -/// There's a whole other APR error-message function if you pass a DSO handle. -bool LL_COMMON_API ll_apr_warn_status(apr_status_t status, apr_dso_handle_t* handle); - -void LL_COMMON_API ll_apr_assert_status(apr_status_t status); -void LL_COMMON_API ll_apr_assert_status(apr_status_t status, apr_dso_handle_t* handle); - -extern "C" LL_COMMON_API apr_pool_t* gAPRPoolp; // Global APR memory pool #endif // LL_LLAPR_H diff --git a/indra/llcommon/llassettype.h b/indra/llcommon/llassettype.h index 69b01731e5..5a95a58d93 100755 --- a/indra/llcommon/llassettype.h +++ b/indra/llcommon/llassettype.h @@ -29,8 +29,6 @@ #include <string> -#include "stdenums.h" // for EDragAndDropType - class LL_COMMON_API LLAssetType { public: diff --git a/indra/llcommon/llassoclist.h b/indra/llcommon/llassoclist.h deleted file mode 100755 index 2950504155..0000000000 --- a/indra/llcommon/llassoclist.h +++ /dev/null @@ -1,296 +0,0 @@ -/** - * @file llassoclist.h - * @brief LLAssocList class header file - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_LLASSOCLIST_H -#define LL_LLASSOCLIST_H - -//------------------------------------------------------------------------ -// LLAssocList is an associative list container class. -// -// The implementation is a single linked list. -// Both index and value objects are stored by value (not reference). -// If pointer values are specified for index and/or value, this -// container does NOT assume ownership of the referenced objects, -// and does NOT delete() them on removal or destruction of the container. -// -// Note that operations are generally not optimized, and may of them -// are O(n) complexity. -//------------------------------------------------------------------------ - -#include <iostream> - -template<class INDEX_TYPE, class VALUE_TYPE> -class LLAssocList -{ -private: - // internal list node type - class Node - { - public: - Node(const INDEX_TYPE &index, const VALUE_TYPE &value, Node *next) - { - mIndex = index; - mValue = value; - mNext = next; - } - ~Node() { } - INDEX_TYPE mIndex; - VALUE_TYPE mValue; - Node *mNext; - }; - - // head of the linked list - Node *mHead; - -public: - // Constructor - LLAssocList() - { - mHead = NULL; - } - - // Destructor - ~LLAssocList() - { - removeAll(); - } - - // Returns TRUE if list is empty. - BOOL isEmpty() - { - return (mHead == NULL); - } - - // Returns the number of items in the list. - U32 length() - { - U32 count = 0; - for ( Node *node = mHead; - node; - node = node->mNext ) - { - count++; - } - return count; - } - - // Removes item with the specified index. - BOOL remove( const INDEX_TYPE &index ) - { - if (!mHead) - return FALSE; - - if (mHead->mIndex == index) - { - Node *node = mHead; - mHead = mHead->mNext; - delete node; - return TRUE; - } - - for ( Node *prev = mHead; - prev->mNext; - prev = prev->mNext ) - { - if (prev->mNext->mIndex == index) - { - Node *node = prev->mNext; - prev->mNext = prev->mNext->mNext; - delete node; - return TRUE; - } - } - return FALSE; - } - - // Removes all items from the list. - void removeAll() - { - while ( mHead ) - { - Node *node = mHead; - mHead = mHead->mNext; - delete node; - } - } - - // Adds a new item to the head of the list, - // removing any existing item with same index. - void addToHead( const INDEX_TYPE &index, const VALUE_TYPE &value ) - { - remove(index); - Node *node = new Node(index, value, mHead); - mHead = node; - } - - // Adds a new item to the end of the list, - // removing any existing item with the same index. - void addToTail( const INDEX_TYPE &index, const VALUE_TYPE &value ) - { - remove(index); - Node *node = new Node(index, value, NULL); - if (!mHead) - { - mHead = node; - return; - } - for ( Node *prev=mHead; - prev; - prev=prev->mNext ) - { - if (!prev->mNext) - { - prev->mNext=node; - return; - } - } - } - - // Sets the value of a specified index. - // If index does not exist, a new value will be added only if - // 'addIfNotFound' is set to TRUE. - // Returns TRUE if successful. - BOOL setValue( const INDEX_TYPE &index, const VALUE_TYPE &value, BOOL addIfNotFound=FALSE ) - { - VALUE_TYPE *valueP = getValue(index); - if (valueP) - { - *valueP = value; - return TRUE; - } - if (!addIfNotFound) - return FALSE; - addToTail(index, value); - return TRUE; - } - - // Sets the ith value in the list. - // A new value will NOT be addded, if the ith value does not exist. - // Returns TRUE if successful. - BOOL setValueAt( U32 i, const VALUE_TYPE &value ) - { - VALUE_TYPE *valueP = getValueAt(i); - if (valueP) - { - *valueP = value; - return TRUE; - } - return FALSE; - } - - // Returns a pointer to the value for the specified index, - // or NULL if no item found. - VALUE_TYPE *getValue( const INDEX_TYPE &index ) - { - for ( Node *node = mHead; - node; - node = node->mNext ) - { - if (node->mIndex == index) - return &node->mValue; - } - return NULL; - } - - // Returns a pointer to the ith value in the list, or - // NULL if i is not valid. - VALUE_TYPE *getValueAt( U32 i ) - { - U32 count = 0; - for ( Node *node = mHead; - node; - node = node->mNext ) - { - if (count == i) - return &node->mValue; - count++; - } - return NULL; - } - - // Returns a pointer to the index for the specified index, - // or NULL if no item found. - INDEX_TYPE *getIndex( const INDEX_TYPE &index ) - { - for ( Node *node = mHead; - node; - node = node->mNext ) - { - if (node->mIndex == index) - return &node->mIndex; - } - return NULL; - } - - // Returns a pointer to the ith index in the list, or - // NULL if i is not valid. - INDEX_TYPE *getIndexAt( U32 i ) - { - U32 count = 0; - for ( Node *node = mHead; - node; - node = node->mNext ) - { - if (count == i) - return &node->mIndex; - count++; - } - return NULL; - } - - // Returns a pointer to the value for the specified index, - // or NULL if no item found. - VALUE_TYPE *operator[](const INDEX_TYPE &index) - { - return getValue(index); - } - - // Returns a pointer to the ith value in the list, or - // NULL if i is not valid. - VALUE_TYPE *operator[](U32 i) - { - return getValueAt(i); - } - - // Prints the list contents to the specified stream. - friend std::ostream &operator<<( std::ostream &os, LLAssocList &map ) - { - os << "{"; - for ( Node *node = map.mHead; - node; - node = node->mNext ) - { - os << "<" << node->mIndex << ", " << node->mValue << ">"; - if (node->mNext) - os << ", "; - } - os << "}"; - - return os; - } -}; - -#endif // LL_LLASSOCLIST_H diff --git a/indra/llcommon/llavatarconstants.h b/indra/llcommon/llavatarconstants.h deleted file mode 100755 index f47f447b45..0000000000 --- a/indra/llcommon/llavatarconstants.h +++ /dev/null @@ -1,55 +0,0 @@ -/** - * @file llavatarconstants.h - * @brief some useful short term constants for Indra - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_AVATAR_CONSTANTS_H -#define LL_AVATAR_CONSTANTS_H - -// If this string is passed to dataserver in AvatarPropertiesUpdate -// then no change is made to user.profile_web -const char* const BLACKLIST_PROFILE_WEB_STR = "featureWebProfilesDisabled"; - -// If profile web pages are feature blacklisted then this URL is -// shown in the profile instead of the user's set URL -const char* const BLACKLIST_PROFILE_WEB_URL = "http://secondlife.com/app/webdisabled"; - -// Maximum number of avatar picks -const S32 MAX_AVATAR_PICKS = 10; - -// For Flags in AvatarPropertiesReply -const U32 AVATAR_ALLOW_PUBLISH = 0x1 << 0; // whether profile is externally visible or not -const U32 AVATAR_MATURE_PUBLISH = 0x1 << 1; // profile is "mature" -const U32 AVATAR_IDENTIFIED = 0x1 << 2; // whether avatar has provided payment info -const U32 AVATAR_TRANSACTED = 0x1 << 3; // whether avatar has actively used payment info -const U32 AVATAR_ONLINE = 0x1 << 4; // the online status of this avatar, if known. -const U32 AVATAR_AGEVERIFIED = 0x1 << 5; // whether avatar has been age-verified - -char const* const VISIBILITY_DEFAULT = "default"; -char const* const VISIBILITY_HIDDEN = "hidden"; -char const* const VISIBILITY_VISIBLE = "visible"; -char const* const VISIBILITY_INVISIBLE = "invisible"; - -#endif - diff --git a/indra/llcommon/llavatarname.cpp b/indra/llcommon/llavatarname.cpp deleted file mode 100755 index d12f157910..0000000000 --- a/indra/llcommon/llavatarname.cpp +++ /dev/null @@ -1,254 +0,0 @@ -/** - * @file llavatarname.cpp - * @brief Represents name-related data for an avatar, such as the - * username/SLID ("bobsmith123" or "james.linden") and the display - * name ("James Cook") - * - * $LicenseInfo:firstyear=2010&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ -#include "linden_common.h" - -#include "llavatarname.h" - -#include "lldate.h" -#include "llframetimer.h" -#include "llsd.h" - -// Store these in pre-built std::strings to avoid memory allocations in -// LLSD map lookups -static const std::string USERNAME("username"); -static const std::string DISPLAY_NAME("display_name"); -static const std::string LEGACY_FIRST_NAME("legacy_first_name"); -static const std::string LEGACY_LAST_NAME("legacy_last_name"); -static const std::string IS_DISPLAY_NAME_DEFAULT("is_display_name_default"); -static const std::string DISPLAY_NAME_EXPIRES("display_name_expires"); -static const std::string DISPLAY_NAME_NEXT_UPDATE("display_name_next_update"); - -bool LLAvatarName::sUseDisplayNames = true; -bool LLAvatarName::sUseUsernames = true; - -// Minimum time-to-live (in seconds) for a name entry. -// Avatar name should always guarantee to expire reasonably soon by default -// so if the failure to get a valid expiration time was due to something temporary -// we will eventually request and get the right data. -const F64 MIN_ENTRY_LIFETIME = 60.0; - -LLAvatarName::LLAvatarName() -: mUsername(), - mDisplayName(), - mLegacyFirstName(), - mLegacyLastName(), - mIsDisplayNameDefault(false), - mIsTemporaryName(false), - mExpires(F64_MAX), - mNextUpdate(0.0) -{ } - -bool LLAvatarName::operator<(const LLAvatarName& rhs) const -{ - if (mUsername == rhs.mUsername) - return mDisplayName < rhs.mDisplayName; - else - return mUsername < rhs.mUsername; -} - -//static -void LLAvatarName::setUseDisplayNames(bool use) -{ - sUseDisplayNames = use; -} -//static -bool LLAvatarName::useDisplayNames() -{ - return sUseDisplayNames; -} - -void LLAvatarName::setUseUsernames(bool use) -{ - sUseUsernames = use; -} - -bool LLAvatarName::useUsernames() -{ - return sUseUsernames; -} - -LLSD LLAvatarName::asLLSD() const -{ - LLSD sd; - sd[USERNAME] = mUsername; - sd[DISPLAY_NAME] = mDisplayName; - sd[LEGACY_FIRST_NAME] = mLegacyFirstName; - sd[LEGACY_LAST_NAME] = mLegacyLastName; - sd[IS_DISPLAY_NAME_DEFAULT] = mIsDisplayNameDefault; - sd[DISPLAY_NAME_EXPIRES] = LLDate(mExpires); - sd[DISPLAY_NAME_NEXT_UPDATE] = LLDate(mNextUpdate); - return sd; -} - -void LLAvatarName::fromLLSD(const LLSD& sd) -{ - mUsername = sd[USERNAME].asString(); - mDisplayName = sd[DISPLAY_NAME].asString(); - mLegacyFirstName = sd[LEGACY_FIRST_NAME].asString(); - mLegacyLastName = sd[LEGACY_LAST_NAME].asString(); - mIsDisplayNameDefault = sd[IS_DISPLAY_NAME_DEFAULT].asBoolean(); - LLDate expires = sd[DISPLAY_NAME_EXPIRES]; - mExpires = expires.secondsSinceEpoch(); - LLDate next_update = sd[DISPLAY_NAME_NEXT_UPDATE]; - mNextUpdate = next_update.secondsSinceEpoch(); - - // Some avatars don't have explicit display names set. Force a legible display name here. - if (mDisplayName.empty()) - { - mDisplayName = mUsername; - } -} - -// Transform a string (typically provided by the legacy service) into a decent -// avatar name instance. -void LLAvatarName::fromString(const std::string& full_name) -{ - mDisplayName = full_name; - std::string::size_type index = full_name.find(' '); - if (index != std::string::npos) - { - // The name is in 2 parts (first last) - mLegacyFirstName = full_name.substr(0, index); - mLegacyLastName = full_name.substr(index+1); - if (mLegacyLastName != "Resident") - { - mUsername = mLegacyFirstName + "." + mLegacyLastName; - mDisplayName = full_name; - LLStringUtil::toLower(mUsername); - } - else - { - // Very old names do have a dummy "Resident" last name - // that we choose to hide from users. - mUsername = mLegacyFirstName; - mDisplayName = mLegacyFirstName; - } - } - else - { - mLegacyFirstName = full_name; - mLegacyLastName = ""; - mUsername = full_name; - mDisplayName = full_name; - } - mIsDisplayNameDefault = true; - mIsTemporaryName = true; - setExpires(MIN_ENTRY_LIFETIME); -} - -void LLAvatarName::setExpires(F64 expires) -{ - mExpires = LLFrameTimer::getTotalSeconds() + expires; -} - -std::string LLAvatarName::getCompleteName() const -{ - std::string name; - if (sUseDisplayNames) - { - if (mUsername.empty() || mIsDisplayNameDefault) - { - // If this particular display name is defaulted (i.e. based on user name), - // then display only the easier to read instance of the person's name. - name = mDisplayName; - } - else - { - name = mDisplayName; - if(sUseUsernames) - { - name += " (" + mUsername + ")"; - } - } - } - else - { - name = getUserName(); - } - return name; -} - -std::string LLAvatarName::getLegacyName() const -{ - if (mLegacyFirstName.empty() && mLegacyLastName.empty()) // display names disabled? - { - return mDisplayName; - } - - std::string name; - name.reserve( mLegacyFirstName.size() + 1 + mLegacyLastName.size() ); - name = mLegacyFirstName; - name += " "; - name += mLegacyLastName; - return name; -} - -std::string LLAvatarName::getDisplayName() const -{ - if (sUseDisplayNames) - { - return mDisplayName; - } - else - { - return getUserName(); - } -} - -std::string LLAvatarName::getUserName() const -{ - std::string name; - if (mLegacyLastName.empty() || (mLegacyLastName == "Resident")) - { - if (mLegacyFirstName.empty()) - { - // If we cannot create a user name from the legacy strings, use the display name - name = mDisplayName; - } - else - { - // The last name might be empty if it defaulted to "Resident" - name = mLegacyFirstName; - } - } - else - { - name = mLegacyFirstName + " " + mLegacyLastName; - } - return name; -} - -void LLAvatarName::dump() const -{ - LL_DEBUGS("AvNameCache") << "LLAvatarName: " - << "user '" << mUsername << "' " - << "display '" << mDisplayName << "' " - << "expires in " << mExpires - LLFrameTimer::getTotalSeconds() << " seconds" - << LL_ENDL; -} - diff --git a/indra/llcommon/llavatarname.h b/indra/llcommon/llavatarname.h deleted file mode 100755 index 1cb3ae421f..0000000000 --- a/indra/llcommon/llavatarname.h +++ /dev/null @@ -1,139 +0,0 @@ -/** - * @file llavatarname.h - * @brief Represents name-related data for an avatar, such as the - * username/SLID ("bobsmith123" or "james.linden") and the display - * name ("James Cook") - * - * $LicenseInfo:firstyear=2010&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ -#ifndef LLAVATARNAME_H -#define LLAVATARNAME_H - -#include <string> - -class LLSD; - -class LL_COMMON_API LLAvatarName -{ -public: - LLAvatarName(); - - bool operator<(const LLAvatarName& rhs) const; - - // Conversion to and from LLSD (cache file or server response) - LLSD asLLSD() const; - void fromLLSD(const LLSD& sd); - - // Used only in legacy mode when the display name capability is not provided server side - // or to otherwise create a temporary valid item. - void fromString(const std::string& full_name); - - // Set the name object to become invalid in "expires" seconds from now - void setExpires(F64 expires); - - // Set and get the display name flag set by the user in preferences. - static void setUseDisplayNames(bool use); - static bool useDisplayNames(); - - static void setUseUsernames(bool use); - static bool useUsernames(); - - // A name object is valid if not temporary and not yet expired (default is expiration not checked) - bool isValidName(F64 max_unrefreshed = 0.0f) const { return !mIsTemporaryName && (mExpires >= max_unrefreshed); } - - // Return true if the name is made up from legacy or temporary data - bool isDisplayNameDefault() const { return mIsDisplayNameDefault; } - - // For normal names, returns "James Linden (james.linden)" - // When display names are disabled returns just "James Linden" - std::string getCompleteName() const; - - // Returns "James Linden" or "bobsmith123 Resident" for backwards - // compatibility with systems like voice and muting - // *TODO: Eliminate this in favor of username only - std::string getLegacyName() const; - - // "José Sanchez" or "James Linden", UTF-8 encoded Unicode - // Takes the display name preference into account. This is truly the name that should - // be used for all UI where an avatar name has to be used unless we truly want something else (rare) - std::string getDisplayName() const; - - // Returns "James Linden" or "bobsmith123 Resident" - // Used where we explicitely prefer or need a non UTF-8 legacy (ASCII) name - // Also used for backwards compatibility with systems like voice and muting - std::string getUserName() const; - - // Returns "james.linden" or the legacy name for very old names - std::string getAccountName() const { return mUsername; } - - // Debug print of the object - void dump() const; - - // Names can change, so need to keep track of when name was - // last checked. - // Unix time-from-epoch seconds for efficiency - F64 mExpires; - - // You can only change your name every N hours, so record - // when the next update is allowed - // Unix time-from-epoch seconds - F64 mNextUpdate; - -private: - // "bobsmith123" or "james.linden", US-ASCII only - std::string mUsername; - - // "José Sanchez" or "James Linden", UTF-8 encoded Unicode - // Contains data whether or not user has explicitly set - // a display name; may duplicate their username. - std::string mDisplayName; - - // For "James Linden", "James" - // For "bobsmith123", "bobsmith123" - // Used to communicate with legacy systems like voice and muting which - // rely on old-style names. - // *TODO: Eliminate this in favor of username only - std::string mLegacyFirstName; - - // For "James Linden", "Linden" - // For "bobsmith123", "Resident" - // see above for rationale - std::string mLegacyLastName; - - // If true, both display name and SLID were generated from - // a legacy first and last name, like "James Linden (james.linden)" - bool mIsDisplayNameDefault; - - // Under error conditions, we may insert "dummy" records with - // names like "???" into caches as placeholders. These can be - // shown in UI, but are not serialized. - bool mIsTemporaryName; - - // Global flag indicating if display name should be used or not - // This will affect the output of the high level "get" methods - static bool sUseDisplayNames; - - // Flag indicating if username should be shown after display name or not - static bool sUseUsernames; -}; - -#endif diff --git a/indra/llcommon/llbase32.cpp b/indra/llcommon/llbase32.cpp index 053ac0d32f..349567c90b 100755 --- a/indra/llcommon/llbase32.cpp +++ b/indra/llcommon/llbase32.cpp @@ -231,8 +231,8 @@ std::string LLBase32::encode(const U8* input, size_t input_size) size_t encoded = base32_encode(&output[0], output_size, input, input_size); - llinfos << "encoded " << encoded << " into buffer of size " - << output_size << llendl; + LL_INFOS() << "encoded " << encoded << " into buffer of size " + << output_size << LL_ENDL; } return output; } diff --git a/indra/llcommon/bitpack.cpp b/indra/llcommon/llbitpack.cpp index cdcaba0765..622a099945 100755 --- a/indra/llcommon/bitpack.cpp +++ b/indra/llcommon/llbitpack.cpp @@ -27,4 +27,4 @@ #include "linden_common.h" // implementation is all in the header, this include dep ensures the unit test is rerun if the implementation changes. -#include "bitpack.h" +#include "llbitpack.h" diff --git a/indra/llcommon/bitpack.h b/indra/llcommon/llbitpack.h index 037300dd14..f99a354cd4 100755 --- a/indra/llcommon/bitpack.h +++ b/indra/llcommon/llbitpack.h @@ -1,5 +1,5 @@ /** - * @file bitpack.h + * @file llbitpack.h * @brief Convert data to packed bit stream * * $LicenseInfo:firstyear=2000&license=viewerlgpl$ @@ -79,7 +79,7 @@ public: *(mBuffer + mBufferSize++) = mLoad; if (mBufferSize > mMaxSize) { - llerror("mBufferSize exceeding mMaxSize!", 0); + LL_ERRS() << "mBufferSize exceeding mMaxSize!" << LL_ENDL; } mLoadSize = 0; mLoad = 0x00; @@ -122,7 +122,7 @@ public: *(mBuffer + mBufferSize++) = mLoad; if (mBufferSize > mMaxSize) { - llerror("mBufferSize exceeding mMaxSize!", 0); + LL_ERRS() << "mBufferSize exceeding mMaxSize!" << LL_ENDL; } mLoadSize = 0; mLoad = 0x00; @@ -165,8 +165,8 @@ public: #ifdef _DEBUG if (mBufferSize > mMaxSize) { - llerrs << "mBufferSize exceeding mMaxSize" << llendl; - llerrs << mBufferSize << " > " << mMaxSize << llendl; + LL_ERRS() << "mBufferSize exceeding mMaxSize" << LL_ENDL; + LL_ERRS() << mBufferSize << " > " << mMaxSize << LL_ENDL; } #endif mLoad = *(mBuffer + mBufferSize++); @@ -190,7 +190,7 @@ public: *(mBuffer + mBufferSize++) = mLoad; if (mBufferSize > mMaxSize) { - llerror("mBufferSize exceeding mMaxSize!", 0); + LL_ERRS() << "mBufferSize exceeding mMaxSize!" << LL_ENDL; } mLoadSize = 0; } diff --git a/indra/llcommon/llchat.h b/indra/llcommon/llchat.h deleted file mode 100755 index f5b242fdfc..0000000000 --- a/indra/llcommon/llchat.h +++ /dev/null @@ -1,109 +0,0 @@ -/** - * @file llchat.h - * @author James Cook - * @brief Chat constants and data structures. - * - * $LicenseInfo:firstyear=2006&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_LLCHAT_H -#define LL_LLCHAT_H - -#include "lluuid.h" -#include "v3math.h" - -// enumerations used by the chat system -typedef enum e_chat_source_type -{ - CHAT_SOURCE_SYSTEM = 0, - CHAT_SOURCE_AGENT = 1, - CHAT_SOURCE_OBJECT = 2, - CHAT_SOURCE_UNKNOWN = 3 -} EChatSourceType; - -typedef enum e_chat_type -{ - CHAT_TYPE_WHISPER = 0, - CHAT_TYPE_NORMAL = 1, - CHAT_TYPE_SHOUT = 2, - CHAT_TYPE_START = 4, - CHAT_TYPE_STOP = 5, - CHAT_TYPE_DEBUG_MSG = 6, - CHAT_TYPE_REGION = 7, - CHAT_TYPE_OWNER = 8, - CHAT_TYPE_DIRECT = 9 // From llRegionSayTo() -} EChatType; - -typedef enum e_chat_audible_level -{ - CHAT_AUDIBLE_NOT = -1, - CHAT_AUDIBLE_BARELY = 0, - CHAT_AUDIBLE_FULLY = 1 -} EChatAudible; - -typedef enum e_chat_style -{ - CHAT_STYLE_NORMAL, - CHAT_STYLE_IRC, - CHAT_STYLE_HISTORY -}EChatStyle; - -// A piece of chat -class LLChat -{ -public: - LLChat(const std::string& text = std::string()) - : mText(text), - mFromName(), - mFromID(), - mNotifId(), - mOwnerID(), - mSourceType(CHAT_SOURCE_AGENT), - mChatType(CHAT_TYPE_NORMAL), - mAudible(CHAT_AUDIBLE_FULLY), - mMuted(FALSE), - mTime(0.0), - mTimeStr(), - mPosAgent(), - mURL(), - mChatStyle(CHAT_STYLE_NORMAL), - mSessionID() - { } - - std::string mText; // UTF-8 line of text - std::string mFromName; // agent or object name - LLUUID mFromID; // agent id or object id - LLUUID mNotifId; - LLUUID mOwnerID; - EChatSourceType mSourceType; - EChatType mChatType; - EChatAudible mAudible; - BOOL mMuted; // pass muted chat to maintain list of chatters - F64 mTime; // viewer only, seconds from viewer start - std::string mTimeStr; - LLVector3 mPosAgent; - std::string mURL; - EChatStyle mChatStyle; - LLUUID mSessionID; -}; - -#endif diff --git a/indra/llcommon/llclickaction.h b/indra/llcommon/llclickaction.h index 1f87d8eec3..2f83113af9 100755..100644 --- a/indra/llcommon/llclickaction.h +++ b/indra/llcommon/llclickaction.h @@ -27,15 +27,4 @@ #ifndef LL_LLCLICKACTION_H #define LL_LLCLICKACTION_H -// DO NOT CHANGE THE SEQUENCE OF THIS LIST!! -const U8 CLICK_ACTION_NONE = 0; -const U8 CLICK_ACTION_TOUCH = 0; -const U8 CLICK_ACTION_SIT = 1; -const U8 CLICK_ACTION_BUY = 2; -const U8 CLICK_ACTION_PAY = 3; -const U8 CLICK_ACTION_OPEN = 4; -const U8 CLICK_ACTION_PLAY = 5; -const U8 CLICK_ACTION_OPEN_MEDIA = 6; -const U8 CLICK_ACTION_ZOOM = 7; -// DO NOT CHANGE THE SEQUENCE OF THIS LIST!! #endif diff --git a/indra/llcommon/llcommon.cpp b/indra/llcommon/llcommon.cpp index b938b0e65a..19642b0982 100755 --- a/indra/llcommon/llcommon.cpp +++ b/indra/llcommon/llcommon.cpp @@ -29,10 +29,14 @@ #include "llmemory.h" #include "llthread.h" +#include "lltrace.h" +#include "lltracethreadrecorder.h" //static BOOL LLCommon::sAprInitialized = FALSE; +static LLTrace::ThreadRecorder* sMasterThreadRecorder = NULL; + //static void LLCommon::initClass() { @@ -45,15 +49,19 @@ void LLCommon::initClass() LLTimer::initClass(); LLThreadSafeRefCount::initThreadSafeRefCount(); assert_main_thread(); // Make sure we record the main thread -// LLWorkerThread::initClass(); -// LLFrameCallbackManager::initClass(); + if (!sMasterThreadRecorder) + { + sMasterThreadRecorder = new LLTrace::ThreadRecorder(); + LLTrace::set_master_thread_recorder(sMasterThreadRecorder); + } } //static void LLCommon::cleanupClass() { -// LLFrameCallbackManager::cleanupClass(); -// LLWorkerThread::cleanupClass(); + delete sMasterThreadRecorder; + sMasterThreadRecorder = NULL; + LLTrace::set_master_thread_recorder(NULL); LLThreadSafeRefCount::cleanupThreadSafeRefCount(); LLTimer::cleanupClass(); if (sAprInitialized) diff --git a/indra/llcommon/llcommonutils.h b/indra/llcommon/llcommonutils.h index 755dc41fb4..20ada27830 100755 --- a/indra/llcommon/llcommonutils.h +++ b/indra/llcommon/llcommonutils.h @@ -27,6 +27,8 @@ #ifndef LL_LLCOMMONUTILS_H #define LL_LLCOMMONUTILS_H +#include "lluuid.h" + namespace LLCommonUtils { /** diff --git a/indra/llcommon/llcrc.cpp b/indra/llcommon/llcrc.cpp index e80da0bb0d..626bb1e564 100755 --- a/indra/llcommon/llcrc.cpp +++ b/indra/llcommon/llcrc.cpp @@ -162,7 +162,7 @@ void LLCRC::update(const std::string& filename) { if (filename.empty()) { - llerrs << "No filename specified" << llendl; + LL_ERRS() << "No filename specified" << LL_ENDL; return; } @@ -185,7 +185,7 @@ void LLCRC::update(const std::string& filename) if (nread < (size_t) size) { - llwarns << "Short read on " << filename << llendl; + LL_WARNS() << "Short read on " << filename << LL_ENDL; } update(data, nread); diff --git a/indra/llcommon/llcrc.h b/indra/llcommon/llcrc.h index 2d291d92a1..3f41b28ffa 100755 --- a/indra/llcommon/llcrc.h +++ b/indra/llcommon/llcrc.h @@ -41,7 +41,7 @@ // crc.update(fgetc(fp)); // } // fclose(fp); -// llinfos << "File crc: " << crc.getCRC() << llendl; +// LL_INFOS() << "File crc: " << crc.getCRC() << LL_ENDL; //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ class LL_COMMON_API LLCRC diff --git a/indra/llcommon/llcriticaldamp.cpp b/indra/llcommon/llcriticaldamp.cpp index 49aac9ce75..54be855f67 100755 --- a/indra/llcommon/llcriticaldamp.cpp +++ b/indra/llcommon/llcriticaldamp.cpp @@ -27,18 +27,38 @@ #include "linden_common.h" #include "llcriticaldamp.h" +#include <algorithm> //----------------------------------------------------------------------------- // static members //----------------------------------------------------------------------------- -LLFrameTimer LLCriticalDamp::sInternalTimer; -std::map<F32, F32> LLCriticalDamp::sInterpolants; -F32 LLCriticalDamp::sTimeDelta; +LLFrameTimer LLSmoothInterpolation::sInternalTimer; +std::vector<LLSmoothInterpolation::Interpolant> LLSmoothInterpolation::sInterpolants; +F32 LLSmoothInterpolation::sTimeDelta; + +// helper functors +struct LLSmoothInterpolation::CompareTimeConstants +{ + bool operator()(const F32& a, const LLSmoothInterpolation::Interpolant& b) const + { + return a < b.mTimeScale; + } + + bool operator()(const LLSmoothInterpolation::Interpolant& a, const F32& b) const + { + return a.mTimeScale < b; // bottom of a is higher than bottom of b + } + + bool operator()(const LLSmoothInterpolation::Interpolant& a, const LLSmoothInterpolation::Interpolant& b) const + { + return a.mTimeScale < b.mTimeScale; // bottom of a is higher than bottom of b + } +}; //----------------------------------------------------------------------------- -// LLCriticalDamp() +// LLSmoothInterpolation() //----------------------------------------------------------------------------- -LLCriticalDamp::LLCriticalDamp() +LLSmoothInterpolation::LLSmoothInterpolation() { sTimeDelta = 0.f; } @@ -47,44 +67,55 @@ LLCriticalDamp::LLCriticalDamp() //----------------------------------------------------------------------------- // updateInterpolants() //----------------------------------------------------------------------------- -void LLCriticalDamp::updateInterpolants() +void LLSmoothInterpolation::updateInterpolants() { sTimeDelta = sInternalTimer.getElapsedTimeAndResetF32(); - F32 time_constant; - - for (std::map<F32, F32>::iterator iter = sInterpolants.begin(); - iter != sInterpolants.end(); iter++) + for (S32 i = 0; i < sInterpolants.size(); i++) { - time_constant = iter->first; - F32 new_interpolant = 1.f - pow(2.f, -sTimeDelta / time_constant); - new_interpolant = llclamp(new_interpolant, 0.f, 1.f); - sInterpolants[time_constant] = new_interpolant; + Interpolant& interp = sInterpolants[i]; + interp.mInterpolant = calcInterpolant(interp.mTimeScale); } } //----------------------------------------------------------------------------- // getInterpolant() //----------------------------------------------------------------------------- -F32 LLCriticalDamp::getInterpolant(const F32 time_constant, BOOL use_cache) +F32 LLSmoothInterpolation::getInterpolant(F32SecondsImplicit time_constant, bool use_cache) { if (time_constant == 0.f) { return 1.f; } - if (use_cache && sInterpolants.count(time_constant)) + if (use_cache) { - return sInterpolants[time_constant]; + interpolant_vec_t::iterator find_it = std::lower_bound(sInterpolants.begin(), sInterpolants.end(), time_constant.value(), CompareTimeConstants()); + if (find_it != sInterpolants.end() && find_it->mTimeScale == time_constant) + { + return find_it->mInterpolant; + } + else + { + Interpolant interp; + interp.mTimeScale = time_constant.value(); + interp.mInterpolant = calcInterpolant(time_constant.value()); + sInterpolants.insert(find_it, interp); + return interp.mInterpolant; + } } - - F32 interpolant = 1.f - pow(2.f, -sTimeDelta / time_constant); - interpolant = llclamp(interpolant, 0.f, 1.f); - if (use_cache) + else { - sInterpolants[time_constant] = interpolant; + return calcInterpolant(time_constant.value()); + } +} - return interpolant; +//----------------------------------------------------------------------------- +// calcInterpolant() +//----------------------------------------------------------------------------- +F32 LLSmoothInterpolation::calcInterpolant(F32 time_constant) +{ + return llclamp(1.f - powf(2.f, -sTimeDelta / time_constant), 0.f, 1.f); } diff --git a/indra/llcommon/llcriticaldamp.h b/indra/llcommon/llcriticaldamp.h index 52f052ae25..1fb6a1af29 100755 --- a/indra/llcommon/llcriticaldamp.h +++ b/indra/llcommon/llcriticaldamp.h @@ -28,26 +28,46 @@ #ifndef LL_LLCRITICALDAMP_H #define LL_LLCRITICALDAMP_H -#include <map> +#include <vector> #include "llframetimer.h" +#include "llunits.h" -class LL_COMMON_API LLCriticalDamp +class LL_COMMON_API LLSmoothInterpolation { public: - LLCriticalDamp(); + LLSmoothInterpolation(); // MANIPULATORS static void updateInterpolants(); // ACCESSORS - static F32 getInterpolant(const F32 time_constant, BOOL use_cache = TRUE); + static F32 getInterpolant(F32SecondsImplicit time_constant, bool use_cache = true); -protected: + template<typename T> + static T lerp(T a, T b, F32SecondsImplicit time_constant, bool use_cache = true) + { + F32 interpolant = getInterpolant(time_constant, use_cache); + return ((a * (1.f - interpolant)) + + (b * interpolant)); + } + +protected: + static F32 calcInterpolant(F32 time_constant); + + struct CompareTimeConstants; static LLFrameTimer sInternalTimer; // frame timer for calculating deltas - static std::map<F32, F32> sInterpolants; + struct Interpolant + { + F32 mTimeScale; + F32 mInterpolant; + }; + typedef std::vector<Interpolant> interpolant_vec_t; + static interpolant_vec_t sInterpolants; static F32 sTimeDelta; }; +typedef LLSmoothInterpolation LLCriticalDamp; + #endif // LL_LLCRITICALDAMP_H diff --git a/indra/llcommon/llcursortypes.cpp b/indra/llcommon/llcursortypes.cpp deleted file mode 100755 index ec60097195..0000000000 --- a/indra/llcommon/llcursortypes.cpp +++ /dev/null @@ -1,91 +0,0 @@ -/** - * @file llcursortypes.cpp - * @brief Cursor types and lookup of types from a string - * - * $LicenseInfo:firstyear=2008&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" - -#include "llcursortypes.h" - -ECursorType getCursorFromString(const std::string& cursor_string) -{ - static std::map<std::string,U32> cursor_string_table; - if (cursor_string_table.empty()) - { - cursor_string_table["UI_CURSOR_ARROW"] = UI_CURSOR_ARROW; - cursor_string_table["UI_CURSOR_WAIT"] = UI_CURSOR_WAIT; - cursor_string_table["UI_CURSOR_HAND"] = UI_CURSOR_HAND; - cursor_string_table["UI_CURSOR_IBEAM"] = UI_CURSOR_IBEAM; - cursor_string_table["UI_CURSOR_CROSS"] = UI_CURSOR_CROSS; - cursor_string_table["UI_CURSOR_SIZENWSE"] = UI_CURSOR_SIZENWSE; - cursor_string_table["UI_CURSOR_SIZENESW"] = UI_CURSOR_SIZENESW; - cursor_string_table["UI_CURSOR_SIZEWE"] = UI_CURSOR_SIZEWE; - cursor_string_table["UI_CURSOR_SIZENS"] = UI_CURSOR_SIZENS; - cursor_string_table["UI_CURSOR_NO"] = UI_CURSOR_NO; - cursor_string_table["UI_CURSOR_WORKING"] = UI_CURSOR_WORKING; - cursor_string_table["UI_CURSOR_TOOLGRAB"] = UI_CURSOR_TOOLGRAB; - cursor_string_table["UI_CURSOR_TOOLLAND"] = UI_CURSOR_TOOLLAND; - cursor_string_table["UI_CURSOR_TOOLFOCUS"] = UI_CURSOR_TOOLFOCUS; - cursor_string_table["UI_CURSOR_TOOLCREATE"] = UI_CURSOR_TOOLCREATE; - cursor_string_table["UI_CURSOR_ARROWDRAG"] = UI_CURSOR_ARROWDRAG; - cursor_string_table["UI_CURSOR_ARROWCOPY"] = UI_CURSOR_ARROWCOPY; - cursor_string_table["UI_CURSOR_ARROWDRAGMULTI"] = UI_CURSOR_ARROWDRAGMULTI; - cursor_string_table["UI_CURSOR_ARROWCOPYMULTI"] = UI_CURSOR_ARROWCOPYMULTI; - cursor_string_table["UI_CURSOR_NOLOCKED"] = UI_CURSOR_NOLOCKED; - cursor_string_table["UI_CURSOR_ARROWLOCKED"] = UI_CURSOR_ARROWLOCKED; - cursor_string_table["UI_CURSOR_GRABLOCKED"] = UI_CURSOR_GRABLOCKED; - cursor_string_table["UI_CURSOR_TOOLTRANSLATE"] = UI_CURSOR_TOOLTRANSLATE; - cursor_string_table["UI_CURSOR_TOOLROTATE"] = UI_CURSOR_TOOLROTATE; - cursor_string_table["UI_CURSOR_TOOLSCALE"] = UI_CURSOR_TOOLSCALE; - cursor_string_table["UI_CURSOR_TOOLCAMERA"] = UI_CURSOR_TOOLCAMERA; - cursor_string_table["UI_CURSOR_TOOLPAN"] = UI_CURSOR_TOOLPAN; - cursor_string_table["UI_CURSOR_TOOLZOOMIN"] = UI_CURSOR_TOOLZOOMIN; - cursor_string_table["UI_CURSOR_TOOLPICKOBJECT3"] = UI_CURSOR_TOOLPICKOBJECT3; - cursor_string_table["UI_CURSOR_TOOLPLAY"] = UI_CURSOR_TOOLPLAY; - cursor_string_table["UI_CURSOR_TOOLPAUSE"] = UI_CURSOR_TOOLPAUSE; - cursor_string_table["UI_CURSOR_TOOLMEDIAOPEN"] = UI_CURSOR_TOOLMEDIAOPEN; - cursor_string_table["UI_CURSOR_PIPETTE"] = UI_CURSOR_PIPETTE; - cursor_string_table["UI_CURSOR_TOOLSIT"] = UI_CURSOR_TOOLSIT; - cursor_string_table["UI_CURSOR_TOOLBUY"] = UI_CURSOR_TOOLBUY; - cursor_string_table["UI_CURSOR_TOOLOPEN"] = UI_CURSOR_TOOLOPEN; - cursor_string_table["UI_CURSOR_TOOLPATHFINDING"] = UI_CURSOR_TOOLPATHFINDING; - cursor_string_table["UI_CURSOR_TOOLPATHFINDINGPATHSTART"] = UI_CURSOR_TOOLPATHFINDING_PATH_START; - cursor_string_table["UI_CURSOR_TOOLPATHFINDINGPATHSTARTADD"] = UI_CURSOR_TOOLPATHFINDING_PATH_START_ADD; - cursor_string_table["UI_CURSOR_TOOLPATHFINDINGPATHEND"] = UI_CURSOR_TOOLPATHFINDING_PATH_END; - cursor_string_table["UI_CURSOR_TOOLPATHFINDINGPATHENDADD"] = UI_CURSOR_TOOLPATHFINDING_PATH_END_ADD; - cursor_string_table["UI_CURSOR_TOOLNO"] = UI_CURSOR_TOOLNO; - } - - std::map<std::string,U32>::const_iterator iter = cursor_string_table.find(cursor_string); - - if (iter != cursor_string_table.end()) - { - return (ECursorType)iter->second; - } - - return UI_CURSOR_ARROW; -} - - - diff --git a/indra/llcommon/llcursortypes.h b/indra/llcommon/llcursortypes.h deleted file mode 100755 index cb6d6636a0..0000000000 --- a/indra/llcommon/llcursortypes.h +++ /dev/null @@ -1,79 +0,0 @@ -/** - * @file llcursortypes.h - * @brief Cursor types - * - * $LicenseInfo:firstyear=2008&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_LLCURSORTYPES_H -#define LL_LLCURSORTYPES_H - -// If you add types here, add them in LLCursor::getCursorFromString -enum ECursorType { - UI_CURSOR_ARROW, - UI_CURSOR_WAIT, - UI_CURSOR_HAND, - UI_CURSOR_IBEAM, - UI_CURSOR_CROSS, - UI_CURSOR_SIZENWSE, - UI_CURSOR_SIZENESW, - UI_CURSOR_SIZEWE, - UI_CURSOR_SIZENS, - UI_CURSOR_NO, - UI_CURSOR_WORKING, - UI_CURSOR_TOOLGRAB, - UI_CURSOR_TOOLLAND, - UI_CURSOR_TOOLFOCUS, - UI_CURSOR_TOOLCREATE, - UI_CURSOR_ARROWDRAG, - UI_CURSOR_ARROWCOPY, // drag with copy - UI_CURSOR_ARROWDRAGMULTI, - UI_CURSOR_ARROWCOPYMULTI, // drag with copy - UI_CURSOR_NOLOCKED, - UI_CURSOR_ARROWLOCKED, - UI_CURSOR_GRABLOCKED, - UI_CURSOR_TOOLTRANSLATE, - UI_CURSOR_TOOLROTATE, - UI_CURSOR_TOOLSCALE, - UI_CURSOR_TOOLCAMERA, - UI_CURSOR_TOOLPAN, - UI_CURSOR_TOOLZOOMIN, - UI_CURSOR_TOOLPICKOBJECT3, - UI_CURSOR_TOOLPLAY, - UI_CURSOR_TOOLPAUSE, - UI_CURSOR_TOOLMEDIAOPEN, - UI_CURSOR_PIPETTE, - UI_CURSOR_TOOLSIT, - UI_CURSOR_TOOLBUY, - UI_CURSOR_TOOLOPEN, - UI_CURSOR_TOOLPATHFINDING, - UI_CURSOR_TOOLPATHFINDING_PATH_START, - UI_CURSOR_TOOLPATHFINDING_PATH_START_ADD, - UI_CURSOR_TOOLPATHFINDING_PATH_END, - UI_CURSOR_TOOLPATHFINDING_PATH_END_ADD, - UI_CURSOR_TOOLNO, - UI_CURSOR_COUNT // Number of elements in this enum (NOT a cursor) -}; - -LL_COMMON_API ECursorType getCursorFromString(const std::string& cursor_string); - -#endif // LL_LLCURSORTYPES_H diff --git a/indra/llcommon/lldarray.h b/indra/llcommon/lldarray.h deleted file mode 100755 index 131b819c99..0000000000 --- a/indra/llcommon/lldarray.h +++ /dev/null @@ -1,223 +0,0 @@ -/** - * @file lldarray.h - * @brief Wrapped std::vector for backward compatibility. - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_LLDARRAY_H -#define LL_LLDARRAY_H - -#include "llerror.h" - -#include <vector> -#include <map> - -// class LLDynamicArray<>; // = std::vector + reserves <BlockSize> elements -// class LLDynamicArrayIndexed<>; // = std::vector + std::map if indices, only supports operator[] and begin(),end() - -//-------------------------------------------------------- -// LLDynamicArray declaration -//-------------------------------------------------------- -// NOTE: BlockSize is used to reserve a minimal initial amount -template <typename Type, int BlockSize = 32> -class LLDynamicArray : public std::vector<Type> -{ -public: - enum - { - OKAY = 0, - FAIL = -1 - }; - - LLDynamicArray(S32 size=0) : std::vector<Type>(size) { if (size < BlockSize) std::vector<Type>::reserve(BlockSize); } - - void reset() { std::vector<Type>::clear(); } - - // ACCESSORS - const Type& get(S32 index) const { return std::vector<Type>::operator[](index); } - Type& get(S32 index) { return std::vector<Type>::operator[](index); } - S32 find(const Type &obj) const; - - S32 count() const { return std::vector<Type>::size(); } - S32 getLength() const { return std::vector<Type>::size(); } - S32 getMax() const { return std::vector<Type>::capacity(); } - - // MANIPULATE - S32 put(const Type &obj); // add to end of array, returns index -// Type* reserve(S32 num); // reserve a block of indices in advance - Type* reserve_block(U32 num); // reserve a block of indices in advance - - S32 remove(S32 index); // remove by index, no bounds checking - S32 removeObj(const Type &obj); // remove by object - S32 removeLast(); - - void operator+=(const LLDynamicArray<Type,BlockSize> &other); -}; - -//-------------------------------------------------------- -// LLDynamicArray implementation -//-------------------------------------------------------- - -template <typename Type,int BlockSize> -inline S32 LLDynamicArray<Type,BlockSize>::find(const Type &obj) const -{ - typename std::vector<Type>::const_iterator iter = std::find(this->begin(), this->end(), obj); - if (iter != this->end()) - { - return iter - this->begin(); - } - return FAIL; -} - - -template <typename Type,int BlockSize> -inline S32 LLDynamicArray<Type,BlockSize>::remove(S32 i) -{ - // This is a fast removal by swapping with the last element - S32 sz = this->size(); - if (i < 0 || i >= sz) - { - return FAIL; - } - if (i < sz-1) - { - this->operator[](i) = this->back(); - } - this->pop_back(); - return i; -} - -template <typename Type,int BlockSize> -inline S32 LLDynamicArray<Type,BlockSize>::removeObj(const Type& obj) -{ - typename std::vector<Type>::iterator iter = std::find(this->begin(), this->end(), obj); - if (iter != this->end()) - { - S32 res = iter - this->begin(); - typename std::vector<Type>::iterator last = this->end(); - --last; - *iter = *last; - this->pop_back(); - return res; - } - return FAIL; -} - -template <typename Type,int BlockSize> -inline S32 LLDynamicArray<Type,BlockSize>::removeLast() -{ - if (!this->empty()) - { - this->pop_back(); - return OKAY; - } - return FAIL; -} - -template <typename Type,int BlockSize> -inline Type* LLDynamicArray<Type,BlockSize>::reserve_block(U32 num) -{ - U32 sz = this->size(); - this->resize(sz+num); - return &(this->operator[](sz)); -} - -template <typename Type,int BlockSize> -inline S32 LLDynamicArray<Type,BlockSize>::put(const Type &obj) -{ - this->push_back(obj); - return this->size() - 1; -} - -template <typename Type,int BlockSize> -inline void LLDynamicArray<Type,BlockSize>::operator+=(const LLDynamicArray<Type,BlockSize> &other) -{ - insert(this->end(), other.begin(), other.end()); -} - -//-------------------------------------------------------- -// LLDynamicArrayIndexed declaration -//-------------------------------------------------------- - -template <typename Type, typename Key, int BlockSize = 32> -class LLDynamicArrayIndexed -{ -public: - typedef typename std::vector<Type>::iterator iterator; - typedef typename std::vector<Type>::const_iterator const_iterator; - typedef typename std::vector<Type>::reverse_iterator reverse_iterator; - typedef typename std::vector<Type>::const_reverse_iterator const_reverse_iterator; - typedef typename std::vector<Type>::size_type size_type; -protected: - std::vector<Type> mVector; - std::map<Key, U32> mIndexMap; - -public: - LLDynamicArrayIndexed() { mVector.reserve(BlockSize); } - - iterator begin() { return mVector.begin(); } - const_iterator begin() const { return mVector.begin(); } - iterator end() { return mVector.end(); } - const_iterator end() const { return mVector.end(); } - - reverse_iterator rbegin() { return mVector.rbegin(); } - const_reverse_iterator rbegin() const { return mVector.rbegin(); } - reverse_iterator rend() { return mVector.rend(); } - const_reverse_iterator rend() const { return mVector.rend(); } - - void reset() { mVector.resize(0); mIndexMap.resize(0); } - bool empty() const { return mVector.empty(); } - size_type size() const { return mVector.size(); } - - Type& operator[](const Key& k) - { - typename std::map<Key, U32>::const_iterator iter = mIndexMap.find(k); - if (iter == mIndexMap.end()) - { - U32 n = mVector.size(); - mIndexMap[k] = n; - mVector.push_back(Type()); - llassert(mVector.size() == mIndexMap.size()); - return mVector[n]; - } - else - { - return mVector[iter->second]; - } - } - - const_iterator find(const Key& k) const - { - typename std::map<Key, U32>::const_iterator iter = mIndexMap.find(k); - if(iter == mIndexMap.end()) - { - return mVector.end(); - } - else - { - return mVector.begin() + iter->second; - } - } -}; - -#endif diff --git a/indra/llcommon/lldate.cpp b/indra/llcommon/lldate.cpp index 030ef6a3c7..7a2a0869f4 100755 --- a/indra/llcommon/lldate.cpp +++ b/indra/llcommon/lldate.cpp @@ -39,6 +39,7 @@ #include "lltimer.h" #include "llstring.h" +#include "llfasttimer.h" static const F64 DATE_EPOCH = 0.0; @@ -48,25 +49,22 @@ static const F64 LL_APR_USEC_PER_SEC = 1000000.0; LLDate::LLDate() : mSecondsSinceEpoch(DATE_EPOCH) -{ -} +{} LLDate::LLDate(const LLDate& date) : mSecondsSinceEpoch(date.mSecondsSinceEpoch) -{ -} +{} -LLDate::LLDate(F64 seconds_since_epoch) : - mSecondsSinceEpoch(seconds_since_epoch) -{ -} +LLDate::LLDate(F64SecondsImplicit seconds_since_epoch) : + mSecondsSinceEpoch(seconds_since_epoch.value()) +{} LLDate::LLDate(const std::string& iso8601_date) { if(!fromString(iso8601_date)) { - llwarns << "date " << iso8601_date << " failed to parse; " - << "ZEROING IT OUT" << llendl; + LL_WARNS() << "date " << iso8601_date << " failed to parse; " + << "ZEROING IT OUT" << LL_ENDL; mSecondsSinceEpoch = DATE_EPOCH; } } @@ -88,11 +86,11 @@ std::string LLDate::asRFC1123() const return toHTTPDateString (std::string ("%A, %d %b %Y %H:%M:%S GMT")); } -LLFastTimer::DeclareTimer FT_DATE_FORMAT("Date Format"); +LLTrace::BlockTimerStatHandle FT_DATE_FORMAT("Date Format"); std::string LLDate::toHTTPDateString (std::string fmt) const { - LLFastTimer ft1(FT_DATE_FORMAT); + LL_RECORD_BLOCK_TIME(FT_DATE_FORMAT); time_t locSeconds = (time_t) mSecondsSinceEpoch; struct tm * gmt = gmtime (&locSeconds); @@ -101,7 +99,7 @@ std::string LLDate::toHTTPDateString (std::string fmt) const std::string LLDate::toHTTPDateString (tm * gmt, std::string fmt) { - LLFastTimer ft1(FT_DATE_FORMAT); + LL_RECORD_BLOCK_TIME(FT_DATE_FORMAT); // avoid calling setlocale() unnecessarily - it's expensive. static std::string prev_locale = ""; diff --git a/indra/llcommon/lldate.h b/indra/llcommon/lldate.h index 7ff8b550ad..be2cd2d051 100755 --- a/indra/llcommon/lldate.h +++ b/indra/llcommon/lldate.h @@ -33,6 +33,7 @@ #include <string> #include "stdtypes.h" +#include "llunits.h" /** * @class LLDate @@ -56,9 +57,9 @@ public: /** * @brief Construct a date from a seconds since epoch value. * - * @pararm seconds_since_epoch The number of seconds since UTC epoch. + * @param seconds_since_epoch The number of seconds since UTC epoch. */ - LLDate(F64 seconds_since_epoch); + LLDate(F64SecondsImplicit seconds_since_epoch); /** * @brief Construct a date from a string representation diff --git a/indra/llcommon/lldeadmantimer.cpp b/indra/llcommon/lldeadmantimer.cpp index 7d9097e344..830443b956 100644 --- a/indra/llcommon/lldeadmantimer.cpp +++ b/indra/llcommon/lldeadmantimer.cpp @@ -43,7 +43,7 @@ // true true Not allowed // LLDeadmanTimer::LLDeadmanTimer(F64 horizon, bool inc_cpu) - : mHorizon(time_type(llmax(horizon, F64(0.0)) * gClockFrequency)), + : mHorizon(time_type(llmax(horizon, F64(0.0)) * get_timer_info().mClockFrequency)), mActive(false), // If true, a timer is running. mDone(false), // If true, timer has completed and can be read (once) mStarted(U64L(0)), @@ -144,8 +144,8 @@ bool LLDeadmanTimer::isExpired(time_type now, F64 & started, F64 & stopped, U64 return false; } - started = mStarted * gClockFrequencyInv; - stopped = mStopped * gClockFrequencyInv; + started = mStarted * get_timer_info().mClockFrequencyInv; + stopped = mStopped * get_timer_info().mClockFrequencyInv; count = mCount; mDone = false; diff --git a/indra/llcommon/lldeleteutils.h b/indra/llcommon/lldeleteutils.h deleted file mode 100755 index f250dc3028..0000000000 --- a/indra/llcommon/lldeleteutils.h +++ /dev/null @@ -1,47 +0,0 @@ -/** - * @file lldeleteutils.h - * @brief Utility functions to simplify some common pointer-munging idioms. - * - * $LicenseInfo:firstyear=2009&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ -#ifndef LL_DELETE_UTILS_H -#define LL_DELETE_UTILS_H - -// Simple utility functions to eventually replace the common 2-line -// idiom scattered throughout the viewer codebase. Note that where -// possible we would rather be using smart pointers of some sort. - -template <class T> -inline void deleteAndClear(T*& ptr) -{ - delete ptr; - ptr = NULL; -} - -template <class T> -inline void deleteAndClearArray(T*& array_ptr) -{ - delete[] array_ptr; - array_ptr = NULL; -} - -#endif diff --git a/indra/llcommon/lldepthstack.h b/indra/llcommon/lldepthstack.h index d9db54efc7..b65840d342 100755 --- a/indra/llcommon/lldepthstack.h +++ b/indra/llcommon/lldepthstack.h @@ -27,18 +27,19 @@ #ifndef LL_LLDEPTHSTACK_H #define LL_LLDEPTHSTACK_H -#include "linked_lists.h" +#include "llstl.h" template <class DATA_TYPE> class LLDepthStack { private: - LLLinkedList<DATA_TYPE> mStack; + std::deque<DATA_TYPE*> mStack; U32 mCurrentDepth; U32 mMaxDepth; public: - LLDepthStack() : mCurrentDepth(0), mMaxDepth(0) {} - ~LLDepthStack() {} + LLDepthStack() + : mCurrentDepth(0), mMaxDepth(0) + {} void setDepth(U32 depth) { @@ -54,24 +55,27 @@ public: { if (mCurrentDepth < mMaxDepth) { - mStack.addData(data); + mStack.push_back(data); mCurrentDepth++; } else { // the last item falls off stack and is deleted - mStack.getLastData(); - mStack.deleteCurrentData(); - mStack.addData(data); + if (!mStack.empty()) + { + mStack.pop_front(); + } + mStack.push_back(data); } } DATA_TYPE *pop() { - DATA_TYPE *tempp = mStack.getFirstData(); - if (tempp) + DATA_TYPE *tempp = NULL; + if (!mStack.empty()) { - mStack.removeCurrentData(); + tempp = mStack.back(); + mStack.pop_back(); mCurrentDepth--; } return tempp; @@ -79,20 +83,13 @@ public: DATA_TYPE *check() { - DATA_TYPE *tempp = mStack.getFirstData(); - return tempp; + return mStack.empty() ? NULL : mStack.back(); } - - void deleteAllData() - { - mCurrentDepth = 0; - mStack.deleteAllData(); - } - + void removeAllNodes() { mCurrentDepth = 0; - mStack.removeAllNodes(); + mStack.clear(); } }; diff --git a/indra/llcommon/lldictionary.h b/indra/llcommon/lldictionary.h index c752859a36..5800ec5e5d 100755 --- a/indra/llcommon/lldictionary.h +++ b/indra/llcommon/lldictionary.h @@ -89,7 +89,7 @@ protected: { if (lookup(index)) { - llerrs << "Dictionary entry already added (attempted to add duplicate entry)" << llendl; + LL_ERRS() << "Dictionary entry already added (attempted to add duplicate entry)" << LL_ENDL; } (*this)[index] = entry; } diff --git a/indra/llcommon/lldlinked.h b/indra/llcommon/lldlinked.h deleted file mode 100755 index 3f7c197be7..0000000000 --- a/indra/llcommon/lldlinked.h +++ /dev/null @@ -1,93 +0,0 @@ -/** - * @file lldlinked.h - * @brief Declaration of the LLDLinked class. - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ -#ifndef LL_LLDLINKED_H -#define LL_LLDLINKED_H - -template <class Type> class LLDLinked -{ - LLDLinked* mNextp; - LLDLinked* mPrevp; -public: - - Type* getNext() { return (Type*)mNextp; } - Type* getPrev() { return (Type*)mPrevp; } - Type* getFirst() { return (Type*)mNextp; } - - void init() - { - mNextp = mPrevp = NULL; - } - - void unlink() - { - if (mPrevp) mPrevp->mNextp = mNextp; - if (mNextp) mNextp->mPrevp = mPrevp; - } - - LLDLinked() { mNextp = mPrevp = NULL; } - virtual ~LLDLinked() { unlink(); } - - virtual void deleteAll() - { - Type *curp = getFirst(); - while(curp) - { - Type *nextp = curp->getNext(); - curp->unlink(); - delete curp; - curp = nextp; - } - } - - void relink(Type &after) - { - LLDLinked *afterp = (LLDLinked*)&after; - afterp->mPrevp = this; - mNextp = afterp; - } - - virtual void append(Type& after) - { - LLDLinked *afterp = (LLDLinked*)&after; - afterp->mPrevp = this; - afterp->mNextp = mNextp; - if (mNextp) mNextp->mPrevp = afterp; - mNextp = afterp; - } - - virtual void insert(Type& before) - { - LLDLinked *beforep = (LLDLinked*)&before; - beforep->mNextp = this; - beforep->mPrevp = mPrevp; - if (mPrevp) mPrevp->mNextp = beforep; - mPrevp = beforep; - } - - virtual void put(Type& obj) { append(obj); } -}; - -#endif diff --git a/indra/llcommon/lldqueueptr.h b/indra/llcommon/lldqueueptr.h deleted file mode 100755 index 9fe08191e1..0000000000 --- a/indra/llcommon/lldqueueptr.h +++ /dev/null @@ -1,352 +0,0 @@ -/** - * @file lldqueueptr.h - * @brief LLDynamicQueuePtr declaration - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ -#ifndef LL_LLDQUEUEPTR_H -#define LL_LLDQUEUEPTR_H - -template <class Type> -class LLDynamicQueuePtr -{ -public: - enum - { - OKAY = 0, - FAIL = -1 - }; - - LLDynamicQueuePtr(const S32 size=8); - ~LLDynamicQueuePtr(); - - void init(); - void destroy(); - void reset(); - void reallocate(U32 newsize); - - // ACCESSORS - const Type& get(const S32 index) const; // no bounds checking - Type& get(const S32 index); // no bounds checking - const Type& operator [] (const S32 index) const { return get(index); } - Type& operator [] (const S32 index) { return get(index); } - S32 find(const Type &obj) const; - - S32 count() const { return (mLastObj >= mFirstObj ? mLastObj - mFirstObj : mLastObj + mMaxObj - mFirstObj); } - S32 getMax() const { return mMaxObj; } - S32 getFirst() const { return mFirstObj; } - S32 getLast () const { return mLastObj; } - - // MANIPULATE - S32 push(const Type &obj); // add to end of Queue, returns index from start - S32 pull( Type &obj); // pull from Queue, returns index from start - - S32 remove (S32 index); // remove by index - S32 removeObj(const Type &obj); // remove by object - -protected: - S32 mFirstObj, mLastObj, mMaxObj; - Type* mMemory; - -public: - - void print() - { - /* - Convert this to llinfos if it's intended to be used - djs 08/30/02 - - printf("Printing from %d to %d (of %d): ",mFirstObj, mLastObj, mMaxObj); - - if (mFirstObj <= mLastObj) - { - for (S32 i=mFirstObj;i<mLastObj;i++) - { - printf("%d ",mMemory[i]); - } - } - else - { - for (S32 i=mFirstObj;i<mMaxObj;i++) - { - printf("%d ",mMemory[i]); - } - for (i=0;i<mLastObj;i++) - { - printf("%d ",mMemory[i]); - } - } - printf("\n"); - */ - } - -}; - - -//-------------------------------------------------------- -// LLDynamicQueuePtrPtr implementation -//-------------------------------------------------------- - - -template <class Type> -inline LLDynamicQueuePtr<Type>::LLDynamicQueuePtr(const S32 size) -{ - init(); - reallocate(size); -} - -template <class Type> -inline LLDynamicQueuePtr<Type>::~LLDynamicQueuePtr() -{ - destroy(); -} - -template <class Type> -inline void LLDynamicQueuePtr<Type>::init() -{ - mFirstObj = 0; - mLastObj = 0; - mMaxObj = 0; - mMemory = NULL; -} - -template <class Type> -inline void LLDynamicQueuePtr<Type>::reallocate(U32 newsize) -{ - if (newsize) - { - if (mFirstObj > mLastObj && newsize > mMaxObj) - { - Type* new_memory = new Type[newsize]; - - llassert(new_memory); - - S32 _count = count(); - S32 i, m = 0; - for (i=mFirstObj; i < mMaxObj; i++) - { - new_memory[m++] = mMemory[i]; - } - for (i=0; i <=mLastObj; i++) - { - new_memory[m++] = mMemory[i]; - } - - delete[] mMemory; - mMemory = new_memory; - - mFirstObj = 0; - mLastObj = _count; - } - else - { - Type* new_memory = new Type[newsize]; - - llassert(new_memory); - - S32 i, m = 0; - for (i=0; i < mLastObj; i++) - { - new_memory[m++] = mMemory[i]; - } - delete[] mMemory; - mMemory = new_memory; - } - } - else if (mMemory) - { - delete[] mMemory; - mMemory = NULL; - } - - mMaxObj = newsize; -} - -template <class Type> -inline void LLDynamicQueuePtr<Type>::destroy() -{ - reset(); - delete[] mMemory; - mMemory = NULL; -} - - -template <class Type> -void LLDynamicQueuePtr<Type>::reset() -{ - for (S32 i=0; i < mMaxObj; i++) - { - get(i) = NULL; // unrefs for pointers - } - - mFirstObj = 0; - mLastObj = 0; -} - - -template <class Type> -inline S32 LLDynamicQueuePtr<Type>::find(const Type &obj) const -{ - S32 i; - if (mFirstObj <= mLastObj) - { - for ( i = mFirstObj; i < mLastObj; i++ ) - { - if (mMemory[i] == obj) - { - return i; - } - } - } - else - { - for ( i = mFirstObj; i < mMaxObj; i++ ) - { - if (mMemory[i] == obj) - { - return i; - } - } - for ( i = 0; i < mLastObj; i++ ) - { - if (mMemory[i] == obj) - { - return i; - } - } - } - - return FAIL; -} - -template <class Type> -inline S32 LLDynamicQueuePtr<Type>::remove(S32 i) -{ - if (mFirstObj > mLastObj) - { - if (i >= mFirstObj && i < mMaxObj) - { - while( i > mFirstObj) - { - mMemory[i] = mMemory[i-1]; - i--; - } - mMemory[mFirstObj] = NULL; - mFirstObj++; - if (mFirstObj >= mMaxObj) mFirstObj = 0; - - return count(); - } - else if (i < mLastObj && i >= 0) - { - while(i < mLastObj) - { - mMemory[i] = mMemory[i+1]; - i++; - } - mMemory[mLastObj] = NULL; - mLastObj--; - if (mLastObj < 0) mLastObj = mMaxObj-1; - - return count(); - } - } - else if (i <= mLastObj && i >= mFirstObj) - { - while(i < mLastObj) - { - mMemory[i] = mMemory[i+1]; - i++; - } - mMemory[mLastObj] = NULL; - mLastObj--; - if (mLastObj < 0) mLastObj = mMaxObj-1; - - return count(); - } - - - return FAIL; -} - -template <class Type> -inline S32 LLDynamicQueuePtr<Type>::removeObj(const Type& obj) -{ - S32 ind = find(obj); - if (ind >= 0) - { - return remove(ind); - } - return FAIL; -} - -template <class Type> -inline S32 LLDynamicQueuePtr<Type>::push(const Type &obj) -{ - if (mMaxObj - count() <= 1) - { - reallocate(mMaxObj * 2); - } - - mMemory[mLastObj++] = obj; - - if (mLastObj >= mMaxObj) - { - mLastObj = 0; - } - - return count(); -} - -template <class Type> -inline S32 LLDynamicQueuePtr<Type>::pull(Type &obj) -{ - obj = NULL; - - if (count() < 1) return -1; - - obj = mMemory[mFirstObj]; - mMemory[mFirstObj] = NULL; - - mFirstObj++; - - if (mFirstObj >= mMaxObj) - { - mFirstObj = 0; - } - - return count(); -} - -template <class Type> -inline const Type& LLDynamicQueuePtr<Type>::get(const S32 i) const -{ - return mMemory[i]; -} - -template <class Type> -inline Type& LLDynamicQueuePtr<Type>::get(const S32 i) -{ - return mMemory[i]; -} - - -#endif // LL_LLDQUEUEPTR_H diff --git a/indra/llcommon/llenum.h b/indra/llcommon/llenum.h deleted file mode 100755 index f57b2bc0b5..0000000000 --- a/indra/llcommon/llenum.h +++ /dev/null @@ -1,78 +0,0 @@ -/** - * @file llenum.h - * @author Tom Yedwab - * @brief Utility class for storing enum value <-> string lookup. - * - * $LicenseInfo:firstyear=2006&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_LLENUM_H -#define LL_LLENUM_H - -class LLEnum -{ -public: - typedef std::pair<const std::string, const U32> enum_t; - enum - { - UNDEFINED = 0xffffffff, - }; - - LLEnum(const enum_t values_array[], const U32 length) - { - for (U32 i=0; i<length; ++i) - { - mEnumMap.insert(values_array[i]); - if (values_array[i].second >= mEnumArray.size()) - { - mEnumArray.resize(values_array[i].second+1); - } - mEnumArray[values_array[i].second] = values_array[i].first; - } - } - - U32 operator[](std::string str) - { - std::map<const std::string, const U32>::iterator itor; - itor = mEnumMap.find(str); - if (itor != mEnumMap.end()) - { - return itor->second; - } - return UNDEFINED; - } - - const std::string operator[](U32 index) - { - if (index < mEnumArray.size()) - { - return mEnumArray[index]; - } - return ""; - } - -private: - std::map<const std::string, const U32> mEnumMap; - std::vector<std::string> mEnumArray; -}; - -#endif // LL_LLENUM_H diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp index 853f279c95..a7963174ad 100755 --- a/indra/llcommon/llerror.cpp +++ b/indra/llcommon/llerror.cpp @@ -51,7 +51,26 @@ #include "lltimer.h" namespace { -#if !LL_WINDOWS +#if LL_WINDOWS + void debugger_print(const std::string& s) + { + // Be careful when calling OutputDebugString as it throws DBG_PRINTEXCEPTION_C + // which works just fine under the windows debugger, but can cause users who + // have enabled SEHOP exception chain validation to crash due to interactions + // between the Win 32-bit exception handling and boost coroutine fiber stacks. BUG-2707 + // + if (IsDebuggerPresent()) + { + // Need UTF16 for Unicode OutputDebugString + // + if (s.size()) + { + OutputDebugString(utf8str_to_utf16str(s).c_str()); + OutputDebugString(TEXT("\n")); + } + } + } +#else class RecordToSyslog : public LLError::Recorder { public: @@ -96,8 +115,9 @@ namespace { mFile.open(filename, llofstream::out | llofstream::app); if (!mFile) { - llinfos << "Error setting log file to " << filename << llendl; + LL_INFOS() << "Error setting log file to " << filename << LL_ENDL; } + mWantsTime = true; } ~RecordToFile() @@ -107,14 +127,10 @@ namespace { bool okay() { return mFile; } - virtual bool wantsTime() { return true; } - virtual void recordMessage(LLError::ELevel level, const std::string& message) { mFile << message << std::endl; - // mFile.flush(); - // *FIX: should we do this? } private: @@ -125,9 +141,10 @@ namespace { class RecordToStderr : public LLError::Recorder { public: - RecordToStderr(bool timestamp) : mTimestamp(timestamp), mUseANSI(ANSI_PROBE) { } - - virtual bool wantsTime() { return mTimestamp; } + RecordToStderr(bool timestamp) : mUseANSI(ANSI_PROBE) + { + mWantsTime = timestamp; + } virtual void recordMessage(LLError::ELevel level, const std::string& message) @@ -158,14 +175,19 @@ namespace { } private: - bool mTimestamp; - enum ANSIState {ANSI_PROBE, ANSI_YES, ANSI_NO}; - ANSIState mUseANSI; + enum ANSIState + { + ANSI_PROBE, + ANSI_YES, + ANSI_NO + } mUseANSI; + void colorANSI(const std::string color) { // ANSI color code escape sequence fprintf(stderr, "\033[%sm", color.c_str() ); }; + bool checkANSI(void) { #if LL_LINUX || LL_DARWIN @@ -198,10 +220,13 @@ namespace { class RecordToWinDebug: public LLError::Recorder { public: + RecordToWinDebug() + {} + virtual void recordMessage(LLError::ELevel level, const std::string& message) { - LL_WINDOWS_OUTPUT_DEBUG(message); + debugger_print(message); } }; #endif @@ -213,7 +238,7 @@ namespace std::string className(const std::type_info& type) { #ifdef __GNUC__ - // GCC: type_info::name() returns a mangled class name, must demangle + // GCC: type_info::name() returns a mangled class name,st demangle static size_t abi_name_len = 100; static char* abi_name_buf = (char*)malloc(abi_name_len); @@ -317,15 +342,15 @@ namespace if (configuration.isUndefined()) { - llwarns << filename() << " missing, ill-formed," + LL_WARNS() << filename() << " missing, ill-formed," " or simply undefined; not changing configuration" - << llendl; + << LL_ENDL; return false; } } LLError::configure(configuration); - llinfos << "logging reconfigured from " << filename() << llendl; + LL_INFOS() << "logging reconfigured from " << filename() << LL_ENDL; return true; } @@ -390,25 +415,25 @@ namespace LLError class Settings { public: - bool printLocation; + bool mPrintLocation; - LLError::ELevel defaultLevel; + LLError::ELevel mDefaultLevel; - LevelMap functionLevelMap; - LevelMap classLevelMap; - LevelMap fileLevelMap; - LevelMap tagLevelMap; - std::map<std::string, unsigned int> uniqueLogMessages; + LevelMap mFunctionLevelMap; + LevelMap mClassLevelMap; + LevelMap mFileLevelMap; + LevelMap mTagLevelMap; + std::map<std::string, unsigned int> mUniqueLogMessages; - LLError::FatalFunction crashFunction; - LLError::TimeFunction timeFunction; + LLError::FatalFunction mCrashFunction; + LLError::TimeFunction mTimeFunction; - Recorders recorders; - Recorder* fileRecorder; - Recorder* fixedBufferRecorder; - std::string fileRecorderFileName; + Recorders mRecorders; + Recorder* mFileRecorder; + Recorder* mFixedBufferRecorder; + std::string mFileRecorderFileName; - int shouldLogCallCounter; + int mShouldLogCallCounter; static Settings& get(); @@ -418,19 +443,19 @@ namespace LLError private: Settings() - : printLocation(false), - defaultLevel(LLError::LEVEL_DEBUG), - crashFunction(), - timeFunction(NULL), - fileRecorder(NULL), - fixedBufferRecorder(NULL), - shouldLogCallCounter(0) + : mPrintLocation(false), + mDefaultLevel(LLError::LEVEL_DEBUG), + mCrashFunction(), + mTimeFunction(NULL), + mFileRecorder(NULL), + mFixedBufferRecorder(NULL), + mShouldLogCallCounter(0) { } ~Settings() { - for_each(recorders.begin(), recorders.end(), DeletePointer()); - recorders.clear(); + for_each(mRecorders.begin(), mRecorders.end(), DeletePointer()); + mRecorders.clear(); } static Settings*& getPtr(); @@ -489,18 +514,64 @@ namespace LLError int line, const std::type_info& class_info, const char* function, - const char* broadTag, - const char* narrowTag, - bool printOnce) - : mLevel(level), mFile(file), mLine(line), - mClassInfo(class_info), mFunction(function), - mCached(false), mShouldLog(false), - mBroadTag(broadTag), mNarrowTag(narrowTag), mPrintOnce(printOnce) - { } + bool printOnce, + const char** tags, + size_t tag_count) + : mLevel(level), + mFile(file), + mLine(line), + mClassInfo(class_info), + mFunction(function), + mCached(false), + mShouldLog(false), + mPrintOnce(printOnce), + mTags(new const char* [tag_count]), + mTagCount(tag_count) + { + for (int i = 0; i < tag_count; i++) + { + mTags[i] = tags[i]; + } + + switch (mLevel) + { + case LEVEL_DEBUG: mLevelString = "DEBUG:"; break; + case LEVEL_INFO: mLevelString = "INFO:"; break; + case LEVEL_WARN: mLevelString = "WARNING:"; break; + case LEVEL_ERROR: mLevelString = "ERROR:"; break; + default: mLevelString = "XXX:"; break; + }; + mLocationString = llformat("%s(%d) :", abbreviateFile(mFile).c_str(), mLine); +#if LL_WINDOWS + // DevStudio: __FUNCTION__ already includes the full class name +#else +#if LL_LINUX + // gross, but typeid comparison seems to always fail here with gcc4.1 + if (0 != strcmp(mClassInfo.name(), typeid(NoClassInfo).name())) +#else + if (mClassInfo != typeid(NoClassInfo)) +#endif // LL_LINUX + { + mFunctionString = className(mClassInfo) + "::"; + } +#endif + mFunctionString += std::string(mFunction) + ":"; + for (size_t i = 0; i < mTagCount; i++) + { + mTagString += std::string("#") + mTags[i] + ((i == mTagCount - 1) ? "" : " "); + } + } + + CallSite::~CallSite() + { + delete []mTags; + } void CallSite::invalidate() - { mCached = false; } + { + mCached = false; + } } namespace @@ -586,25 +657,25 @@ namespace LLError void setPrintLocation(bool print) { Settings& s = Settings::get(); - s.printLocation = print; + s.mPrintLocation = print; } void setFatalFunction(const FatalFunction& f) { Settings& s = Settings::get(); - s.crashFunction = f; + s.mCrashFunction = f; } FatalFunction getFatalFunction() { Settings& s = Settings::get(); - return s.crashFunction; + return s.mCrashFunction; } void setTimeFunction(TimeFunction f) { Settings& s = Settings::get(); - s.timeFunction = f; + s.mTimeFunction = f; } void setDefaultLevel(ELevel level) @@ -612,13 +683,13 @@ namespace LLError Globals& g = Globals::get(); Settings& s = Settings::get(); g.invalidateCallSites(); - s.defaultLevel = level; + s.mDefaultLevel = level; } ELevel getDefaultLevel() { Settings& s = Settings::get(); - return s.defaultLevel; + return s.mDefaultLevel; } void setFunctionLevel(const std::string& function_name, ELevel level) @@ -626,7 +697,7 @@ namespace LLError Globals& g = Globals::get(); Settings& s = Settings::get(); g.invalidateCallSites(); - s.functionLevelMap[function_name] = level; + s.mFunctionLevelMap[function_name] = level; } void setClassLevel(const std::string& class_name, ELevel level) @@ -634,7 +705,7 @@ namespace LLError Globals& g = Globals::get(); Settings& s = Settings::get(); g.invalidateCallSites(); - s.classLevelMap[class_name] = level; + s.mClassLevelMap[class_name] = level; } void setFileLevel(const std::string& file_name, ELevel level) @@ -642,7 +713,7 @@ namespace LLError Globals& g = Globals::get(); Settings& s = Settings::get(); g.invalidateCallSites(); - s.fileLevelMap[file_name] = level; + s.mFileLevelMap[file_name] = level; } void setTagLevel(const std::string& tag_name, ELevel level) @@ -650,7 +721,7 @@ namespace LLError Globals& g = Globals::get(); Settings& s = Settings::get(); g.invalidateCallSites(); - s.tagLevelMap[tag_name] = level; + s.mTagLevelMap[tag_name] = level; } LLError::ELevel decodeLevel(std::string name) @@ -671,7 +742,7 @@ namespace LLError LevelMap::const_iterator i = level_names.find(name); if (i == level_names.end()) { - llwarns << "unrecognized logging level: '" << name << "'" << llendl; + LL_WARNS() << "unrecognized logging level: '" << name << "'" << LL_ENDL; return LLError::LEVEL_INFO; } @@ -698,11 +769,11 @@ namespace LLError Settings& s = Settings::get(); g.invalidateCallSites(); - s.functionLevelMap.clear(); - s.classLevelMap.clear(); - s.fileLevelMap.clear(); - s.tagLevelMap.clear(); - s.uniqueLogMessages.clear(); + s.mFunctionLevelMap.clear(); + s.mClassLevelMap.clear(); + s.mFileLevelMap.clear(); + s.mTagLevelMap.clear(); + s.mUniqueLogMessages.clear(); setPrintLocation(config["print-location"]); setDefaultLevel(decodeLevel(config["default-level"])); @@ -715,10 +786,10 @@ namespace LLError ELevel level = decodeLevel(entry["level"]); - setLevels(s.functionLevelMap, entry["functions"], level); - setLevels(s.classLevelMap, entry["classes"], level); - setLevels(s.fileLevelMap, entry["files"], level); - setLevels(s.tagLevelMap, entry["tags"], level); + setLevels(s.mFunctionLevelMap, entry["functions"], level); + setLevels(s.mClassLevelMap, entry["classes"], level); + setLevels(s.mFileLevelMap, entry["files"], level); + setLevels(s.mTagLevelMap, entry["tags"], level); } } } @@ -726,14 +797,45 @@ namespace LLError namespace LLError { + Recorder::Recorder() + : mWantsTime(false), + mWantsTags(false), + mWantsLevel(true), + mWantsLocation(false), + mWantsFunctionName(true) + {} + Recorder::~Recorder() { } - // virtual bool Recorder::wantsTime() - { return false; } + { + return mWantsTime; + } + // virtual + bool Recorder::wantsTags() + { + return mWantsTags; + } + // virtual + bool Recorder::wantsLevel() + { + return mWantsLevel; + } + + // virtual + bool Recorder::wantsLocation() + { + return mWantsLocation; + } + + // virtual + bool Recorder::wantsFunctionName() + { + return mWantsFunctionName; + } void addRecorder(Recorder* recorder) { @@ -742,7 +844,7 @@ namespace LLError return; } Settings& s = Settings::get(); - s.recorders.push_back(recorder); + s.mRecorders.push_back(recorder); } void removeRecorder(Recorder* recorder) @@ -752,9 +854,8 @@ namespace LLError return; } Settings& s = Settings::get(); - s.recorders.erase( - std::remove(s.recorders.begin(), s.recorders.end(), recorder), - s.recorders.end()); + s.mRecorders.erase(std::remove(s.mRecorders.begin(), s.mRecorders.end(), recorder), + s.mRecorders.end()); } } @@ -764,10 +865,10 @@ namespace LLError { LLError::Settings& s = LLError::Settings::get(); - removeRecorder(s.fileRecorder); - delete s.fileRecorder; - s.fileRecorder = NULL; - s.fileRecorderFileName.clear(); + removeRecorder(s.mFileRecorder); + delete s.mFileRecorder; + s.mFileRecorder = NULL; + s.mFileRecorderFileName.clear(); if (file_name.empty()) { @@ -781,8 +882,8 @@ namespace LLError return; } - s.fileRecorderFileName = file_name; - s.fileRecorder = f; + s.mFileRecorderFileName = file_name; + s.mFileRecorder = f; addRecorder(f); } @@ -790,98 +891,112 @@ namespace LLError { LLError::Settings& s = LLError::Settings::get(); - removeRecorder(s.fixedBufferRecorder); - delete s.fixedBufferRecorder; - s.fixedBufferRecorder = NULL; + removeRecorder(s.mFixedBufferRecorder); + delete s.mFixedBufferRecorder; + s.mFixedBufferRecorder = NULL; if (!fixedBuffer) { return; } - s.fixedBufferRecorder = new RecordToFixedBuffer(fixedBuffer); - addRecorder(s.fixedBufferRecorder); + s.mFixedBufferRecorder = new RecordToFixedBuffer(fixedBuffer); + addRecorder(s.mFixedBufferRecorder); } std::string logFileName() { LLError::Settings& s = LLError::Settings::get(); - return s.fileRecorderFileName; + return s.mFileRecorderFileName; } } namespace { - void writeToRecorders(LLError::ELevel level, const std::string& message) + void writeToRecorders(const LLError::CallSite& site, const std::string& message, bool show_location = true, bool show_time = true, bool show_tags = true, bool show_level = true, bool show_function = true) { + LLError::ELevel level = site.mLevel; LLError::Settings& s = LLError::Settings::get(); - std::string messageWithTime; - - for (Recorders::const_iterator i = s.recorders.begin(); - i != s.recorders.end(); + for (Recorders::const_iterator i = s.mRecorders.begin(); + i != s.mRecorders.end(); ++i) { LLError::Recorder* r = *i; - if (r->wantsTime() && s.timeFunction != NULL) + std::ostringstream message_stream; + + if (show_location && (r->wantsLocation() || level == LLError::LEVEL_ERROR || s.mPrintLocation)) + { + message_stream << site.mLocationString << " "; + } + + if (show_time && r->wantsTime() && s.mTimeFunction != NULL) { - if (messageWithTime.empty()) + message_stream << s.mTimeFunction() << " "; + } + + if (show_level && r->wantsLevel()) { - messageWithTime = s.timeFunction() + " " + message; + message_stream << site.mLevelString << " "; } - r->recordMessage(level, messageWithTime); + if (show_tags && r->wantsTags()) + { + message_stream << site.mTagString << " "; } - else + + if (show_function && r->wantsFunctionName()) { - r->recordMessage(level, message); + message_stream << site.mFunctionString << " "; } + + message_stream << message; + + r->recordMessage(level, message_stream.str()); } } } - -/* -Recorder formats: - -$type = "ERROR" | "WARNING" | "ALERT" | "INFO" | "DEBUG" -$loc = "$file($line)" -$msg = "$loc : " if FATAL or printing loc - "" otherwise -$msg += "$type: " -$msg += contents of stringstream - -$time = "%Y-%m-%dT%H:%M:%SZ" if UTC - or "%Y-%m-%dT%H:%M:%S %Z" if local - -syslog: "$msg" -file: "$time $msg\n" -stderr: "$time $msg\n" except on windows, "$msg\n" -fixedbuf: "$msg" -winddebug: "$msg\n" - -Note: if FATAL, an additional line gets logged first, with $msg set to - "$loc : error" - -You get: - llfoo.cpp(42) : error - llfoo.cpp(42) : ERROR: something - -*/ - namespace { bool checkLevelMap(const LevelMap& map, const std::string& key, LLError::ELevel& level) { + bool stop_checking; LevelMap::const_iterator i = map.find(key); if (i == map.end()) { - return false; + return stop_checking = false; } level = i->second; - return true; + return stop_checking = true; + } + + bool checkLevelMap( const LevelMap& map, + const char *const * keys, + size_t count, + LLError::ELevel& level) + { + bool found_level = false; + + LLError::ELevel tag_level = LLError::LEVEL_NONE; + + for (size_t i = 0; i < count; i++) + { + LevelMap::const_iterator it = map.find(keys[i]); + if (it != map.end()) + { + found_level = true; + tag_level = llmin(tag_level, it->second); + } + } + + if (found_level) + { + level = tag_level; + } + return found_level; } class LogLock @@ -948,9 +1063,9 @@ namespace LLError Globals& g = Globals::get(); Settings& s = Settings::get(); - s.shouldLogCallCounter += 1; + s.mShouldLogCallCounter++; - std::string class_name = className(site.mClassInfo); + const std::string& class_name = className(site.mClassInfo); std::string function_name = functionName(site.mFunction); #if LL_LINUX // gross, but typeid comparison seems to always fail here with gcc4.1 @@ -962,17 +1077,18 @@ namespace LLError function_name = class_name + "::" + function_name; } - ELevel compareLevel = s.defaultLevel; + ELevel compareLevel = s.mDefaultLevel; // The most specific match found will be used as the log level, // since the computation short circuits. // So, in increasing order of importance: - // Default < Broad Tag < File < Class < Function < Narrow Tag - ((site.mNarrowTag != NULL) ? checkLevelMap(s.tagLevelMap, site.mNarrowTag, compareLevel) : false) - || checkLevelMap(s.functionLevelMap, function_name, compareLevel) - || checkLevelMap(s.classLevelMap, class_name, compareLevel) - || checkLevelMap(s.fileLevelMap, abbreviateFile(site.mFile), compareLevel) - || ((site.mBroadTag != NULL) ? checkLevelMap(s.tagLevelMap, site.mBroadTag, compareLevel) : false); + // Default < Tags < File < Class < Function + checkLevelMap(s.mFunctionLevelMap, function_name, compareLevel) + || checkLevelMap(s.mClassLevelMap, class_name, compareLevel) + || checkLevelMap(s.mFileLevelMap, abbreviateFile(site.mFile), compareLevel) + || (site.mTagCount > 0 + ? checkLevelMap(s.mTagLevelMap, site.mTags, site.mTagCount, compareLevel) + : false); site.mCached = true; g.addCallSite(site); @@ -1016,6 +1132,7 @@ namespace LLError } Globals& g = Globals::get(); + if (out == &g.messageStream) { g.messageStream.clear(); @@ -1054,56 +1171,21 @@ namespace LLError if (site.mLevel == LEVEL_ERROR) { - std::ostringstream fatalMessage; - fatalMessage << abbreviateFile(site.mFile) - << "(" << site.mLine << ") : error"; - - writeToRecorders(site.mLevel, fatalMessage.str()); - } - - - std::ostringstream prefix; - - switch (site.mLevel) - { - case LEVEL_DEBUG: prefix << "DEBUG: "; break; - case LEVEL_INFO: prefix << "INFO: "; break; - case LEVEL_WARN: prefix << "WARNING: "; break; - case LEVEL_ERROR: prefix << "ERROR: "; break; - default: prefix << "XXX: "; break; - }; - - if (s.printLocation) - { - prefix << abbreviateFile(site.mFile) - << "(" << site.mLine << ") : "; + writeToRecorders(site, "error", true, true, true, false, false); } - #if LL_WINDOWS - // DevStudio: __FUNCTION__ already includes the full class name - #else - #if LL_LINUX - // gross, but typeid comparison seems to always fail here with gcc4.1 - if (0 != strcmp(site.mClassInfo.name(), typeid(NoClassInfo).name())) - #else - if (site.mClassInfo != typeid(NoClassInfo)) - #endif // LL_LINUX - { - prefix << className(site.mClassInfo) << "::"; - } - #endif - prefix << site.mFunction << ": "; + std::ostringstream message_stream; if (site.mPrintOnce) { - std::map<std::string, unsigned int>::iterator messageIter = s.uniqueLogMessages.find(message); - if (messageIter != s.uniqueLogMessages.end()) + std::map<std::string, unsigned int>::iterator messageIter = s.mUniqueLogMessages.find(message); + if (messageIter != s.mUniqueLogMessages.end()) { messageIter->second++; unsigned int num_messages = messageIter->second; if (num_messages == 10 || num_messages == 50 || (num_messages % 100) == 0) { - prefix << "ONCE (" << num_messages << "th time seen): "; + message_stream << "ONCE (" << num_messages << "th time seen): "; } else { @@ -1112,26 +1194,22 @@ namespace LLError } else { - prefix << "ONCE: "; - s.uniqueLogMessages[message] = 1; + message_stream << "ONCE: "; + s.mUniqueLogMessages[message] = 1; } } - prefix << message; - message = prefix.str(); + message_stream << message; - writeToRecorders(site.mLevel, message); + writeToRecorders(site, message_stream.str()); - if (site.mLevel == LEVEL_ERROR && s.crashFunction) + if (site.mLevel == LEVEL_ERROR && s.mCrashFunction) { - s.crashFunction(message); + s.mCrashFunction(message_stream.str()); } } } - - - namespace LLError { Settings* saveAndResetSettings() @@ -1188,7 +1266,7 @@ namespace LLError int shouldLogCallCount() { Settings& s = Settings::get(); - return s.shouldLogCallCounter; + return s.mShouldLogCallCounter; } #if LL_WINDOWS @@ -1376,13 +1454,13 @@ namespace LLError if(sIndex > 0) { - llinfos << " ************* PRINT OUT LL CALL STACKS ************* " << llendl ; + LL_INFOS() << " ************* PRINT OUT LL CALL STACKS ************* " << LL_ENDL; while(sIndex > 0) { sIndex-- ; - llinfos << sBuffer[sIndex] << llendl ; + LL_INFOS() << sBuffer[sIndex] << LL_ENDL; } - llinfos << " *************** END OF LL CALL STACKS *************** " << llendl ; + LL_INFOS() << " *************** END OF LL CALL STACKS *************** " << LL_ENDL; } if(sBuffer) @@ -1399,26 +1477,5 @@ namespace LLError sIndex = 0 ; } -#if LL_WINDOWS - void LLOutputDebugUTF8(const std::string& s) - { - // Be careful when calling OutputDebugString as it throws DBG_PRINTEXCEPTION_C - // which works just fine under the windows debugger, but can cause users who - // have enabled SEHOP exception chain validation to crash due to interactions - // between the Win 32-bit exception handling and boost coroutine fiber stacks. BUG-2707 - // - if (IsDebuggerPresent()) - { - // Need UTF16 for Unicode OutputDebugString - // - if (s.size()) - { - OutputDebugString(utf8str_to_utf16str(s).c_str()); - OutputDebugString(TEXT("\n")); - } - } - } -#endif - } diff --git a/indra/llcommon/llerror.h b/indra/llcommon/llerror.h index 0b723aeb5d..bc80e64423 100755 --- a/indra/llcommon/llerror.h +++ b/indra/llcommon/llerror.h @@ -31,9 +31,68 @@ #include <sstream> #include <typeinfo> -#include "llerrorlegacy.h" #include "stdtypes.h" +#include "llpreprocessor.h" +#include <boost/static_assert.hpp> + +const int LL_ERR_NOERR = 0; + +// Define one of these for different error levels in release... +// #define RELEASE_SHOW_DEBUG // Define this if you want your release builds to show lldebug output. +#define RELEASE_SHOW_INFO // Define this if you want your release builds to show llinfo output +#define RELEASE_SHOW_WARN // Define this if you want your release builds to show llwarn output. + +#ifdef _DEBUG +#define SHOW_DEBUG +#define SHOW_WARN +#define SHOW_INFO +#define SHOW_ASSERT +#else // _DEBUG + +#ifdef LL_RELEASE_WITH_DEBUG_INFO +#define SHOW_ASSERT +#endif // LL_RELEASE_WITH_DEBUG_INFO + +#ifdef RELEASE_SHOW_DEBUG +#define SHOW_DEBUG +#endif + +#ifdef RELEASE_SHOW_WARN +#define SHOW_WARN +#endif + +#ifdef RELEASE_SHOW_INFO +#define SHOW_INFO +#endif + +#ifdef RELEASE_SHOW_ASSERT +#define SHOW_ASSERT +#endif + +#endif // !_DEBUG + +#define llassert_always_msg(func, msg) if (LL_UNLIKELY(!(func))) LL_ERRS() << "ASSERT (" << msg << ")" << LL_ENDL + +#define llassert_always(func) llassert_always_msg(func, #func) + +#ifdef SHOW_ASSERT +#define llassert(func) llassert_always_msg(func, #func) +#define llverify(func) llassert_always_msg(func, #func) +#else +#define llassert(func) +#define llverify(func) do {if (func) {}} while(0) +#endif + +#ifdef LL_WINDOWS +#define LL_STATIC_ASSERT(func, msg) static_assert(func, msg) +#define LL_BAD_TEMPLATE_INSTANTIATION(type, msg) static_assert(false, msg) +#else +#define LL_STATIC_ASSERT(func, msg) BOOST_STATIC_ASSERT(func) +#define LL_BAD_TEMPLATE_INSTANTIATION(type, msg) BOOST_STATIC_ASSERT(sizeof(type) != 0 && false); +#endif + + /** Error Logging Facility Information for most users: @@ -121,50 +180,62 @@ namespace LLError They are not intended for general use. */ - class CallSite; + struct CallSite; class LL_COMMON_API Log { public: static bool shouldLog(CallSite&); static std::ostringstream* out(); - static void flush(std::ostringstream* out, char* message) ; + static void flush(std::ostringstream* out, char* message); static void flush(std::ostringstream*, const CallSite&); }; - class LL_COMMON_API CallSite + struct LL_COMMON_API CallSite { // Represents a specific place in the code where a message is logged // This is public because it is used by the macros below. It is not // intended for public use. - public: - CallSite(ELevel, const char* file, int line, - const std::type_info& class_info, const char* function, const char* broadTag, const char* narrowTag, bool printOnce); - + CallSite(ELevel level, + const char* file, + int line, + const std::type_info& class_info, + const char* function, + bool print_once, + const char** tags, + size_t tag_count); + + ~CallSite(); + #ifdef LL_LIBRARY_INCLUDE bool shouldLog(); #else // LL_LIBRARY_INCLUDE bool shouldLog() - { return mCached ? mShouldLog : Log::shouldLog(*this); } + { + return mCached + ? mShouldLog + : Log::shouldLog(*this); + } // this member function needs to be in-line for efficiency #endif // LL_LIBRARY_INCLUDE void invalidate(); - private: // these describe the call site and never change const ELevel mLevel; const char* const mFile; - const int mLine; - const std::type_info& mClassInfo; + const int mLine; + const std::type_info& mClassInfo; const char* const mFunction; - const char* const mBroadTag; - const char* const mNarrowTag; - const bool mPrintOnce; - - // these implement a cache of the call to shouldLog() - bool mCached; - bool mShouldLog; + const char** mTags; + size_t mTagCount; + const bool mPrintOnce; + const char* mLevelString; + std::string mLocationString, + mFunctionString, + mTagString; + bool mCached, + mShouldLog; friend class Log; }; @@ -198,32 +269,23 @@ namespace LLError static void clear() ; static void end(std::ostringstream* _out) ; }; - -#if LL_WINDOWS - void LLOutputDebugUTF8(const std::string& s); -#endif - } -#if LL_WINDOWS - // Macro accepting a std::string for display in windows debugging console - #define LL_WINDOWS_OUTPUT_DEBUG(a) LLError::LLOutputDebugUTF8(a) -#else - #define LL_WINDOWS_OUTPUT_DEBUG(a) -#endif - //this is cheaper than llcallstacks if no need to output other variables to call stacks. -#define llpushcallstacks LLError::LLCallStacks::push(__FUNCTION__, __LINE__) -#define llcallstacks \ - {\ +#define LL_PUSH_CALLSTACKS() LLError::LLCallStacks::push(__FUNCTION__, __LINE__) + +#define llcallstacks \ + { \ std::ostringstream* _out = LLError::LLCallStacks::insert(__FUNCTION__, __LINE__) ; \ (*_out) -#define llcallstacksendl \ - LLError::End(); \ + +#define llcallstacksendl \ + LLError::End(); \ LLError::LLCallStacks::end(_out) ; \ } -#define llclearcallstacks LLError::LLCallStacks::clear() -#define llprintcallstacks LLError::LLCallStacks::print() + +#define LL_CLEAR_CALLSTACKS() LLError::LLCallStacks::clear() +#define LL_PRINT_CALLSTACKS() LLError::LLCallStacks::print() /* Class type information for logging @@ -237,78 +299,72 @@ typedef LLError::NoClassInfo _LL_CLASS_TO_LOG; // Outside a class declaration, or in class without LOG_CLASS(), this // typedef causes the messages to not be associated with any class. +///////////////////////////////// +// Error Logging Macros +// See top of file for common usage. +///////////////////////////////// +// this macro uses a one-shot do statement to avoid parsing errors when writing control flow statements +// without braces: +// if (condition) LL_INFOS() << "True" << LL_ENDL; else LL_INFOS()() << "False" << LL_ENDL +#define lllog(level, once, ...) \ + do { \ + const char* tags[] = {"", ##__VA_ARGS__}; \ + ::size_t tag_count = LL_ARRAY_SIZE(tags) - 1; \ + static LLError::CallSite _site( \ + level, __FILE__, __LINE__, typeid(_LL_CLASS_TO_LOG), __FUNCTION__, once, &tags[1], tag_count);\ + if (LL_UNLIKELY(_site.shouldLog())) \ + { \ + std::ostringstream* _out = LLError::Log::out(); \ + (*_out) +//Use this construct if you need to do computation in the middle of a +//message: +// +// LL_INFOS("AgentGesture") << "the agent " << agend_id; +// switch (f) +// { +// case FOP_SHRUGS: LL_CONT << "shrugs"; break; +// case FOP_TAPS: LL_CONT << "points at " << who; break; +// case FOP_SAYS: LL_CONT << "says " << message; break; +// } +// LL_CONT << " for " << t << " seconds" << LL_ENDL; +// +//Such computation is done iff the message will be logged. +#define LL_CONT (*_out) -/* - Error Logging Macros - See top of file for common usage. -*/ - -#define lllog(level, broadTag, narrowTag, once) \ - do { \ - static LLError::CallSite _site( \ - level, __FILE__, __LINE__, typeid(_LL_CLASS_TO_LOG), __FUNCTION__, broadTag, narrowTag, once);\ - if (LL_UNLIKELY(_site.shouldLog())) \ - { \ - std::ostringstream* _out = LLError::Log::out(); \ - (*_out) +#define LL_NEWLINE '\n' -// DEPRECATED: Don't call directly, use LL_ENDL instead, which actually looks like a macro -#define llendl \ - LLError::End(); \ +#define LL_ENDL \ + LLError::End(); \ LLError::Log::flush(_out, _site); \ - } \ + } \ } while(0) -// DEPRECATED: Use the new macros that allow tags and *look* like macros. -#define lldebugs lllog(LLError::LEVEL_DEBUG, NULL, NULL, false) -#define llinfos lllog(LLError::LEVEL_INFO, NULL, NULL, false) -#define llwarns lllog(LLError::LEVEL_WARN, NULL, NULL, false) -#define llerrs lllog(LLError::LEVEL_ERROR, NULL, NULL, false) -#define llcont (*_out) - // NEW Macros for debugging, allow the passing of a string tag -// One Tag -#define LL_DEBUGS(broadTag) lllog(LLError::LEVEL_DEBUG, broadTag, NULL, false) -#define LL_INFOS(broadTag) lllog(LLError::LEVEL_INFO, broadTag, NULL, false) -#define LL_WARNS(broadTag) lllog(LLError::LEVEL_WARN, broadTag, NULL, false) -#define LL_ERRS(broadTag) lllog(LLError::LEVEL_ERROR, broadTag, NULL, false) -// Two Tags -#define LL_DEBUGS2(broadTag, narrowTag) lllog(LLError::LEVEL_DEBUG, broadTag, narrowTag, false) -#define LL_INFOS2(broadTag, narrowTag) lllog(LLError::LEVEL_INFO, broadTag, narrowTag, false) -#define LL_WARNS2(broadTag, narrowTag) lllog(LLError::LEVEL_WARN, broadTag, narrowTag, false) -#define LL_ERRS2(broadTag, narrowTag) lllog(LLError::LEVEL_ERROR, broadTag, narrowTag, false) +// Pass comma separated list of tags (currently only supports up to 0, 1, or 2) +#define LL_DEBUGS(...) lllog(LLError::LEVEL_DEBUG, false, ##__VA_ARGS__) +#define LL_INFOS(...) lllog(LLError::LEVEL_INFO, false, ##__VA_ARGS__) +#define LL_WARNS(...) lllog(LLError::LEVEL_WARN, false, ##__VA_ARGS__) +#define LL_ERRS(...) lllog(LLError::LEVEL_ERROR, false, ##__VA_ARGS__) +// alternative to llassert_always that prints explanatory message +#define LL_ERRS_IF(exp, ...) if (exp) LL_ERRS(##__VA_ARGS__) << "(" #exp ")" // Only print the log message once (good for warnings or infos that would otherwise // spam the log file over and over, such as tighter loops). -#define LL_DEBUGS_ONCE(broadTag) lllog(LLError::LEVEL_DEBUG, broadTag, NULL, true) -#define LL_INFOS_ONCE(broadTag) lllog(LLError::LEVEL_INFO, broadTag, NULL, true) -#define LL_WARNS_ONCE(broadTag) lllog(LLError::LEVEL_WARN, broadTag, NULL, true) -#define LL_DEBUGS2_ONCE(broadTag, narrowTag) lllog(LLError::LEVEL_DEBUG, broadTag, narrowTag, true) -#define LL_INFOS2_ONCE(broadTag, narrowTag) lllog(LLError::LEVEL_INFO, broadTag, narrowTag, true) -#define LL_WARNS2_ONCE(broadTag, narrowTag) lllog(LLError::LEVEL_WARN, broadTag, narrowTag, true) - -#define LL_ENDL llendl -#define LL_CONT (*_out) +#define LL_DEBUGS_ONCE(...) lllog(LLError::LEVEL_DEBUG, true, ##__VA_ARGS__) +#define LL_INFOS_ONCE(...) lllog(LLError::LEVEL_INFO, true, ##__VA_ARGS__) +#define LL_WARNS_ONCE(...) lllog(LLError::LEVEL_WARN, true, ##__VA_ARGS__) - /* - Use this construct if you need to do computation in the middle of a - message: - - LL_INFOS("AgentGesture") << "the agent " << agend_id; - switch (f) - { - case FOP_SHRUGS: LL_CONT << "shrugs"; break; - case FOP_TAPS: LL_CONT << "points at " << who; break; - case FOP_SAYS: LL_CONT << "says " << message; break; - } - LL_CONT << " for " << t << " seconds" << LL_ENDL; - - Such computation is done iff the message will be logged. - */ +// DEPRECATED: Use the new macros that allow tags and *look* like macros. +#define lldebugs LL_COMPILE_TIME_MESSAGE("Warning: lldebugs deprecated, use LL_DEBUGS() instead") LL_DEBUGS() +#define llinfos LL_COMPILE_TIME_MESSAGE("Warning: llinfos deprecated, use LL_INFOS() instead") LL_INFOS() +#define llwarns LL_COMPILE_TIME_MESSAGE("Warning: llwarns deprecated, use LL_WARNS() instead") LL_WARNS() +#define llerrs LL_COMPILE_TIME_MESSAGE("Warning: llerrs deprecated, use LL_ERRS() instead") LL_ERRS() +#define llcont LL_COMPILE_TIME_MESSAGE("Warning: llcont deprecated, use LL_CONT instead") LL_CONT +#define llendl LL_COMPILE_TIME_MESSAGE("Warning: llendl deprecated, use LL_ENDL instead") LL_ENDL #endif // LL_LLERROR_H diff --git a/indra/llcommon/llerrorcontrol.h b/indra/llcommon/llerrorcontrol.h index 480654b1a2..aab695094c 100755 --- a/indra/llcommon/llerrorcontrol.h +++ b/indra/llcommon/llerrorcontrol.h @@ -136,14 +136,24 @@ namespace LLError { // An object that handles the actual output or error messages. public: + Recorder(); virtual ~Recorder(); virtual void recordMessage(LLError::ELevel, const std::string& message) = 0; // use the level for better display, not for filtering - virtual bool wantsTime(); // default returns false - // override and return true if the recorder wants the time string - // included in the text of the message + bool wantsTime(); + bool wantsTags(); + bool wantsLevel(); + bool wantsLocation(); + bool wantsFunctionName(); + + protected: + bool mWantsTime, + mWantsTags, + mWantsLevel, + mWantsLocation, + mWantsFunctionName; }; /** diff --git a/indra/llcommon/llerrorlegacy.h b/indra/llcommon/llerrorlegacy.h index 37cee579cd..31dd207008 100755 --- a/indra/llcommon/llerrorlegacy.h +++ b/indra/llcommon/llerrorlegacy.h @@ -28,91 +28,5 @@ #ifndef LL_LLERRORLEGACY_H #define LL_LLERRORLEGACY_H -#include "llpreprocessor.h" - -/* - LEGACY -- DO NOT USE THIS STUFF ANYMORE -*/ - -// Specific error codes -const int LL_ERR_NOERR = 0; -const int LL_ERR_ASSET_REQUEST_FAILED = -1; -//const int LL_ERR_ASSET_REQUEST_INVALID = -2; -const int LL_ERR_ASSET_REQUEST_NONEXISTENT_FILE = -3; -const int LL_ERR_ASSET_REQUEST_NOT_IN_DATABASE = -4; -const int LL_ERR_INSUFFICIENT_PERMISSIONS = -5; -const int LL_ERR_EOF = -39; -const int LL_ERR_CANNOT_OPEN_FILE = -42; -const int LL_ERR_FILE_NOT_FOUND = -43; -const int LL_ERR_FILE_EMPTY = -44; -const int LL_ERR_TCP_TIMEOUT = -23016; -const int LL_ERR_CIRCUIT_GONE = -23017; -const int LL_ERR_PRICE_MISMATCH = -23018; - - - -// Define one of these for different error levels in release... -// #define RELEASE_SHOW_DEBUG // Define this if you want your release builds to show lldebug output. -#define RELEASE_SHOW_INFO // Define this if you want your release builds to show llinfo output -#define RELEASE_SHOW_WARN // Define this if you want your release builds to show llwarn output. - - -////////////////////////////////////////// -// -// Implementation - ignore -// -// -#ifdef _DEBUG -#define SHOW_DEBUG -#define SHOW_WARN -#define SHOW_INFO -#define SHOW_ASSERT -#else // _DEBUG - -#ifdef LL_RELEASE_WITH_DEBUG_INFO -#define SHOW_ASSERT -#endif // LL_RELEASE_WITH_DEBUG_INFO - -#ifdef RELEASE_SHOW_DEBUG -#define SHOW_DEBUG -#endif - -#ifdef RELEASE_SHOW_WARN -#define SHOW_WARN -#endif - -#ifdef RELEASE_SHOW_INFO -#define SHOW_INFO -#endif - -#ifdef RELEASE_SHOW_ASSERT -#define SHOW_ASSERT -#endif - -#endif // _DEBUG - - - -#define lldebugst(type) lldebugs -#define llendflush llendl - - -#define llerror(msg, num) llerrs << "Error # " << num << ": " << msg << llendl; - -#define llwarning(msg, num) llwarns << "Warning # " << num << ": " << msg << llendl; - -#define llassert_always(func) if (LL_UNLIKELY(!(func))) llerrs << "ASSERT (" << #func << ")" << llendl; - -#ifdef SHOW_ASSERT -#define llassert(func) llassert_always(func) -#define llverify(func) llassert_always(func) -#else -#define llassert(func) -#define llverify(func) do {if (func) {}} while(0) -#endif - -// handy compile-time assert - enforce those template parameters! -#define cassert(expn) typedef char __C_ASSERT__[(expn)?1:-1] /* Flawfinder: ignore */ - //XXX: used in two places in llcommon/llskipmap.h #endif // LL_LLERRORLEGACY_H diff --git a/indra/llcommon/llerrorthread.cpp b/indra/llcommon/llerrorthread.cpp index 950fcd6e83..f6bc68b5c1 100755 --- a/indra/llcommon/llerrorthread.cpp +++ b/indra/llcommon/llerrorthread.cpp @@ -65,7 +65,7 @@ void get_child_status(const int waitpid_status, int &process_status, bool &exite exited = true; if (do_logging) { - llinfos << "get_child_status - Child exited cleanly with return of " << process_status << llendl; + LL_INFOS() << "get_child_status - Child exited cleanly with return of " << process_status << LL_ENDL; } return; } @@ -75,15 +75,15 @@ void get_child_status(const int waitpid_status, int &process_status, bool &exite exited = true; if (do_logging) { - llinfos << "get_child_status - Child died because of uncaught signal " << process_status << llendl; + LL_INFOS() << "get_child_status - Child died because of uncaught signal " << process_status << LL_ENDL; #ifdef WCOREDUMP if (WCOREDUMP(waitpid_status)) { - llinfos << "get_child_status - Child dumped core" << llendl; + LL_INFOS() << "get_child_status - Child dumped core" << LL_ENDL; } else { - llinfos << "get_child_status - Child didn't dump core" << llendl; + LL_INFOS() << "get_child_status - Child didn't dump core" << LL_ENDL; } #endif } @@ -93,7 +93,7 @@ void get_child_status(const int waitpid_status, int &process_status, bool &exite { // This is weird. I just dump the waitpid status into the status code, // not that there's any way of telling what it is... - llinfos << "get_child_status - Got SIGCHILD but child didn't exit" << llendl; + LL_INFOS() << "get_child_status - Got SIGCHILD but child didn't exit" << LL_ENDL; process_status = waitpid_status; } @@ -106,99 +106,28 @@ void LLErrorThread::run() // This thread sits and waits for the sole purpose // of waiting for the signal/exception handlers to flag the // application state as APP_STATUS_ERROR. - llinfos << "thread_error - Waiting for an error" << llendl; + LL_INFOS() << "thread_error - Waiting for an error" << LL_ENDL; S32 counter = 0; -#if !LL_WINDOWS - U32 last_sig_child_count = 0; -#endif while (! (LLApp::isError() || LLApp::isStopped())) { -#if !LL_WINDOWS - // Check whether or not the main thread had a sig child we haven't handled. - U32 current_sig_child_count = LLApp::getSigChildCount(); - if (last_sig_child_count != current_sig_child_count) - { - int status = 0; - pid_t child_pid = 0; - last_sig_child_count = current_sig_child_count; - if (LLApp::sLogInSignal) - { - llinfos << "thread_error handling SIGCHLD #" << current_sig_child_count << llendl; - } - for (LLApp::child_map::iterator iter = LLApp::sChildMap.begin(); iter != LLApp::sChildMap.end();) - { - child_pid = iter->first; - LLChildInfo &child_info = iter->second; - // check the status of *all* children, in case we missed a signal - if (0 != waitpid(child_pid, &status, WNOHANG)) - { - bool exited = false; - int exit_status = -1; - get_child_status(status, exit_status, exited, LLApp::sLogInSignal); - - if (child_info.mCallback) - { - if (LLApp::sLogInSignal) - { - llinfos << "Signal handler - Running child callback" << llendl; - } - child_info.mCallback(child_pid, exited, status); - } - LLApp::sChildMap.erase(iter++); - } - else - { - // Child didn't terminate, yet we got a sigchild somewhere... - if (child_info.mGotSigChild && child_info.mCallback) - { - child_info.mCallback(child_pid, false, 0); - } - child_info.mGotSigChild = FALSE; - iter++; - } - } - - // check the status of *all* children, in case we missed a signal - // Same as above, but use the default child callback - while(0 < (child_pid = waitpid( -1, &status, WNOHANG ))) - { - if (0 != waitpid(child_pid, &status, WNOHANG)) - { - bool exited = false; - int exit_status = -1; - get_child_status(status, exit_status, exited, LLApp::sLogInSignal); - if (LLApp::sDefaultChildCallback) - { - if (LLApp::sLogInSignal) - { - llinfos << "Signal handler - Running default child callback" << llendl; - } - LLApp::sDefaultChildCallback(child_pid, true, status); - } - } - } - } - - -#endif ms_sleep(10); counter++; } if (LLApp::isError()) { // The app is in an error state, run the application's error handler. - //llinfos << "thread_error - An error has occurred, running error callback!" << llendl; + //LL_INFOS() << "thread_error - An error has occurred, running error callback!" << LL_ENDL; // Run the error handling callback LLApp::runErrorHandler(); } else { // Everything is okay, a clean exit. - //llinfos << "thread_error - Application exited cleanly" << llendl; + //LL_INFOS() << "thread_error - Application exited cleanly" << LL_ENDL; } - //llinfos << "thread_error - Exiting" << llendl; + //LL_INFOS() << "thread_error - Exiting" << LL_ENDL; LLApp::sErrorThreadRunning = FALSE; } diff --git a/indra/llcommon/llevent.h b/indra/llcommon/llevent.h index 8cd682b8bf..28ce7de102 100755 --- a/indra/llcommon/llevent.h +++ b/indra/llcommon/llevent.h @@ -29,8 +29,8 @@ #define LL_EVENT_H #include "llsd.h" +#include "llrefcount.h" #include "llpointer.h" -#include "llthread.h" namespace LLOldEvents { diff --git a/indra/llcommon/llevents.cpp b/indra/llcommon/llevents.cpp index 0855180dcd..1c928b3db8 100755 --- a/indra/llcommon/llevents.cpp +++ b/indra/llcommon/llevents.cpp @@ -41,7 +41,6 @@ #include <algorithm> // std headers #include <typeinfo> -#include <cassert> #include <cmath> #include <cctype> // external library headers diff --git a/indra/llcommon/llevents.h b/indra/llcommon/llevents.h index 65b0fef354..0cbd1da32d 100755 --- a/indra/llcommon/llevents.h +++ b/indra/llcommon/llevents.h @@ -61,7 +61,7 @@ #include "llsd.h" #include "llsingleton.h" #include "lldependencies.h" -#include "ll_template_cast.h" +#include "llstl.h" /*==========================================================================*| // override this to allow binding free functions with more parameters diff --git a/indra/llcommon/llextendedstatus.h b/indra/llcommon/llextendedstatus.h deleted file mode 100755 index 8ce173d1ff..0000000000 --- a/indra/llcommon/llextendedstatus.h +++ /dev/null @@ -1,67 +0,0 @@ -/** - * @file llextendedstatus.h - * @date August 2007 - * @brief extended status codes for curl/vfs/resident asset storage and delivery - * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_LLEXTENDEDSTATUS_H -#define LL_LLEXTENDEDSTATUS_H - - -typedef S32 LLExtStat; - - -// Status provider groups - Top bits indicate which status type it is -// Zero is common status code (next section) -const LLExtStat LL_EXSTAT_CURL_RESULT = 1L<<30; // serviced by curl - use 1L if we really implement the below -const LLExtStat LL_EXSTAT_RES_RESULT = 2L<<30; // serviced by resident copy -const LLExtStat LL_EXSTAT_VFS_RESULT = 3L<<30; // serviced by vfs - - -// Common Status Codes -// -const LLExtStat LL_EXSTAT_NONE = 0x00000; // No extra info here - sorry! -const LLExtStat LL_EXSTAT_NULL_UUID = 0x10001; // null asset ID -const LLExtStat LL_EXSTAT_NO_UPSTREAM = 0x10002; // attempt to upload without a valid upstream method/provider -const LLExtStat LL_EXSTAT_REQUEST_DROPPED = 0x10003; // request was dropped unserviced -const LLExtStat LL_EXSTAT_NONEXISTENT_FILE = 0x10004; // trying to upload a file that doesn't exist -const LLExtStat LL_EXSTAT_BLOCKED_FILE = 0x10005; // trying to upload a file that we can't open - - -// curl status codes: -// -// Mask off LL_EXSTAT_CURL_RESULT for original result and -// see: libraries/include/curl/curl.h - - -// Memory-Resident status codes: -// None at present - - -// VFS status codes: -const LLExtStat LL_EXSTAT_VFS_CACHED = LL_EXSTAT_VFS_RESULT | 0x0001; -const LLExtStat LL_EXSTAT_VFS_CORRUPT = LL_EXSTAT_VFS_RESULT | 0x0002; - - -#endif // LL_LLEXTENDEDSTATUS_H diff --git a/indra/llcommon/llfasttimer.cpp b/indra/llcommon/llfasttimer.cpp index 58db7d0d17..3d28cd15b0 100755 --- a/indra/llcommon/llfasttimer.cpp +++ b/indra/llcommon/llfasttimer.cpp @@ -32,8 +32,13 @@ #include "llsingleton.h" #include "lltreeiterators.h" #include "llsdserialize.h" +#include "llunits.h" +#include "llsd.h" +#include "lltracerecording.h" +#include "lltracethreadrecorder.h" #include <boost/bind.hpp> +#include <queue> #if LL_WINDOWS @@ -49,140 +54,115 @@ #error "architecture not supported" #endif +namespace LLTrace +{ + ////////////////////////////////////////////////////////////////////////////// // statics -S32 LLFastTimer::sCurFrameIndex = -1; -S32 LLFastTimer::sLastFrameIndex = -1; -U64 LLFastTimer::sLastFrameTime = LLFastTimer::getCPUClockCount64(); -bool LLFastTimer::sPauseHistory = 0; -bool LLFastTimer::sResetHistory = 0; -LLFastTimer::CurTimerData LLFastTimer::sCurTimerData; -BOOL LLFastTimer::sLog = FALSE; -std::string LLFastTimer::sLogName = ""; -BOOL LLFastTimer::sMetricLog = FALSE; -LLMutex* LLFastTimer::sLogLock = NULL; -std::queue<LLSD> LLFastTimer::sLogQueue; +bool BlockTimer::sLog = false; +std::string BlockTimer::sLogName = ""; +bool BlockTimer::sMetricLog = false; #if LL_LINUX || LL_SOLARIS -U64 LLFastTimer::sClockResolution = 1000000000; // Nanosecond resolution +U64 BlockTimer::sClockResolution = 1000000000; // Nanosecond resolution #else -U64 LLFastTimer::sClockResolution = 1000000; // Microsecond resolution +U64 BlockTimer::sClockResolution = 1000000; // Microsecond resolution #endif -// FIXME: move these declarations to the relevant modules - -// helper functions -typedef LLTreeDFSPostIter<LLFastTimer::NamedTimer, LLFastTimer::NamedTimer::child_const_iter> timer_tree_bottom_up_iterator_t; +static LLMutex* sLogLock = NULL; +static std::queue<LLSD> sLogQueue; -static timer_tree_bottom_up_iterator_t begin_timer_tree_bottom_up(LLFastTimer::NamedTimer& id) +block_timer_tree_df_iterator_t begin_block_timer_tree_df(BlockTimerStatHandle& id) { - return timer_tree_bottom_up_iterator_t(&id, - boost::bind(boost::mem_fn(&LLFastTimer::NamedTimer::beginChildren), _1), - boost::bind(boost::mem_fn(&LLFastTimer::NamedTimer::endChildren), _1)); + return block_timer_tree_df_iterator_t(&id, + boost::bind(boost::mem_fn(&BlockTimerStatHandle::beginChildren), _1), + boost::bind(boost::mem_fn(&BlockTimerStatHandle::endChildren), _1)); } -static timer_tree_bottom_up_iterator_t end_timer_tree_bottom_up() +block_timer_tree_df_iterator_t end_block_timer_tree_df() { - return timer_tree_bottom_up_iterator_t(); + return block_timer_tree_df_iterator_t(); } -typedef LLTreeDFSIter<LLFastTimer::NamedTimer, LLFastTimer::NamedTimer::child_const_iter> timer_tree_dfs_iterator_t; - +block_timer_tree_df_post_iterator_t begin_block_timer_tree_df_post(BlockTimerStatHandle& id) +{ + return block_timer_tree_df_post_iterator_t(&id, + boost::bind(boost::mem_fn(&BlockTimerStatHandle::beginChildren), _1), + boost::bind(boost::mem_fn(&BlockTimerStatHandle::endChildren), _1)); +} -static timer_tree_dfs_iterator_t begin_timer_tree(LLFastTimer::NamedTimer& id) +block_timer_tree_df_post_iterator_t end_block_timer_tree_df_post() { - return timer_tree_dfs_iterator_t(&id, - boost::bind(boost::mem_fn(&LLFastTimer::NamedTimer::beginChildren), _1), - boost::bind(boost::mem_fn(&LLFastTimer::NamedTimer::endChildren), _1)); + return block_timer_tree_df_post_iterator_t(); } -static timer_tree_dfs_iterator_t end_timer_tree() +block_timer_tree_bf_iterator_t begin_block_timer_tree_bf(BlockTimerStatHandle& id) { - return timer_tree_dfs_iterator_t(); + return block_timer_tree_bf_iterator_t(&id, + boost::bind(boost::mem_fn(&BlockTimerStatHandle::beginChildren), _1), + boost::bind(boost::mem_fn(&BlockTimerStatHandle::endChildren), _1)); } -// factory class that creates NamedTimers via static DeclareTimer objects -class NamedTimerFactory : public LLSingleton<NamedTimerFactory> -{ -public: - NamedTimerFactory() - : mTimerRoot(new LLFastTimer::NamedTimer("root")) +block_timer_tree_bf_iterator_t end_block_timer_tree_bf() { - mRootFrameState.setNamedTimer(mTimerRoot); - mTimerRoot->setFrameState(&mRootFrameState); - mTimerRoot->mParent = mTimerRoot; - mTimerRoot->setCollapsed(false); - mRootFrameState.mParent = &mRootFrameState; + return block_timer_tree_bf_iterator_t(); } - ~NamedTimerFactory() +block_timer_tree_df_iterator_t begin_timer_tree(BlockTimerStatHandle& id) { - std::for_each(mTimers.begin(), mTimers.end(), DeletePairedPointer()); - mTimers.clear(); - - delete mTimerRoot; + return block_timer_tree_df_iterator_t(&id, + boost::bind(boost::mem_fn(&BlockTimerStatHandle::beginChildren), _1), + boost::bind(boost::mem_fn(&BlockTimerStatHandle::endChildren), _1)); } - LLFastTimer::NamedTimer& createNamedTimer(const std::string& name, LLFastTimer::FrameState* state) +block_timer_tree_df_iterator_t end_timer_tree() { - LLFastTimer::NamedTimer* timer = new LLFastTimer::NamedTimer(name); - timer->setFrameState(state); - timer->setParent(mTimerRoot); - mTimers.insert(std::make_pair(name, timer)); + return block_timer_tree_df_iterator_t(); +} - return *timer; - } - LLFastTimer::NamedTimer* getTimerByName(const std::string& name) +// sort child timers by name +struct SortTimerByName { - timer_map_t::iterator found_it = mTimers.find(name); - if (found_it != mTimers.end()) + bool operator()(const BlockTimerStatHandle* i1, const BlockTimerStatHandle* i2) { - return found_it->second; + return i1->getName() < i2->getName(); } - return NULL; - } - - LLFastTimer::NamedTimer* getRootTimer() { return mTimerRoot; } - - typedef std::multimap<std::string, LLFastTimer::NamedTimer*> timer_map_t; - timer_map_t::iterator beginTimers() { return mTimers.begin(); } - timer_map_t::iterator endTimers() { return mTimers.end(); } - S32 timerCount() { return mTimers.size(); } - -private: - timer_map_t mTimers; - - LLFastTimer::NamedTimer* mTimerRoot; - LLFastTimer::FrameState mRootFrameState; }; -LLFastTimer::DeclareTimer::DeclareTimer(const std::string& name, bool open ) -: mTimer(NamedTimerFactory::instance().createNamedTimer(name, &mFrameState)) +static BlockTimerStatHandle sRootTimer("root", NULL); +BlockTimerStatHandle& BlockTimer::getRootTimeBlock() { - mTimer.setCollapsed(!open); + return sRootTimer; + } + +void BlockTimer::pushLog(LLSD log) +{ + LLMutexLock lock(sLogLock); + + sLogQueue.push(log); } -LLFastTimer::DeclareTimer::DeclareTimer(const std::string& name) -: mTimer(NamedTimerFactory::instance().createNamedTimer(name, &mFrameState)) +void BlockTimer::setLogLock(LLMutex* lock) { + sLogLock = lock; } + //static #if (LL_DARWIN || LL_LINUX || LL_SOLARIS) && !(defined(__i386__) || defined(__amd64__)) -U64 LLFastTimer::countsPerSecond() // counts per second for the *32-bit* timer +U64 BlockTimer::countsPerSecond() { - return sClockResolution >> 8; + return sClockResolution; } #else // windows or x86-mac or x86-linux or x86-solaris -U64 LLFastTimer::countsPerSecond() // counts per second for the *32-bit* timer +U64 BlockTimer::countsPerSecond() { #if LL_FASTTIMER_USE_RDTSC || !LL_WINDOWS //getCPUFrequency returns MHz and sCPUClockFrequency wants to be in Hz - static U64 sCPUClockFrequency = U64(LLProcessorInfo().getCPUFrequency()*1000000.0); - - // we drop the low-order byte in our timers, so report a lower frequency + static LLUnit<U64, LLUnits::Hertz> sCPUClockFrequency = LLProcessorInfo().getCPUFrequency(); + return sCPUClockFrequency.value(); #else // If we're not using RDTSC, each fasttimer tick is just a performance counter tick. // Not redefining the clock frequency itself (in llprocessor.cpp/calculate_cpu_frequency()) @@ -194,270 +174,211 @@ U64 LLFastTimer::countsPerSecond() // counts per second for the *32-bit* timer QueryPerformanceFrequency((LARGE_INTEGER*)&sCPUClockFrequency); firstcall = false; } + return sCPUClockFrequency.value(); #endif - return sCPUClockFrequency >> 8; } #endif -LLFastTimer::FrameState::FrameState() -: mActiveCount(0), - mCalls(0), - mSelfTimeCounter(0), - mParent(NULL), - mLastCaller(NULL), - mMoveUpTree(false) +BlockTimerStatHandle::BlockTimerStatHandle(const char* name, const char* description) +: StatType<TimeBlockAccumulator>(name, description) {} - -LLFastTimer::NamedTimer::NamedTimer(const std::string& name) -: mName(name), - mCollapsed(true), - mParent(NULL), - mTotalTimeCounter(0), - mCountAverage(0), - mCallAverage(0), - mNeedsSorting(false), - mFrameState(NULL) +TimeBlockTreeNode& BlockTimerStatHandle::getTreeNode() const { - mCountHistory = new U32[HISTORY_NUM]; - memset(mCountHistory, 0, sizeof(U32) * HISTORY_NUM); - mCallHistory = new U32[HISTORY_NUM]; - memset(mCallHistory, 0, sizeof(U32) * HISTORY_NUM); + TimeBlockTreeNode* nodep = LLTrace::get_thread_recorder()->getTimeBlockTreeNode(getIndex()); + llassert(nodep); + return *nodep; } -LLFastTimer::NamedTimer::~NamedTimer() -{ - delete[] mCountHistory; - delete[] mCallHistory; -} -std::string LLFastTimer::NamedTimer::getToolTip(S32 history_idx) +void BlockTimer::bootstrapTimerTree() { - F64 ms_multiplier = 1000.0 / (F64)LLFastTimer::countsPerSecond(); - if (history_idx < 0) - { - // by default, show average number of call - return llformat("%s (%d ms, %d calls)", getName().c_str(), (S32)(getCountAverage() * ms_multiplier), (S32)getCallAverage()); - } - else + for (BlockTimerStatHandle::instance_tracker_t::instance_iter it = BlockTimerStatHandle::instance_tracker_t::beginInstances(), end_it = BlockTimerStatHandle::instance_tracker_t::endInstances(); + it != end_it; + ++it) { - return llformat("%s (%d ms, %d calls)", getName().c_str(), (S32)(getHistoricalCount(history_idx) * ms_multiplier), (S32)getHistoricalCalls(history_idx)); - } -} + BlockTimerStatHandle& timer = static_cast<BlockTimerStatHandle&>(*it); + if (&timer == &BlockTimer::getRootTimeBlock()) continue; -void LLFastTimer::NamedTimer::setParent(NamedTimer* parent) + // bootstrap tree construction by attaching to last timer to be on stack + // when this timer was called + if (timer.getParent() == &BlockTimer::getRootTimeBlock()) { - llassert_always(parent != this); - llassert_always(parent != NULL); + TimeBlockAccumulator& accumulator = timer.getCurrentAccumulator(); - if (mParent) + if (accumulator.mLastCaller) { - // subtract our accumulated from previous parent - for (S32 i = 0; i < HISTORY_NUM; i++) - { - mParent->mCountHistory[i] -= mCountHistory[i]; - } - - // subtract average timing from previous parent - mParent->mCountAverage -= mCountAverage; - - std::vector<NamedTimer*>& children = mParent->getChildren(); - std::vector<NamedTimer*>::iterator found_it = std::find(children.begin(), children.end(), this); - if (found_it != children.end()) - { - children.erase(found_it); + timer.setParent(accumulator.mLastCaller); + accumulator.mParent = accumulator.mLastCaller; } + // no need to push up tree on first use, flag can be set spuriously + accumulator.mMoveUpTree = false; } - - mParent = parent; - if (parent) - { - getFrameState().mParent = &parent->getFrameState(); - parent->getChildren().push_back(this); - parent->mNeedsSorting = true; } } -S32 LLFastTimer::NamedTimer::getDepth() +// bump timers up tree if they have been flagged as being in the wrong place +// do this in a bottom up order to promote descendants first before promoting ancestors +// this preserves partial order derived from current frame's observations +void BlockTimer::incrementalUpdateTimerTree() { - S32 depth = 0; - NamedTimer* timerp = mParent; - while(timerp) + for(block_timer_tree_df_post_iterator_t it = begin_block_timer_tree_df_post(BlockTimer::getRootTimeBlock()); + it != end_block_timer_tree_df_post(); + ++it) { - depth++; - if (timerp->getParent() == timerp) break; - timerp = timerp->mParent; - } - return depth; -} + BlockTimerStatHandle* timerp = *it; -// static -void LLFastTimer::NamedTimer::processTimes() + // sort timers by time last called, so call graph makes sense + TimeBlockTreeNode& tree_node = timerp->getTreeNode(); + if (tree_node.mNeedsSorting) { - if (sCurFrameIndex < 0) return; - - buildHierarchy(); - accumulateTimings(); + std::sort(tree_node.mChildren.begin(), tree_node.mChildren.end(), SortTimerByName()); } -// sort child timers by name -struct SortTimerByName + // skip root timer + if (timerp != &BlockTimer::getRootTimeBlock()) { - bool operator()(const LLFastTimer::NamedTimer* i1, const LLFastTimer::NamedTimer* i2) - { - return i1->getName() < i2->getName(); - } -}; + TimeBlockAccumulator& accumulator = timerp->getCurrentAccumulator(); -//static -void LLFastTimer::NamedTimer::buildHierarchy() + if (accumulator.mMoveUpTree) { - if (sCurFrameIndex < 0 ) return; - - // set up initial tree - { - for (instance_iter it = beginInstances(); it != endInstances(); ++it) - { - NamedTimer& timer = *it; - if (&timer == NamedTimerFactory::instance().getRootTimer()) continue; - - // bootstrap tree construction by attaching to last timer to be on stack - // when this timer was called - if (timer.getFrameState().mLastCaller && timer.mParent == NamedTimerFactory::instance().getRootTimer()) - { - timer.setParent(timer.getFrameState().mLastCaller->mTimer); - // no need to push up tree on first use, flag can be set spuriously - timer.getFrameState().mMoveUpTree = false; - } - } - } - - // bump timers up tree if they've been flagged as being in the wrong place - // do this in a bottom up order to promote descendants first before promoting ancestors - // this preserves partial order derived from current frame's observations - for(timer_tree_bottom_up_iterator_t it = begin_timer_tree_bottom_up(*NamedTimerFactory::instance().getRootTimer()); - it != end_timer_tree_bottom_up(); - ++it) - { - NamedTimer* timerp = *it; - // skip root timer - if (timerp == NamedTimerFactory::instance().getRootTimer()) continue; - - if (timerp->getFrameState().mMoveUpTree) - { - // since ancestors have already been visited, reparenting won't affect tree traversal + // since ancestors have already been visited, re-parenting won't affect tree traversal //step up tree, bringing our descendants with us LL_DEBUGS("FastTimers") << "Moving " << timerp->getName() << " from child of " << timerp->getParent()->getName() << " to child of " << timerp->getParent()->getParent()->getName() << LL_ENDL; timerp->setParent(timerp->getParent()->getParent()); - timerp->getFrameState().mMoveUpTree = false; + accumulator.mParent = timerp->getParent(); + accumulator.mMoveUpTree = false; // don't bubble up any ancestors until descendants are done bubbling up + // as ancestors may call this timer only on certain paths, so we want to resolve + // child-most block locations before their parents it.skipAncestors(); } } + } +} - // sort timers by time last called, so call graph makes sense - for(timer_tree_dfs_iterator_t it = begin_timer_tree(*NamedTimerFactory::instance().getRootTimer()); - it != end_timer_tree(); - ++it) + +void BlockTimer::updateTimes() { - NamedTimer* timerp = (*it); - if (timerp->mNeedsSorting) + // walk up stack of active timers and accumulate current time while leaving timing structures active + BlockTimerStackRecord* stack_record = LLThreadLocalSingletonPointer<BlockTimerStackRecord>::getInstance(); + if (!stack_record) return; + + U64 cur_time = getCPUClockCount64(); + BlockTimer* cur_timer = stack_record->mActiveTimer; + TimeBlockAccumulator* accumulator = &stack_record->mTimeBlock->getCurrentAccumulator(); + + while(cur_timer + && cur_timer->mParentTimerData.mActiveTimer != cur_timer) // root defined by parent pointing to self { - std::sort(timerp->getChildren().begin(), timerp->getChildren().end(), SortTimerByName()); - } - timerp->mNeedsSorting = false; + U64 cumulative_time_delta = cur_time - cur_timer->mStartTime; + cur_timer->mStartTime = cur_time; + + accumulator->mTotalTimeCounter += cumulative_time_delta; + accumulator->mSelfTimeCounter += cumulative_time_delta - stack_record->mChildTime; + stack_record->mChildTime = 0; + + stack_record = &cur_timer->mParentTimerData; + accumulator = &stack_record->mTimeBlock->getCurrentAccumulator(); + cur_timer = stack_record->mActiveTimer; + + stack_record->mChildTime += cumulative_time_delta; } } +static LLTrace::BlockTimerStatHandle FTM_PROCESS_TIMES("Process FastTimer Times"); + +// not thread safe, so only call on main thread //static -void LLFastTimer::NamedTimer::accumulateTimings() +void BlockTimer::processTimes() { - U32 cur_time = getCPUClockCount32(); +#if LL_TRACE_ENABLED + LL_RECORD_BLOCK_TIME(FTM_PROCESS_TIMES); + get_clock_count(); // good place to calculate clock frequency - // walk up stack of active timers and accumulate current time while leaving timing structures active - LLFastTimer* cur_timer = sCurTimerData.mCurTimer; - // root defined by parent pointing to self - CurTimerData* cur_data = &sCurTimerData; - while(cur_timer && cur_timer->mLastTimerData.mCurTimer != cur_timer) - { - U32 cumulative_time_delta = cur_time - cur_timer->mStartTime; - U32 self_time_delta = cumulative_time_delta - cur_data->mChildTime; - cur_data->mChildTime = 0; - cur_timer->mFrameState->mSelfTimeCounter += self_time_delta; - cur_timer->mStartTime = cur_time; + // set up initial tree + bootstrapTimerTree(); - cur_data = &cur_timer->mLastTimerData; - cur_data->mChildTime += cumulative_time_delta; + incrementalUpdateTimerTree(); - cur_timer = cur_timer->mLastTimerData.mCurTimer; - } + updateTimes(); - // traverse tree in DFS post order, or bottom up - for(timer_tree_bottom_up_iterator_t it = begin_timer_tree_bottom_up(*NamedTimerFactory::instance().getRootTimer()); - it != end_timer_tree_bottom_up(); + // reset for next frame + for (BlockTimerStatHandle::instance_tracker_t::instance_iter it = BlockTimerStatHandle::instance_tracker_t::beginInstances(), + end_it = BlockTimerStatHandle::instance_tracker_t::endInstances(); + it != end_it; ++it) { - NamedTimer* timerp = (*it); - timerp->mTotalTimeCounter = timerp->getFrameState().mSelfTimeCounter; - for (child_const_iter child_it = timerp->beginChildren(); child_it != timerp->endChildren(); ++child_it) + BlockTimerStatHandle& timer = static_cast<BlockTimerStatHandle&>(*it); + TimeBlockAccumulator& accumulator = timer.getCurrentAccumulator(); + + accumulator.mLastCaller = NULL; + accumulator.mMoveUpTree = false; + } +#endif +} + +std::vector<BlockTimerStatHandle*>::iterator BlockTimerStatHandle::beginChildren() { - timerp->mTotalTimeCounter += (*child_it)->mTotalTimeCounter; + return getTreeNode().mChildren.begin(); } - S32 cur_frame = sCurFrameIndex; - if (cur_frame >= 0) +std::vector<BlockTimerStatHandle*>::iterator BlockTimerStatHandle::endChildren() { - // update timer history - int hidx = cur_frame % HISTORY_NUM; + return getTreeNode().mChildren.end(); +} - timerp->mCountHistory[hidx] = timerp->mTotalTimeCounter; - timerp->mCountAverage = ((U64)timerp->mCountAverage * cur_frame + timerp->mTotalTimeCounter) / (cur_frame+1); - timerp->mCallHistory[hidx] = timerp->getFrameState().mCalls; - timerp->mCallAverage = ((U64)timerp->mCallAverage * cur_frame + timerp->getFrameState().mCalls) / (cur_frame+1); - } +std::vector<BlockTimerStatHandle*>& BlockTimerStatHandle::getChildren() +{ + return getTreeNode().mChildren; } + +bool BlockTimerStatHandle::hasChildren() +{ + return ! getTreeNode().mChildren.empty(); } // static -void LLFastTimer::NamedTimer::resetFrame() +void BlockTimer::logStats() { + // get ready for next frame if (sLog) { //output current frame counts to performance log static S32 call_count = 0; if (call_count % 100 == 0) { - LL_DEBUGS("FastTimers") << "countsPerSecond (32 bit): " << countsPerSecond() << LL_ENDL; - LL_DEBUGS("FastTimers") << "get_clock_count (64 bit): " << get_clock_count() << llendl; + LL_DEBUGS("FastTimers") << "countsPerSecond: " << countsPerSecond() << LL_ENDL; LL_DEBUGS("FastTimers") << "LLProcessorInfo().getCPUFrequency() " << LLProcessorInfo().getCPUFrequency() << LL_ENDL; LL_DEBUGS("FastTimers") << "getCPUClockCount32() " << getCPUClockCount32() << LL_ENDL; LL_DEBUGS("FastTimers") << "getCPUClockCount64() " << getCPUClockCount64() << LL_ENDL; - LL_DEBUGS("FastTimers") << "elapsed sec " << ((F64)getCPUClockCount64())/((F64)LLProcessorInfo().getCPUFrequency()*1000000.0) << LL_ENDL; + LL_DEBUGS("FastTimers") << "elapsed sec " << ((F64)getCPUClockCount64() / (F64HertzImplicit)LLProcessorInfo().getCPUFrequency()) << LL_ENDL; } call_count++; - F64 iclock_freq = 1000.0 / countsPerSecond(); // good place to calculate clock frequency - - F64 total_time = 0; + F64Seconds total_time(0); LLSD sd; { - for (instance_iter it = beginInstances(); it != endInstances(); ++it) + for (BlockTimerStatHandle::instance_tracker_t::instance_iter it = BlockTimerStatHandle::instance_tracker_t::beginInstances(), + end_it = BlockTimerStatHandle::instance_tracker_t::endInstances(); + it != end_it; + ++it) { - NamedTimer& timer = *it; - FrameState& info = timer.getFrameState(); - sd[timer.getName()]["Time"] = (LLSD::Real) (info.mSelfTimeCounter*iclock_freq); - sd[timer.getName()]["Calls"] = (LLSD::Integer) info.mCalls; + BlockTimerStatHandle& timer = static_cast<BlockTimerStatHandle&>(*it); + LLTrace::PeriodicRecording& frame_recording = LLTrace::get_frame_recording(); + sd[timer.getName()]["Time"] = (LLSD::Real) (frame_recording.getLastRecording().getSum(timer).value()); + sd[timer.getName()]["Calls"] = (LLSD::Integer) (frame_recording.getLastRecording().getSum(timer.callCount())); // computing total time here because getting the root timer's getCountHistory // doesn't work correctly on the first frame - total_time = total_time + info.mSelfTimeCounter * iclock_freq; + total_time += frame_recording.getLastRecording().getSum(timer); } } - sd["Total"]["Time"] = (LLSD::Real) total_time; + sd["Total"]["Time"] = (LLSD::Real) total_time.value(); sd["Total"]["Calls"] = (LLSD::Integer) 1; { @@ -466,168 +387,44 @@ void LLFastTimer::NamedTimer::resetFrame() } } - // reset for next frame - for (instance_iter it = beginInstances(); it != endInstances(); ++it) - { - NamedTimer& timer = *it; - - FrameState& info = timer.getFrameState(); - info.mSelfTimeCounter = 0; - info.mCalls = 0; - info.mLastCaller = NULL; - info.mMoveUpTree = false; - // update parent pointer in timer state struct - if (timer.mParent) - { - info.mParent = &timer.mParent->getFrameState(); - } - } -} - -//static -void LLFastTimer::NamedTimer::reset() -{ - resetFrame(); // reset frame data - - // walk up stack of active timers and reset start times to current time - // effectively zeroing out any accumulated time - U32 cur_time = getCPUClockCount32(); - - // root defined by parent pointing to self - CurTimerData* cur_data = &sCurTimerData; - LLFastTimer* cur_timer = cur_data->mCurTimer; - while(cur_timer && cur_timer->mLastTimerData.mCurTimer != cur_timer) - { - cur_timer->mStartTime = cur_time; - cur_data->mChildTime = 0; - - cur_data = &cur_timer->mLastTimerData; - cur_timer = cur_data->mCurTimer; - } - - // reset all history - { - for (instance_iter it = beginInstances(); it != endInstances(); ++it) - { - NamedTimer& timer = *it; - if (&timer != NamedTimerFactory::instance().getRootTimer()) - { - timer.setParent(NamedTimerFactory::instance().getRootTimer()); - } - - timer.mCountAverage = 0; - timer.mCallAverage = 0; - memset(timer.mCountHistory, 0, sizeof(U32) * HISTORY_NUM); - memset(timer.mCallHistory, 0, sizeof(U32) * HISTORY_NUM); - } - } - - sLastFrameIndex = 0; - sCurFrameIndex = 0; -} - -U32 LLFastTimer::NamedTimer::getHistoricalCount(S32 history_index) const -{ - S32 history_idx = (getLastFrameIndex() + history_index) % LLFastTimer::NamedTimer::HISTORY_NUM; - return mCountHistory[history_idx]; -} - -U32 LLFastTimer::NamedTimer::getHistoricalCalls(S32 history_index ) const -{ - S32 history_idx = (getLastFrameIndex() + history_index) % LLFastTimer::NamedTimer::HISTORY_NUM; - return mCallHistory[history_idx]; -} - -LLFastTimer::FrameState& LLFastTimer::NamedTimer::getFrameState() const -{ - return *mFrameState; -} - -std::vector<LLFastTimer::NamedTimer*>::const_iterator LLFastTimer::NamedTimer::beginChildren() -{ - return mChildren.begin(); -} - -std::vector<LLFastTimer::NamedTimer*>::const_iterator LLFastTimer::NamedTimer::endChildren() -{ - return mChildren.end(); -} - -std::vector<LLFastTimer::NamedTimer*>& LLFastTimer::NamedTimer::getChildren() -{ - return mChildren; -} - -//static -LLFastTimer::NamedTimer& LLFastTimer::NamedTimer::getRootNamedTimer() -{ - return *NamedTimerFactory::instance().getRootTimer(); -} - -//static -void LLFastTimer::nextFrame() -{ - countsPerSecond(); // good place to calculate clock frequency - U64 frame_time = getCPUClockCount64(); - if ((frame_time - sLastFrameTime) >> 8 > 0xffffffff) - { - llinfos << "Slow frame, fast timers inaccurate" << llendl; - } - - if (!sPauseHistory) - { - NamedTimer::processTimes(); - sLastFrameIndex = sCurFrameIndex++; - } - - // get ready for next frame - NamedTimer::resetFrame(); - sLastFrameTime = frame_time; } //static -void LLFastTimer::dumpCurTimes() +void BlockTimer::dumpCurTimes() { - // accumulate timings, etc. - NamedTimer::processTimes(); - - F64 clock_freq = (F64)countsPerSecond(); - F64 iclock_freq = 1000.0 / clock_freq; // clock_ticks -> milliseconds + LLTrace::PeriodicRecording& frame_recording = LLTrace::get_frame_recording(); + LLTrace::Recording& last_frame_recording = frame_recording.getLastRecording(); // walk over timers in depth order and output timings - for(timer_tree_dfs_iterator_t it = begin_timer_tree(*NamedTimerFactory::instance().getRootTimer()); + for(block_timer_tree_df_iterator_t it = begin_timer_tree(BlockTimer::getRootTimeBlock()); it != end_timer_tree(); ++it) { - NamedTimer* timerp = (*it); - F64 total_time_ms = ((F64)timerp->getHistoricalCount(0) * iclock_freq); + BlockTimerStatHandle* timerp = (*it); + F64Seconds total_time = last_frame_recording.getSum(*timerp); + U32 num_calls = last_frame_recording.getSum(timerp->callCount()); + // Don't bother with really brief times, keep output concise - if (total_time_ms < 0.1) continue; + if (total_time < F32Milliseconds(0.1f)) continue; std::ostringstream out_str; - for (S32 i = 0; i < timerp->getDepth(); i++) + BlockTimerStatHandle* parent_timerp = timerp; + while(parent_timerp && parent_timerp != parent_timerp->getParent()) { out_str << "\t"; + parent_timerp = parent_timerp->getParent(); } - out_str << timerp->getName() << " " - << std::setprecision(3) << total_time_ms << " ms, " - << timerp->getHistoricalCalls(0) << " calls"; + << std::setprecision(3) << total_time.valueInUnits<LLUnits::Milliseconds>() << " ms, " + << num_calls << " calls"; - llinfos << out_str.str() << llendl; - } + LL_INFOS() << out_str.str() << LL_ENDL; } - -//static -void LLFastTimer::reset() -{ - NamedTimer::reset(); } - //static -void LLFastTimer::writeLog(std::ostream& os) +void BlockTimer::writeLog(std::ostream& os) { while (!sLogQueue.empty()) { @@ -638,22 +435,57 @@ void LLFastTimer::writeLog(std::ostream& os) } } -//static -const LLFastTimer::NamedTimer* LLFastTimer::getTimerByName(const std::string& name) +////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +// TimeBlockAccumulator +////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +TimeBlockAccumulator::TimeBlockAccumulator() +: mTotalTimeCounter(0), + mSelfTimeCounter(0), + mCalls(0), + mLastCaller(NULL), + mActiveCount(0), + mMoveUpTree(false), + mParent(NULL) +{} + +void TimeBlockAccumulator::addSamples( const TimeBlockAccumulator& other, EBufferAppendType append_type ) { - return NamedTimerFactory::instance().getTimerByName(name); +#if LL_TRACE_ENABLED + // we can't merge two unrelated time block samples, as that will screw with the nested timings + // due to the call hierarchy of each thread + llassert(append_type == SEQUENTIAL); + mTotalTimeCounter += other.mTotalTimeCounter; + mSelfTimeCounter += other.mSelfTimeCounter; + mCalls += other.mCalls; + mLastCaller = other.mLastCaller; + mActiveCount = other.mActiveCount; + mMoveUpTree = other.mMoveUpTree; + mParent = other.mParent; +#endif } -LLFastTimer::LLFastTimer(LLFastTimer::FrameState* state) -: mFrameState(state) +void TimeBlockAccumulator::reset( const TimeBlockAccumulator* other ) +{ + mCalls = 0; + mSelfTimeCounter = 0; + mTotalTimeCounter = 0; + + if (other) { - U32 start_time = getCPUClockCount32(); - mStartTime = start_time; - mFrameState->mActiveCount++; - LLFastTimer::sCurTimerData.mCurTimer = this; - LLFastTimer::sCurTimerData.mFrameState = mFrameState; - LLFastTimer::sCurTimerData.mChildTime = 0; - mLastTimerData = LLFastTimer::sCurTimerData; + mLastCaller = other->mLastCaller; + mActiveCount = other->mActiveCount; + mMoveUpTree = other->mMoveUpTree; + mParent = other->mParent; + } +} + +F64Seconds BlockTimer::getElapsedTime() +{ + U64 total_time = getCPUClockCount64() - mStartTime; + + return F64Seconds((F64)total_time / (F64)BlockTimer::countsPerSecond()); } +} // namespace LLTrace diff --git a/indra/llcommon/llfasttimer.h b/indra/llcommon/llfasttimer.h index a99a1d88af..2370253078 100755 --- a/indra/llcommon/llfasttimer.h +++ b/indra/llcommon/llfasttimer.h @@ -28,218 +28,30 @@ #define LL_FASTTIMER_H #include "llinstancetracker.h" +#include "lltrace.h" +#include "lltreeiterators.h" -#define FAST_TIMER_ON 1 -#define DEBUG_FAST_TIMER_THREADS 1 - -class LLMutex; - -#include <queue> -#include "llsd.h" - +#define LL_FAST_TIMER_ON 1 #define LL_FASTTIMER_USE_RDTSC 1 +#define LL_RECORD_BLOCK_TIME(timer_stat) const LLTrace::BlockTimer& LL_GLUE_TOKENS(block_time_recorder, __LINE__)(LLTrace::timeThisBlock(timer_stat)); (void)LL_GLUE_TOKENS(block_time_recorder, __LINE__); -LL_COMMON_API void assert_main_thread(); - -class LL_COMMON_API LLFastTimer +namespace LLTrace { -public: - class NamedTimer; - - struct LL_COMMON_API FrameState - { - FrameState(); - void setNamedTimer(NamedTimer* timerp) { mTimer = 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 - }; - - // 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 = 300 }; - - 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(); - - void setFrameState(FrameState* state) { mFrameState = state; state->setNamedTimer(this); } - 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 - // - FrameState* mFrameState; - - 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 > - { - friend class LLFastTimer; - public: - - DeclareTimer(const std::string& name, bool open); - DeclareTimer(const std::string& name); - - NamedTimer& getNamedTimer() { return mTimer; } - - private: - FrameState mFrameState; - NamedTimer& mTimer; - }; - -public: - LLFastTimer(LLFastTimer::FrameState* state); - - LL_FORCE_INLINE LLFastTimer(LLFastTimer::DeclareTimer& timer) - : mFrameState(&timer.mFrameState) - { -#if FAST_TIMER_ON - LLFastTimer::FrameState* frame_state = mFrameState; - mStartTime = getCPUClockCount32(); - - 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); - - LLFastTimer::CurTimerData* cur_timer_data = &LLFastTimer::sCurTimerData; - mLastTimerData = *cur_timer_data; - cur_timer_data->mCurTimer = this; - cur_timer_data->mFrameState = frame_state; - cur_timer_data->mChildTime = 0; -#endif -#if DEBUG_FAST_TIMER_THREADS -#if !LL_RELEASE - assert_main_thread(); -#endif -#endif - } - - LL_FORCE_INLINE ~LLFastTimer() - { -#if FAST_TIMER_ON - LLFastTimer::FrameState* frame_state = mFrameState; - U32 total_time = getCPUClockCount32() - mStartTime; - - frame_state->mSelfTimeCounter += total_time - LLFastTimer::sCurTimerData.mChildTime; - frame_state->mActiveCount--; - - // store last caller to bootstrap tree creation - // do this in the destructor in case of recursion to get topmost caller - frame_state->mLastCaller = mLastTimerData.mFrameState; - - // we are only tracking self time, so subtract our total time delta from parents - mLastTimerData.mChildTime += total_time; - - LLFastTimer::sCurTimerData = mLastTimerData; -#endif - } +// use to create blocktimer rvalue to be captured in a reference so that the BlockTimer lives to the end of the block. +class BlockTimer timeThisBlock(class BlockTimerStatHandle& timer); +class BlockTimer +{ public: - static LLMutex* sLogLock; - static std::queue<LLSD> sLogQueue; - static BOOL sLog; - static BOOL sMetricLog; - static std::string sLogName; - static bool sPauseHistory; - static bool sResetHistory; - - // call this once a frame to reset timers - static void nextFrame(); + typedef BlockTimer self_t; + typedef class BlockTimerStatHandle DeclareTimer; - // dumps current cumulative frame stats to log - // call nextFrame() to reset timers - static void dumpCurTimes(); + ~BlockTimer(); - // call this to reset timer hierarchy, averages, etc. - static void reset(); + F64Seconds getElapsedTime(); - 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); - - struct CurTimerData - { - LLFastTimer* mCurTimer; - FrameState* mFrameState; - U32 mChildTime; - }; - static CurTimerData sCurTimerData; - -private: - - - ////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////// // // Important note: These implementations must be FAST! // @@ -261,14 +73,14 @@ private: //#undef _interlockedbittestandset //#undef _interlockedbittestandreset - //inline U32 LLFastTimer::getCPUClockCount32() + //inline U32 getCPUClockCount32() //{ // U64 time_stamp = __rdtsc(); // return (U32)(time_stamp >> 8); //} // //// return full timer value, *not* shifted by 8 bits - //inline U64 LLFastTimer::getCPUClockCount64() + //inline U64 getCPUClockCount64() //{ // return __rdtsc(); //} @@ -308,7 +120,7 @@ private: } #else - //LL_COMMON_API U64 get_clock_count(); // in lltimer.cpp + //U64 get_clock_count(); // in lltimer.cpp // These use QueryPerformanceCounter, which is arguably fine and also works on AMD architectures. static U32 getCPUClockCount32() { @@ -375,18 +187,160 @@ private: #endif - static U64 sClockResolution; + static BlockTimerStatHandle& getRootTimeBlock(); + static void pushLog(LLSD sd); + static void setLogLock(class LLMutex* mutex); + static void writeLog(std::ostream& os); + static void updateTimes(); + + static U64 countsPerSecond(); + + // updates cumulative times and hierarchy, + // can be called multiple times in a frame, at any point + static void processTimes(); - static S32 sCurFrameIndex; - static S32 sLastFrameIndex; - static U64 sLastFrameTime; + static void bootstrapTimerTree(); + static void incrementalUpdateTimerTree(); - U32 mStartTime; - LLFastTimer::FrameState* mFrameState; - LLFastTimer::CurTimerData mLastTimerData; + // call this once a frame to periodically log timers + static void logStats(); + + // dumps current cumulative frame stats to log + // call nextFrame() to reset timers + static void dumpCurTimes(); + +private: + friend class BlockTimerStatHandle; + // FIXME: this friendship exists so that each thread can instantiate a root timer, + // which could be a derived class with a public constructor instead, possibly + friend class ThreadRecorder; + friend BlockTimer timeThisBlock(BlockTimerStatHandle&); + + BlockTimer(BlockTimerStatHandle& timer); +#if !defined(MSC_VER) || MSC_VER < 1700 + // Visual Studio 2010 has a bug where capturing an object returned by value + // into a local reference requires access to the copy constructor at the call site. + // This appears to be fixed in 2012. +public: +#endif + // no-copy + BlockTimer(const BlockTimer& other) {}; + +private: + U64 mStartTime; + BlockTimerStackRecord mParentTimerData; + +public: + // statics + static std::string sLogName; + static bool sMetricLog, + sLog; + static U64 sClockResolution; }; -typedef class LLFastTimer LLFastTimer; +// this dummy function assists in allocating a block timer with stack-based lifetime. +// this is done by capturing the return value in a stack-allocated const reference variable. +// (This is most easily done using the macro LL_RECORD_BLOCK_TIME) +// Otherwise, it would be possible to store a BlockTimer on the heap, resulting in non-nested lifetimes, +// which would break the invariants of the timing hierarchy logic +LL_FORCE_INLINE class BlockTimer timeThisBlock(class BlockTimerStatHandle& timer) +{ + return BlockTimer(timer); +} + +// stores a "named" timer instance to be reused via multiple BlockTimer stack instances +class BlockTimerStatHandle +: public StatType<TimeBlockAccumulator> +{ +public: + BlockTimerStatHandle(const char* name, const char* description = ""); + + TimeBlockTreeNode& getTreeNode() const; + BlockTimerStatHandle* getParent() const { return getTreeNode().getParent(); } + void setParent(BlockTimerStatHandle* parent) { getTreeNode().setParent(parent); } + + typedef std::vector<BlockTimerStatHandle*>::iterator child_iter; + typedef std::vector<BlockTimerStatHandle*>::const_iterator child_const_iter; + child_iter beginChildren(); + child_iter endChildren(); + bool hasChildren(); + std::vector<BlockTimerStatHandle*>& getChildren(); + + StatType<TimeBlockAccumulator::CallCountFacet>& callCount() + { + return static_cast<StatType<TimeBlockAccumulator::CallCountFacet>&>(*(StatType<TimeBlockAccumulator>*)this); + } + + StatType<TimeBlockAccumulator::SelfTimeFacet>& selfTime() + { + return static_cast<StatType<TimeBlockAccumulator::SelfTimeFacet>&>(*(StatType<TimeBlockAccumulator>*)this); + } + + bool mCollapsed; // don't show children +}; + +// iterators and helper functions for walking the call hierarchy of block timers in different ways +typedef LLTreeDFSIter<BlockTimerStatHandle, BlockTimerStatHandle::child_const_iter> block_timer_tree_df_iterator_t; +typedef LLTreeDFSPostIter<BlockTimerStatHandle, BlockTimerStatHandle::child_const_iter> block_timer_tree_df_post_iterator_t; +typedef LLTreeBFSIter<BlockTimerStatHandle, BlockTimerStatHandle::child_const_iter> block_timer_tree_bf_iterator_t; + +block_timer_tree_df_iterator_t begin_block_timer_tree_df(BlockTimerStatHandle& id); +block_timer_tree_df_iterator_t end_block_timer_tree_df(); +block_timer_tree_df_post_iterator_t begin_block_timer_tree_df_post(BlockTimerStatHandle& id); +block_timer_tree_df_post_iterator_t end_block_timer_tree_df_post(); +block_timer_tree_bf_iterator_t begin_block_timer_tree_bf(BlockTimerStatHandle& id); +block_timer_tree_bf_iterator_t end_block_timer_tree_bf(); + +LL_FORCE_INLINE BlockTimer::BlockTimer(BlockTimerStatHandle& timer) +{ +#if LL_FAST_TIMER_ON + BlockTimerStackRecord* cur_timer_data = LLThreadLocalSingletonPointer<BlockTimerStackRecord>::getInstance(); + if (!cur_timer_data) return; + TimeBlockAccumulator& accumulator = timer.getCurrentAccumulator(); + accumulator.mActiveCount++; + // keep current parent as long as it is active when we are + accumulator.mMoveUpTree |= (accumulator.mParent->getCurrentAccumulator().mActiveCount == 0); + + // store top of stack + mParentTimerData = *cur_timer_data; + // push new information + cur_timer_data->mActiveTimer = this; + cur_timer_data->mTimeBlock = &timer; + cur_timer_data->mChildTime = 0; + + mStartTime = getCPUClockCount64(); +#endif +} + +LL_FORCE_INLINE BlockTimer::~BlockTimer() +{ +#if LL_FAST_TIMER_ON + U64 total_time = getCPUClockCount64() - mStartTime; + BlockTimerStackRecord* cur_timer_data = LLThreadLocalSingletonPointer<BlockTimerStackRecord>::getInstance(); + if (!cur_timer_data) return; + + TimeBlockAccumulator& accumulator = cur_timer_data->mTimeBlock->getCurrentAccumulator(); + + accumulator.mCalls++; + accumulator.mTotalTimeCounter += total_time; + accumulator.mSelfTimeCounter += total_time - cur_timer_data->mChildTime; + accumulator.mActiveCount--; + + // store last caller to bootstrap tree creation + // do this in the destructor in case of recursion to get topmost caller + accumulator.mLastCaller = mParentTimerData.mTimeBlock; + + // we are only tracking self time, so subtract our total time delta from parents + mParentTimerData.mChildTime += total_time; + + //pop stack + *cur_timer_data = mParentTimerData; +#endif +} + +} + +typedef LLTrace::BlockTimer LLFastTimer; #endif // LL_LLFASTTIMER_H diff --git a/indra/llcommon/llfile.cpp b/indra/llcommon/llfile.cpp index c3a0f0bfe0..259187c52f 100755 --- a/indra/llcommon/llfile.cpp +++ b/indra/llcommon/llfile.cpp @@ -28,7 +28,7 @@ */ #if LL_WINDOWS -#include <windows.h> +#include "llwin32headerslean.h" #include <stdlib.h> // Windows errno #else #include <errno.h> @@ -265,6 +265,37 @@ int LLFile::rename(const std::string& filename, const std::string& newname) return warnif(STRINGIZE("rename to '" << newname << "' from"), filename, rc); } +bool LLFile::copy(const std::string from, const std::string to) +{ + bool copied = false; + LLFILE* in = LLFile::fopen(from, "rb"); /* Flawfinder: ignore */ + if (in) + { + LLFILE* out = LLFile::fopen(to, "wb"); /* Flawfinder: ignore */ + if (out) + { + char buf[16384]; /* Flawfinder: ignore */ + size_t readbytes; + bool write_ok = true; + while(write_ok && (readbytes = fread(buf, 1, 16384, in))) /* Flawfinder: ignore */ + { + if (fwrite(buf, 1, readbytes, out) != readbytes) + { + LL_WARNS("LLFile") << "Short write" << LL_ENDL; + write_ok = false; + } + } + if ( write_ok ) + { + copied = true; + } + fclose(out); + } + fclose(in); + } + return copied; +} + int LLFile::stat(const std::string& filename, llstat* filestatus) { #if LL_WINDOWS @@ -438,7 +469,7 @@ llstdio_filebuf::int_type llstdio_filebuf::overflow(llstdio_filebuf::int_type __ _M_set_buffer(0); __ret = traits_type::not_eof(__c); } - } + } else if (_M_buf_size > 1) { // Overflow in 'uncommitted' mode: set _M_writing, set @@ -496,11 +527,11 @@ bool llstdio_filebuf::_convert_to_external(char_type* __ibuf, if (__r == codecvt_base::ok || __r == codecvt_base::partial) __blen = __bend - __buf; else if (__r == codecvt_base::noconv) - { + { // Same as the always_noconv case above. __buf = reinterpret_cast<char*>(__ibuf); __blen = __ilen; - } + } else __throw_ios_failure(__N("llstdio_filebuf::_convert_to_external " "conversion error")); @@ -643,9 +674,9 @@ llstdio_filebuf::int_type llstdio_filebuf::underflow() _M_ext_end, _M_ext_next, this->eback(), this->eback() + __buflen, __iend); -} + } if (__r == codecvt_base::noconv) -{ + { size_t __avail = _M_ext_end - _M_ext_buf; __ilen = std::min(__avail, __buflen); traits_type::copy(this->eback(), @@ -806,15 +837,15 @@ std::streamsize llstdio_filebuf::xsputn(char_type* __s, std::streamsize __n) __ret = fwrite(__buf, 1, __buffill, _M_file.file()); } if (__ret == __buffill) - { + { __ret += fwrite(reinterpret_cast<const char*>(__s), 1, __n, _M_file.file()); - } + } if (__ret == __buffill + __n) { _M_set_buffer(0); _M_writing = true; -} + } if (__ret > __buffill) __ret -= __buffill; else @@ -848,7 +879,7 @@ llifstream::llifstream() : _M_filebuf(), #endif // explicit -llifstream::llifstream(const std::string& _Filename, +llifstream::llifstream(const std::string& _Filename, ios_base::openmode _Mode) : _M_filebuf(), #if LL_WINDOWS std::istream(&_M_filebuf) @@ -877,7 +908,7 @@ llifstream::llifstream(const char* _Filename, if (_M_filebuf.open(wideName.c_str(), _Mode | ios_base::in) == 0) { _Myios::setstate(ios_base::failbit); -} + } } #else std::istream() @@ -951,8 +982,8 @@ void llifstream::close() #else this->setstate(ios_base::failbit); #endif - } } +} /************** output file stream ********************************/ @@ -1042,7 +1073,7 @@ void llofstream::open(const char* _Filename, ios_base::openmode _Mode) #if LL_WINDOWS llutf16string wideName = utf8str_to_utf16str( _Filename ); if (_M_filebuf.open( wideName.c_str(), _Mode | ios_base::out) == 0) -{ + { _Myios::setstate(ios_base::failbit); } else diff --git a/indra/llcommon/llfile.h b/indra/llcommon/llfile.h index d59e68367e..f56b22bf9a 100755 --- a/indra/llcommon/llfile.h +++ b/indra/llcommon/llfile.h @@ -75,6 +75,8 @@ public: static int rmdir(const std::string& filename); static int remove(const std::string& filename); static int rename(const std::string& filename,const std::string& newname); + static bool copy(const std::string from, const std::string to); + static int stat(const std::string& filename,llstat* file_status); static bool isdir(const std::string& filename); static bool isfile(const std::string& filename); diff --git a/indra/llcommon/llfindlocale.cpp b/indra/llcommon/llfindlocale.cpp index cd7c0c7c09..f019bd0c64 100755 --- a/indra/llcommon/llfindlocale.cpp +++ b/indra/llcommon/llfindlocale.cpp @@ -33,7 +33,7 @@ #include <ctype.h> #ifdef WIN32 -#include <windows.h> +#include "llwin32headers.h" #include <winnt.h> #endif diff --git a/indra/llcommon/llfoldertype.cpp b/indra/llcommon/llfoldertype.cpp deleted file mode 100755 index f6d0f5bce8..0000000000 --- a/indra/llcommon/llfoldertype.cpp +++ /dev/null @@ -1,168 +0,0 @@ -/** - * @file llfoldertype.cpp - * @brief Implementatino of LLFolderType functionality. - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#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(); -protected: - virtual LLFolderType::EType notFound() const - { - return LLFolderType::FT_NONE; - } -}; - -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_ROOT_INVENTORY, new FolderEntry("root_inv", 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_MESH, new FolderEntry("mesh", TRUE)); - - addEntry(LLFolderType::FT_INBOX, new FolderEntry("inbox", TRUE)); - addEntry(LLFolderType::FT_OUTBOX, new FolderEntry("outbox", TRUE)); - addEntry(LLFolderType::FT_BASIC_ROOT, new FolderEntry("basic_rt", 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 deleted file mode 100644 index a0c847914f..0000000000 --- a/indra/llcommon/llfoldertype.h +++ /dev/null @@ -1,111 +0,0 @@ -/** - * @file llfoldertype.h - * @brief Declaration of LLFolderType. - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef 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_CLOTHING = 5, - - FT_OBJECT = 6, - - FT_NOTECARD = 7, - - FT_ROOT_INVENTORY = 8, - // We'd really like to change this to 9 since AT_CATEGORY is 8, - // but "My Inventory" has been type 8 for a long time. - - FT_LSL_TEXT = 10, - - FT_BODYPART = 13, - - FT_TRASH = 14, - - FT_SNAPSHOT_CATEGORY = 15, - - FT_LOST_AND_FOUND = 16, - - FT_ANIMATION = 20, - - FT_GESTURE = 21, - - 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_MESH = 49, - - FT_INBOX = 50, - FT_OUTBOX = 51, - - FT_BASIC_ROOT = 52, - - FT_COUNT, - - 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/llformat.h b/indra/llcommon/llformat.h index a4ec5e01de..fb8e7cd045 100755 --- a/indra/llcommon/llformat.h +++ b/indra/llcommon/llformat.h @@ -29,7 +29,7 @@ #define LL_LLFORMAT_H // Use as follows: -// llinfos << llformat("Test:%d (%.2f %.2f)", idx, x, y) << llendl; +// LL_INFOS() << llformat("Test:%d (%.2f %.2f)", idx, x, y) << LL_ENDL; // // *NOTE: buffer limited to 1024, (but vsnprintf prevents overrun) // should perhaps be replaced with boost::format. diff --git a/indra/llcommon/llframetimer.cpp b/indra/llcommon/llframetimer.cpp index ec64195b21..1af2cb8afd 100755 --- a/indra/llcommon/llframetimer.cpp +++ b/indra/llcommon/llframetimer.cpp @@ -115,10 +115,10 @@ F64 LLFrameTimer::expiresAt() const BOOL LLFrameTimer::checkExpirationAndReset(F32 expiration) { - //llinfos << "LLFrameTimer::checkExpirationAndReset()" << llendl; - //llinfos << " mStartTime:" << mStartTime << llendl; - //llinfos << " sFrameTime:" << sFrameTime << llendl; - //llinfos << " mExpiry: " << mExpiry << llendl; + //LL_INFOS() << "LLFrameTimer::checkExpirationAndReset()" << LL_ENDL; + //LL_INFOS() << " mStartTime:" << mStartTime << LL_ENDL; + //LL_INFOS() << " sFrameTime:" << sFrameTime << LL_ENDL; + //LL_INFOS() << " mExpiry: " << mExpiry << LL_ENDL; if(hasExpired()) { diff --git a/indra/llcommon/llframetimer.h b/indra/llcommon/llframetimer.h index 45754f3785..81bd5da8a3 100755 --- a/indra/llcommon/llframetimer.h +++ b/indra/llcommon/llframetimer.h @@ -35,7 +35,6 @@ */ #include "lltimer.h" -#include "timing.h" class LL_COMMON_API LLFrameTimer { @@ -44,7 +43,7 @@ public: // Return the number of seconds since the start of this // application instance. - static F64 getElapsedSeconds() + static F64SecondsImplicit getElapsedSeconds() { // Loses msec precision after ~4.5 hours... return sFrameTime; @@ -53,7 +52,7 @@ public: // Return a low precision usec since epoch static U64 getTotalTime() { - return sTotalTime ? sTotalTime : totalTime(); + return sTotalTime ? U64MicrosecondsImplicit(sTotalTime) : totalTime(); } // Return a low precision seconds since epoch diff --git a/indra/llcommon/llheartbeat.cpp b/indra/llcommon/llheartbeat.cpp index 18a0c489bd..19b7452748 100755 --- a/indra/llcommon/llheartbeat.cpp +++ b/indra/llcommon/llheartbeat.cpp @@ -98,7 +98,7 @@ LLHeartbeat::rawSendWithTimeout(F32 timeout_sec) mTimeoutTimer.setTimerExpirySec(timeout_sec); do { result = rawSend(); - //llinfos << " HEARTSENDc=" << result << llendl; + //LL_INFOS() << " HEARTSENDc=" << result << LL_ENDL; } while (result==1 && !mTimeoutTimer.hasExpired()); return result; @@ -118,7 +118,7 @@ LLHeartbeat::send(F32 timeout_sec) // zero-timeout; we don't care too much whether our // heartbeat was digested. result = rawSend(); - //llinfos << " HEARTSENDb=" << result << llendl; + //LL_INFOS() << " HEARTSENDb=" << result << LL_ENDL; } } @@ -146,14 +146,14 @@ LLHeartbeat::send(F32 timeout_sec) // It's been ages since we successfully had a heartbeat // digested by the watchdog. Sit here and spin a while // in the hope that we can force it through. - llwarns << "Unable to deliver heartbeat to launcher for " << mPanicTimer.getElapsedTimeF32() << " seconds. Going to try very hard for up to " << mAggressiveHeartbeatMaxBlockingSecs << " seconds." << llendl; + LL_WARNS() << "Unable to deliver heartbeat to launcher for " << mPanicTimer.getElapsedTimeF32() << " seconds. Going to try very hard for up to " << mAggressiveHeartbeatMaxBlockingSecs << " seconds." << LL_ENDL; result = rawSendWithTimeout(mAggressiveHeartbeatMaxBlockingSecs); if (result == 0) { total_success = true; } else { // we couldn't even force it through. That's bad, // but we'll try again in a while. - llwarns << "Could not deliver heartbeat to launcher even after trying very hard for " << mAggressiveHeartbeatMaxBlockingSecs << " seconds." << llendl; + LL_WARNS() << "Could not deliver heartbeat to launcher even after trying very hard for " << mAggressiveHeartbeatMaxBlockingSecs << " seconds." << LL_ENDL; } // in any case, reset the panic timer. diff --git a/indra/llcommon/llindexedqueue.h b/indra/llcommon/llindexedqueue.h deleted file mode 100755 index aa2675d87d..0000000000 --- a/indra/llcommon/llindexedqueue.h +++ /dev/null @@ -1,155 +0,0 @@ -/** - * @file llindexedqueue.h - * @brief An indexed FIFO queue, where only one element with each key - * can be in the queue. - * - * $LicenseInfo:firstyear=2003&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_LLINDEXEDQUEUE_H -#define LL_LLINDEXEDQUEUE_H - -// An indexed FIFO queue, where only one element with each key can be in the queue. -// This is ONLY used in the interest list, you'll probably want to review this code -// carefully if you want to use it elsewhere - Doug - -template <typename Type> -class LLIndexedQueue -{ -protected: - typedef std::deque<Type> type_deque; - type_deque mQueue; - std::set<Type> mKeySet; - -public: - LLIndexedQueue() {} - - // move_if_there is an O(n) operation - bool push_back(const Type &value, bool move_if_there = false) - { - if (mKeySet.find(value) != mKeySet.end()) - { - // Already on the queue - if (move_if_there) - { - // Remove the existing entry. - typename type_deque::iterator it; - for (it = mQueue.begin(); it != mQueue.end(); ++it) - { - if (*it == value) - { - break; - } - } - - // This HAS to succeed, otherwise there's a serious bug in the keyset implementation - // (although this isn't thread safe, at all) - - mQueue.erase(it); - } - else - { - // We're not moving it, leave it alone - return false; - } - } - else - { - // Doesn't exist, add it to the key set - mKeySet.insert(value); - } - - mQueue.push_back(value); - - // We succeeded in adding the new element. - return true; - } - - bool push_front(const Type &value, bool move_if_there = false) - { - if (mKeySet.find(value) != mKeySet.end()) - { - // Already on the queue - if (move_if_there) - { - // Remove the existing entry. - typename type_deque::iterator it; - for (it = mQueue.begin(); it != mQueue.end(); ++it) - { - if (*it == value) - { - break; - } - } - - // This HAS to succeed, otherwise there's a serious bug in the keyset implementation - // (although this isn't thread safe, at all) - - mQueue.erase(it); - } - else - { - // We're not moving it, leave it alone - return false; - } - } - else - { - // Doesn't exist, add it to the key set - mKeySet.insert(value); - } - - mQueue.push_front(value); - return true; - } - - void pop() - { - Type value = mQueue.front(); - mKeySet.erase(value); - mQueue.pop_front(); - } - - Type &front() - { - return mQueue.front(); - } - - S32 size() const - { - return mQueue.size(); - } - - bool empty() const - { - return mQueue.empty(); - } - - void clear() - { - // Clear out all elements on the queue - mQueue.clear(); - mKeySet.clear(); - } -}; - -#endif // LL_LLINDEXEDQUEUE_H diff --git a/indra/llcommon/llindexedvector.h b/indra/llcommon/llindexedvector.h new file mode 100755 index 0000000000..68c3821802 --- /dev/null +++ b/indra/llcommon/llindexedvector.h @@ -0,0 +1,100 @@ +/** + * @file lldarray.h + * @brief Wrapped std::vector for backward compatibility. + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLDARRAY_H +#define LL_LLDARRAY_H + +#include "llerror.h" + +#include <vector> +#include <map> + +//-------------------------------------------------------- +// LLIndexedVector +//-------------------------------------------------------- + +template <typename Type, typename Key, int BlockSize = 32> +class LLIndexedVector +{ +public: + typedef typename std::vector<Type>::iterator iterator; + typedef typename std::vector<Type>::const_iterator const_iterator; + typedef typename std::vector<Type>::reverse_iterator reverse_iterator; + typedef typename std::vector<Type>::const_reverse_iterator const_reverse_iterator; + typedef typename std::vector<Type>::size_type size_type; +protected: + std::vector<Type> mVector; + std::map<Key, U32> mIndexMap; + +public: + LLIndexedVector() { mVector.reserve(BlockSize); } + + iterator begin() { return mVector.begin(); } + const_iterator begin() const { return mVector.begin(); } + iterator end() { return mVector.end(); } + const_iterator end() const { return mVector.end(); } + + reverse_iterator rbegin() { return mVector.rbegin(); } + const_reverse_iterator rbegin() const { return mVector.rbegin(); } + reverse_iterator rend() { return mVector.rend(); } + const_reverse_iterator rend() const { return mVector.rend(); } + + void reset() { mVector.resize(0); mIndexMap.resize(0); } + bool empty() const { return mVector.empty(); } + size_type size() const { return mVector.size(); } + + Type& operator[](const Key& k) + { + typename std::map<Key, U32>::const_iterator iter = mIndexMap.find(k); + if (iter == mIndexMap.end()) + { + U32 n = mVector.size(); + mIndexMap[k] = n; + mVector.push_back(Type()); + llassert(mVector.size() == mIndexMap.size()); + return mVector[n]; + } + else + { + return mVector[iter->second]; + } + } + + const_iterator find(const Key& k) const + { + typename std::map<Key, U32>::const_iterator iter = mIndexMap.find(k); + if(iter == mIndexMap.end()) + { + return mVector.end(); + } + else + { + return mVector.begin() + iter->second; + } + } +}; + +#endif diff --git a/indra/llcommon/llinitparam.cpp b/indra/llcommon/llinitparam.cpp index 89c831d296..aa2f4eb289 100755 --- a/indra/llcommon/llinitparam.cpp +++ b/indra/llcommon/llinitparam.cpp @@ -28,10 +28,17 @@ #include "linden_common.h" #include "llinitparam.h" +#include "llformat.h" namespace LLInitParam { + + predicate_rule_t default_parse_rules() + { + return ll_make_predicate(PROVIDED) && !ll_make_predicate(EMPTY); + } + // // Param // @@ -93,13 +100,13 @@ namespace LLInitParam void Parser::parserWarning(const std::string& message) { if (mParseSilently) return; - llwarns << message << llendl; + LL_WARNS() << message << LL_ENDL; } void Parser::parserError(const std::string& message) { if (mParseSilently) return; - llerrs << message << llendl; + LL_ERRS() << message << LL_ENDL; } @@ -124,7 +131,7 @@ namespace LLInitParam std::string name(char_name); if ((size_t)param->mParamHandle > mMaxParamOffset) { - llerrs << "Attempted to register param with block defined for parent class, make sure to derive from LLInitParam::Block<YOUR_CLASS, PARAM_BLOCK_BASE_CLASS>" << llendl; + LL_ERRS() << "Attempted to register param with block defined for parent class, make sure to derive from LLInitParam::Block<YOUR_CLASS, PARAM_BLOCK_BASE_CLASS>" << LL_ENDL; } if (name.empty()) @@ -196,6 +203,9 @@ namespace LLInitParam bool BaseBlock::validateBlock(bool emit_errors) const { + // only validate block when it hasn't already passed validation with current data + if (!mValidated) + { const BlockDescriptor& block_data = mostDerivedBlockDescriptor(); for (BlockDescriptor::param_validation_list_t::const_iterator it = block_data.mValidationList.begin(); it != block_data.mValidationList.end(); ++it) { @@ -204,16 +214,23 @@ namespace LLInitParam { if (emit_errors) { - llwarns << "Invalid param \"" << getParamName(block_data, param) << "\"" << llendl; + LL_WARNS() << "Invalid param \"" << getParamName(block_data, param) << "\"" << LL_ENDL; } return false; } } - return true; + mValidated = true; + } + return mValidated; } - void BaseBlock::serializeBlock(Parser& parser, Parser::name_stack_t& name_stack, const LLInitParam::BaseBlock* diff_block) const + bool BaseBlock::serializeBlock(Parser& parser, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const LLInitParam::BaseBlock* diff_block) const { + bool serialized = false; + if (!predicate_rule.check(ll_make_predicate(PROVIDED, isProvided()))) + { + return false; + } // named param is one like LLView::Params::follows // unnamed param is like LLView::Params::rect - implicit const BlockDescriptor& block_data = mostDerivedBlockDescriptor(); @@ -225,10 +242,10 @@ namespace LLInitParam param_handle_t param_handle = (*it)->mParamHandle; const Param* param = getParamFromHandle(param_handle); ParamDescriptor::serialize_func_t serialize_func = (*it)->mSerializeFunc; - if (serialize_func) + if (serialize_func && predicate_rule.check(ll_make_predicate(PROVIDED, param->anyProvided()))) { const Param* diff_param = diff_block ? diff_block->getParamFromHandle(param_handle) : NULL; - serialize_func(*param, parser, name_stack, diff_param); + serialized |= serialize_func(*param, parser, name_stack, predicate_rule, diff_param); } } @@ -239,7 +256,7 @@ namespace LLInitParam param_handle_t param_handle = it->second->mParamHandle; const Param* param = getParamFromHandle(param_handle); ParamDescriptor::serialize_func_t serialize_func = it->second->mSerializeFunc; - if (serialize_func && param->anyProvided()) + if (serialize_func && predicate_rule.check(ll_make_predicate(PROVIDED, param->anyProvided()))) { // Ensure this param has not already been serialized // Prevents <rect> from being serialized as its own tag. @@ -264,10 +281,17 @@ namespace LLInitParam name_stack.push_back(std::make_pair(it->first, !duplicate)); const Param* diff_param = diff_block ? diff_block->getParamFromHandle(param_handle) : NULL; - serialize_func(*param, parser, name_stack, diff_param); + serialized |= serialize_func(*param, parser, name_stack, predicate_rule, diff_param); name_stack.pop_back(); } } + + if (!serialized && predicate_rule.check(ll_make_predicate(EMPTY))) + { + serialized |= parser.writeValue(Flag(), name_stack); + } + // was anything serialized in this block? + return serialized; } bool BaseBlock::inspectBlock(Parser& parser, Parser::name_stack_t name_stack, S32 min_count, S32 max_count) const @@ -393,7 +417,7 @@ namespace LLInitParam // Block<T, Base_Class> if ((size_t)handle > block_data.mMaxParamOffset) { - llerrs << "Attempted to register param with block defined for parent class, make sure to derive from LLInitParam::Block<YOUR_CLASS, PARAM_BLOCK_BASE_CLASS>" << llendl; + LL_ERRS() << "Attempted to register param with block defined for parent class, make sure to derive from LLInitParam::Block<YOUR_CLASS, PARAM_BLOCK_BASE_CLASS>" << LL_ENDL; } ParamDescriptorPtr param_descriptor = findParamDescriptor(param); diff --git a/indra/llcommon/llinitparam.h b/indra/llcommon/llinitparam.h index 03ab0fb67f..2532566319 100755 --- a/indra/llcommon/llinitparam.h +++ b/indra/llcommon/llinitparam.h @@ -29,14 +29,16 @@ #define LL_LLPARAM_H #include <vector> +#include <list> #include <boost/function.hpp> #include <boost/type_traits/is_convertible.hpp> #include <boost/type_traits/is_enum.hpp> #include <boost/unordered_map.hpp> -#include <boost/shared_ptr.hpp> #include "llerror.h" #include "llstl.h" +#include "llpredicate.h" +#include "llsd.h" namespace LLTypeTags { @@ -195,6 +197,8 @@ namespace LLInitParam return mValue; } + bool isValid() const { return true; } + protected: T mValue; }; @@ -209,13 +213,11 @@ namespace LLInitParam typedef T value_t; ParamValue() - : T(), - mValidated(false) + : T() {} ParamValue(const default_value_t& other) - : T(other), - mValidated(false) + : T(other) {} void setValue(const value_t& val) @@ -232,9 +234,6 @@ namespace LLInitParam { return *this; } - - protected: - mutable bool mValidated; // lazy validation flag }; @@ -497,25 +496,25 @@ namespace LLInitParam virtual ~Parser(); template <typename T> bool readValue(T& param, typename boost::disable_if<boost::is_enum<T> >::type* dummy = 0) - { + { parser_read_func_map_t::iterator found_it = mParserReadFuncs->find(&typeid(T)); if (found_it != mParserReadFuncs->end()) - { + { return found_it->second(*this, (void*)¶m); - } - - return false; } - + + return false; + } + template <typename T> bool readValue(T& param, typename boost::enable_if<boost::is_enum<T> >::type* dummy = 0) - { + { parser_read_func_map_t::iterator found_it = mParserReadFuncs->find(&typeid(T)); if (found_it != mParserReadFuncs->end()) - { + { return found_it->second(*this, (void*)¶m); - } + } else - { + { found_it = mParserReadFuncs->find(&typeid(S32)); if (found_it != mParserReadFuncs->end()) { @@ -523,20 +522,20 @@ namespace LLInitParam bool parsed = found_it->second(*this, (void*)&int_value); param = (T)int_value; return parsed; - } } - return false; } + return false; + } template <typename T> bool writeValue(const T& param, name_stack_t& name_stack) - { + { parser_write_func_map_t::iterator found_it = mParserWriteFuncs->find(&typeid(T)); if (found_it != mParserWriteFuncs->end()) - { + { return found_it->second(*this, (const void*)¶m, name_stack); - } - return false; } + return false; + } // dispatch inspection to registered inspection functions, for each parameter in a param block template <typename T> bool inspectValue(name_stack_t& name_stack, S32 min_count, S32 max_count, const possible_values_t* possible_values) @@ -579,6 +578,19 @@ namespace LLInitParam class Param; + enum ESerializePredicates + { + PROVIDED, + REQUIRED, + VALID, + HAS_DEFAULT_VALUE, + EMPTY + }; + + typedef LLPredicate::Rule<ESerializePredicates> predicate_rule_t; + + predicate_rule_t default_parse_rules(); + // various callbacks and constraints associated with an individual param struct LL_COMMON_API ParamDescriptor { @@ -589,7 +601,7 @@ namespace LLInitParam typedef bool(*merge_func_t)(Param&, const Param&, bool); typedef bool(*deserialize_func_t)(Param&, Parser&, Parser::name_stack_range_t&, bool); - typedef void(*serialize_func_t)(const Param&, Parser&, Parser::name_stack_t&, const Param* diff_param); + typedef bool(*serialize_func_t)(const Param&, Parser&, Parser::name_stack_t&, const predicate_rule_t rules, const Param* diff_param); typedef void(*inspect_func_t)(const Param&, Parser&, Parser::name_stack_t&, S32 min_count, S32 max_count); typedef bool(*validation_func_t)(const Param*); @@ -617,7 +629,7 @@ namespace LLInitParam UserData* mUserData; }; - typedef boost::shared_ptr<ParamDescriptor> ParamDescriptorPtr; + typedef ParamDescriptor* ParamDescriptorPtr; // each derived Block class keeps a static data structure maintaining offsets to various params class LL_COMMON_API BlockDescriptor @@ -829,12 +841,28 @@ namespace LLInitParam LOG_CLASS(BaseBlock); friend class Param; + BaseBlock() + : mValidated(false), + mParamProvided(false) + {} + virtual ~BaseBlock() {} bool submitValue(Parser::name_stack_t& name_stack, Parser& p, bool silent=false); param_handle_t getHandleFromParam(const Param* param) const; bool validateBlock(bool emit_errors = true) const; + bool isProvided() const + { + return mParamProvided; + } + + bool isValid() const + { + return validateBlock(false); + } + + Param* getParamFromHandle(const param_handle_t param_handle) { if (param_handle == 0) return NULL; @@ -852,10 +880,19 @@ namespace LLInitParam void addSynonym(Param& param, const std::string& synonym); // Blocks can override this to do custom tracking of changes - virtual void paramChanged(const Param& changed_param, bool user_provided) {} + virtual void paramChanged(const Param& changed_param, bool user_provided) + { + if (user_provided) + { + // a child param has been explicitly changed + // so *some* aspect of this block is now provided + mValidated = false; + mParamProvided = true; + } + } bool deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack_range, bool new_name); - void serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const BaseBlock* diff_block = NULL) const; + bool serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const predicate_rule_t rule, const BaseBlock* diff_block = NULL) const; bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const; virtual const BlockDescriptor& mostDerivedBlockDescriptor() const { return getBlockDescriptor(); } @@ -893,6 +930,9 @@ namespace LLInitParam return mergeBlock(block_data, source, overwrite); } + mutable bool mValidated; // lazy validation flag + bool mParamProvided; + private: const std::string& getParamName(const BlockDescriptor& block_data, const Param* paramp) const; }; @@ -986,6 +1026,8 @@ namespace LLInitParam bool isProvided() const { return Param::anyProvided(); } + bool isValid() const { return true; } + static bool deserializeParam(Param& param, Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name) { self_t& typed_param = static_cast<self_t&>(param); @@ -1014,10 +1056,23 @@ namespace LLInitParam return false; } - static void serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const Param* diff_param) + static bool serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const Param* diff_param) { + bool serialized = false; const self_t& typed_param = static_cast<const self_t&>(param); - if (!typed_param.isProvided()) return; + const self_t* diff_typed_param = static_cast<const self_t*>(diff_param); + + LLPredicate::Value<ESerializePredicates> predicate; + if (diff_typed_param && ParamCompare<T>::equals(typed_param.getValue(), diff_typed_param->getValue())) + { + predicate.set(HAS_DEFAULT_VALUE); + } + + predicate.set(VALID, typed_param.isValid()); + predicate.set(PROVIDED, typed_param.anyProvided()); + predicate.set(EMPTY, false); + + if (!predicate_rule.check(predicate)) return false; if (!name_stack.empty()) { @@ -1030,25 +1085,27 @@ namespace LLInitParam if (!key.empty()) { - if (!diff_param || !ParamCompare<std::string>::equals(static_cast<const self_t*>(diff_param)->getValueName(), key)) + if (!diff_typed_param || !ParamCompare<std::string>::equals(diff_typed_param->getValueName(), key)) { - parser.writeValue(key, name_stack); + serialized = parser.writeValue(key, name_stack); } } // then try to serialize value directly - else if (!diff_param || !ParamCompare<T>::equals(typed_param.getValue(), static_cast<const self_t*>(diff_param)->getValue())) + else if (!diff_typed_param || ParamCompare<T>::equals(typed_param.getValue(), diff_typed_param->getValue())) { - if (!parser.writeValue(typed_param.getValue(), name_stack)) + serialized = parser.writeValue(typed_param.getValue(), name_stack); + if (!serialized) { std::string calculated_key = typed_param.calcValueName(typed_param.getValue()); if (calculated_key.size() - && (!diff_param + && (!diff_typed_param || !ParamCompare<std::string>::equals(static_cast<const self_t*>(diff_param)->getValueName(), calculated_key))) { - parser.writeValue(calculated_key, name_stack); + serialized = parser.writeValue(calculated_key, name_stack); } } } + return serialized; } static void inspectParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, S32 min_count, S32 max_count) @@ -1113,19 +1170,19 @@ namespace LLInitParam }; // parameter that is a block - template <typename T, typename NAME_VALUE_LOOKUP> - class TypedParam<T, NAME_VALUE_LOOKUP, false, IS_A_BLOCK> + template <typename BLOCK_T, typename NAME_VALUE_LOOKUP> + class TypedParam<BLOCK_T, NAME_VALUE_LOOKUP, false, IS_A_BLOCK> : public Param, public NAME_VALUE_LOOKUP::type_value_t { protected: - typedef ParamValue<typename LLTypeTags::Sorted<T>::value_t> param_value_t; - typedef typename param_value_t::default_value_t default_value_t; - typedef TypedParam<T, NAME_VALUE_LOOKUP, false, IS_A_BLOCK> self_t; - typedef typename NAME_VALUE_LOOKUP::type_value_t named_value_t; + typedef ParamValue<typename LLTypeTags::Sorted<BLOCK_T>::value_t> param_value_t; + typedef typename param_value_t::default_value_t default_value_t; + typedef TypedParam<BLOCK_T, NAME_VALUE_LOOKUP, false, IS_A_BLOCK> self_t; + typedef typename NAME_VALUE_LOOKUP::type_value_t named_value_t; public: using named_value_t::operator(); - typedef typename param_value_t::value_t value_t; + typedef typename param_value_t::value_t value_t; TypedParam(BlockDescriptor& block_descriptor, const char* name, const default_value_t& value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count) : Param(block_descriptor.mCurrentBlockPtr), @@ -1148,11 +1205,11 @@ namespace LLInitParam if(named_value_t::valueNamesExist() && parser.readValue(name) && named_value_t::getValueFromName(name, typed_param.getValue())) - { - typed_param.setValueName(name); - typed_param.setProvided(); - return true; - } + { + typed_param.setValueName(name); + typed_param.setProvided(); + return true; + } } if(typed_param.deserializeBlock(parser, name_stack_range, new_name)) @@ -1166,10 +1223,16 @@ namespace LLInitParam return false; } - static void serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const Param* diff_param) + static bool serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const Param* diff_param) { const self_t& typed_param = static_cast<const self_t&>(param); - if (!typed_param.isProvided()) return; + + LLPredicate::Value<ESerializePredicates> predicate; + + predicate.set(VALID, typed_param.isValid()); + predicate.set(PROVIDED, typed_param.anyProvided()); + + if (!predicate_rule.check(predicate)) return false; if (!name_stack.empty()) { @@ -1182,12 +1245,15 @@ namespace LLInitParam if (!diff_param || !ParamCompare<std::string>::equals(static_cast<const self_t*>(diff_param)->getValueName(), key)) { parser.writeValue(key, name_stack); + return true; } } else { - typed_param.serializeBlock(parser, name_stack, static_cast<const self_t*>(diff_param)); + return typed_param.serializeBlock(parser, name_stack, predicate_rule, static_cast<const self_t*>(diff_param)); } + + return false; } static void inspectParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, S32 min_count, S32 max_count) @@ -1209,13 +1275,12 @@ namespace LLInitParam // *and* the block as a whole validates bool isProvided() const { - // only validate block when it hasn't already passed validation with current data - if (Param::anyProvided() && !param_value_t::mValidated) - { - // a sub-block is "provided" when it has been filled in enough to be valid - param_value_t::mValidated = param_value_t::validateBlock(false); - } - return Param::anyProvided() && param_value_t::mValidated; + return Param::anyProvided() && isValid(); + } + + bool isValid() const + { + return param_value_t::isValid(); } // assign block contents to this param-that-is-a-block @@ -1223,9 +1288,6 @@ namespace LLInitParam { setValue(val); named_value_t::clearValueName(); - // force revalidation of block - // next call to isProvided() will update provision status based on validity - param_value_t::mValidated = false; setProvided(flag_as_provided); } @@ -1242,9 +1304,6 @@ namespace LLInitParam if (user_provided) { - // a child param has been explicitly changed - // so *some* aspect of this block is now provided - param_value_t::mValidated = false; setProvided(); named_value_t::clearValueName(); } @@ -1296,13 +1355,13 @@ namespace LLInitParam }; // list of non-block parameters - template <typename VALUE_TYPE, typename NAME_VALUE_LOOKUP> - class TypedParam<VALUE_TYPE, NAME_VALUE_LOOKUP, true, NOT_BLOCK> + template <typename MULTI_VALUE_T, typename NAME_VALUE_LOOKUP> + class TypedParam<MULTI_VALUE_T, NAME_VALUE_LOOKUP, true, NOT_BLOCK> : public Param { protected: - typedef TypedParam<VALUE_TYPE, NAME_VALUE_LOOKUP, true, NOT_BLOCK> self_t; - typedef ParamValue<typename LLTypeTags::Sorted<VALUE_TYPE>::value_t> param_value_t; + typedef TypedParam<MULTI_VALUE_T, NAME_VALUE_LOOKUP, true, NOT_BLOCK> self_t; + typedef ParamValue<typename LLTypeTags::Sorted<MULTI_VALUE_T>::value_t> param_value_t; typedef typename std::vector<typename NAME_VALUE_LOOKUP::type_value_t> container_t; typedef container_t default_value_t; typedef typename NAME_VALUE_LOOKUP::type_value_t named_value_t; @@ -1311,7 +1370,9 @@ namespace LLInitParam typedef typename param_value_t::value_t value_t; TypedParam(BlockDescriptor& block_descriptor, const char* name, const default_value_t& value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count) - : Param(block_descriptor.mCurrentBlockPtr) + : Param(block_descriptor.mCurrentBlockPtr), + mMinCount(min_count), + mMaxCount(max_count) { std::copy(value.begin(), value.end(), std::back_inserter(mValues)); @@ -1322,7 +1383,13 @@ namespace LLInitParam } } - bool isProvided() const { return Param::anyProvided(); } + bool isProvided() const { return Param::anyProvided() && isValid(); } + + bool isValid() const + { + size_t num_elements = numValidElements(); + return mMinCount < num_elements && num_elements < mMaxCount; + } static bool deserializeParam(Param& param, Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name) { @@ -1337,7 +1404,7 @@ namespace LLInitParam } // no further names in stack, attempt to parse value now - if (name_stack_range.first == name_stack_range.second) + if (new_name_stack_range.first == new_name_stack_range.second) { std::string name; @@ -1359,10 +1426,19 @@ namespace LLInitParam return false; } - static void serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const Param* diff_param) + static bool serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const Param* diff_param) { + bool serialized = false; const self_t& typed_param = static_cast<const self_t&>(param); - if (!typed_param.isProvided()) return; + + LLPredicate::Value<ESerializePredicates> predicate; + + predicate.set(REQUIRED, typed_param.mMinCount > 0); + predicate.set(VALID, typed_param.isValid()); + predicate.set(PROVIDED, typed_param.anyProvided()); + predicate.set(EMPTY, typed_param.mValues.empty()); + + if (!predicate_rule.check(predicate)) return false; for (const_iterator it = typed_param.mValues.begin(), end_it = typed_param.mValues.end(); it != end_it; @@ -1378,7 +1454,11 @@ namespace LLInitParam if (!value_written) { std::string calculated_key = it->calcValueName(it->getValue()); - if (!parser.writeValue(calculated_key, name_stack)) + if (parser.writeValue(calculated_key, name_stack)) + { + serialized = true; + } + else { break; } @@ -1386,19 +1466,23 @@ namespace LLInitParam } else { - if(!parser.writeValue(key, name_stack)) + if(parser.writeValue(key, name_stack)) + { + serialized = true; + } + else { break; } } - - name_stack.pop_back(); } + + return serialized; } static void inspectParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, S32 min_count, S32 max_count) { - parser.inspectValue<VALUE_TYPE>(name_stack, min_count, max_count, NULL); + parser.inspectValue<MULTI_VALUE_T>(name_stack, min_count, max_count, NULL); if (named_value_t::getPossibleValues()) { parser.inspectValue<std::string>(name_stack, min_count, max_count, named_value_t::getPossibleValues()); @@ -1453,7 +1537,7 @@ namespace LLInitParam bool empty() const { return mValues.empty(); } size_t size() const { return mValues.size(); } - U32 numValidElements() const + size_t numValidElements() const { return mValues.size(); } @@ -1483,6 +1567,8 @@ namespace LLInitParam } container_t mValues; + size_t mMinCount, + mMaxCount; private: void init( BlockDescriptor &block_descriptor, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count, const char* name ) @@ -1500,13 +1586,13 @@ namespace LLInitParam }; // list of block parameters - template <typename VALUE_TYPE, typename NAME_VALUE_LOOKUP> - class TypedParam<VALUE_TYPE, NAME_VALUE_LOOKUP, true, IS_A_BLOCK> + template <typename MULTI_BLOCK_T, typename NAME_VALUE_LOOKUP> + class TypedParam<MULTI_BLOCK_T, NAME_VALUE_LOOKUP, true, IS_A_BLOCK> : public Param { protected: - typedef TypedParam<VALUE_TYPE, NAME_VALUE_LOOKUP, true, IS_A_BLOCK> self_t; - typedef ParamValue<typename LLTypeTags::Sorted<VALUE_TYPE>::value_t> param_value_t; + typedef TypedParam<MULTI_BLOCK_T, NAME_VALUE_LOOKUP, true, IS_A_BLOCK> self_t; + typedef ParamValue<typename LLTypeTags::Sorted<MULTI_BLOCK_T>::value_t> param_value_t; typedef typename std::vector<typename NAME_VALUE_LOOKUP::type_value_t> container_t; typedef typename NAME_VALUE_LOOKUP::type_value_t named_value_t; typedef container_t default_value_t; @@ -1516,7 +1602,9 @@ namespace LLInitParam typedef typename param_value_t::value_t value_t; TypedParam(BlockDescriptor& block_descriptor, const char* name, const default_value_t& value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count) - : Param(block_descriptor.mCurrentBlockPtr) + : Param(block_descriptor.mCurrentBlockPtr), + mMinCount(min_count), + mMaxCount(max_count) { std::copy(value.begin(), value.end(), back_inserter(mValues)); @@ -1526,7 +1614,14 @@ namespace LLInitParam } } - bool isProvided() const { return Param::anyProvided(); } + bool isProvided() const { return Param::anyProvided() && isValid(); } + + bool isValid() const + { + size_t num_elements = numValidElements(); + return mMinCount < num_elements && num_elements < mMaxCount; + } + static bool deserializeParam(Param& param, Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name) { @@ -1549,7 +1644,7 @@ namespace LLInitParam } param_value_t& value = typed_param.mValues.back(); - if (name_stack_range.first == name_stack_range.second) + if (new_name_stack_range.first == new_name_stack_range.second) { // try to parse a known named value std::string name; @@ -1559,6 +1654,10 @@ namespace LLInitParam { typed_param.mValues.back().setValueName(name); typed_param.setProvided(); + if (new_array_value) + { + name_stack_range.first->second = false; + } return true; } } @@ -1583,10 +1682,18 @@ namespace LLInitParam return false; } - static void serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const Param* diff_param) + static bool serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const Param* diff_param) { + bool serialized = false; const self_t& typed_param = static_cast<const self_t&>(param); - if (!typed_param.isProvided()) return; + LLPredicate::Value<ESerializePredicates> predicate; + + predicate.set(REQUIRED, typed_param.mMinCount > 0); + predicate.set(VALID, typed_param.isValid()); + predicate.set(PROVIDED, typed_param.anyProvided()); + predicate.set(EMPTY, typed_param.mValues.empty()); + + if (!predicate_rule.check(predicate)) return false; for (const_iterator it = typed_param.mValues.begin(), end_it = typed_param.mValues.end(); it != end_it; @@ -1597,17 +1704,24 @@ namespace LLInitParam std::string key = it->getValueName(); if (!key.empty()) { - parser.writeValue(key, name_stack); + serialized |= parser.writeValue(key, name_stack); } // Not parsed via named values, write out value directly - // NOTE: currently we don't worry about removing default values in Multiple + // NOTE: currently we don't do diffing of Multiples else { - it->serializeBlock(parser, name_stack, NULL); + serialized = it->serializeBlock(parser, name_stack, predicate_rule, NULL); } name_stack.pop_back(); } + + if (!serialized && predicate_rule.check(ll_make_predicate(EMPTY))) + { + serialized |= parser.writeValue(Flag(), name_stack); + } + + return serialized; } static void inspectParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, S32 min_count, S32 max_count) @@ -1670,14 +1784,14 @@ namespace LLInitParam bool empty() const { return mValues.empty(); } size_t size() const { return mValues.size(); } - U32 numValidElements() const + size_t numValidElements() const { - U32 count = 0; + size_t count = 0; for (const_iterator it = mValues.begin(), end_it = mValues.end(); it != end_it; ++it) { - if(it->validateBlock(false)) count++; + if(it->isValid()) count++; } return count; } @@ -1709,6 +1823,8 @@ namespace LLInitParam } container_t mValues; + size_t mMinCount, + mMaxCount; private: void init( BlockDescriptor &block_descriptor, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count, const char* name ) @@ -2015,7 +2131,7 @@ namespace LLInitParam static bool validate(const Param* paramp) { - U32 num_valid = ((super_t*)paramp)->numValidElements(); + size_t num_valid = ((super_t*)paramp)->numValidElements(); return RANGE::minCount <= num_valid && num_valid <= RANGE::maxCount; } }; @@ -2158,13 +2274,11 @@ namespace LLInitParam typedef T default_value_t; ParamValue() - : mValue(), - mValidated(false) + : mValue() {} ParamValue(const default_value_t& value) - : mValue(value), - mValidated(false) + : mValue(value) {} void setValue(const value_t& val) @@ -2191,18 +2305,18 @@ namespace LLInitParam return mValue.deserializeBlock(p, name_stack_range, new_name); } - void serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const self_t* diff_block = NULL) const + bool serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const self_t* diff_block = NULL) const { const BaseBlock* base_block = diff_block ? &(diff_block->mValue) : NULL; - mValue.serializeBlock(p, name_stack, base_block); + return mValue.serializeBlock(p, name_stack, predicate_rule, base_block); } bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const - { + { return mValue.inspectBlock(p, name_stack, min_count, max_count); - } + } bool mergeBlockParam(bool source_provided, bool dst_provided, BlockDescriptor& block_data, const self_t& source, bool overwrite) { @@ -2212,9 +2326,7 @@ namespace LLInitParam // clear away what is there and take the new stuff as a whole resetToDefault(); return mValue.mergeBlock(block_data, source.getValue(), overwrite); - } - - + } return mValue.mergeBlock(block_data, source.getValue(), overwrite); } @@ -2223,14 +2335,17 @@ namespace LLInitParam return mValue.validateBlock(emit_errors); } + bool isValid() const + { + return validateBlock(false); + } + static BlockDescriptor& getBlockDescriptor() { return value_t::getBlockDescriptor(); } - mutable bool mValidated; // lazy validation flag - private: void resetToDefault() { @@ -2251,15 +2366,13 @@ namespace LLInitParam typedef T default_value_t; ParamValue() - : mValue(), - mValidated(false) + : mValue() { mCurParam = getBlockDescriptor().mAllParams.begin(); } ParamValue(const default_value_t& value) - : mValue(value), - mValidated(false) + : mValue(value) { mCurParam = getBlockDescriptor().mAllParams.begin(); } @@ -2284,7 +2397,7 @@ namespace LLInitParam if (new_name) { mCurParam = getBlockDescriptor().mAllParams.begin(); - } + } if (name_stack_range.first == name_stack_range.second && mCurParam != getBlockDescriptor().mAllParams.end()) { @@ -2296,7 +2409,7 @@ namespace LLInitParam if (deserialize_func && paramp && deserialize_func(*paramp, p, name_stack_range, new_name)) - { + { ++mCurParam; return true; } @@ -2304,19 +2417,19 @@ namespace LLInitParam { return false; } - } + } else { return mValue.deserializeBlock(p, name_stack_range, new_name); } } - void serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const self_t* diff_block = NULL) const + bool serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const self_t* diff_block = NULL) const { const BaseBlock* base_block = diff_block ? &(diff_block->mValue) : NULL; - mValue.serializeBlock(p, name_stack, base_block); + return mValue.serializeBlock(p, name_stack, predicate_rule, base_block); } bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const @@ -2334,13 +2447,16 @@ namespace LLInitParam return mValue.validateBlock(emit_errors); } + bool isValid() const + { + return validateBlock(false); + } + static BlockDescriptor& getBlockDescriptor() { return value_t::getBlockDescriptor(); } - mutable bool mValidated; // lazy validation flag - private: BlockDescriptor::all_params_list_t::iterator mCurParam; @@ -2358,16 +2474,14 @@ namespace LLInitParam typedef T default_value_t; ParamValue() - : T(), - mValidated(false) + : T() {} ParamValue(const default_value_t& value) - : T(value.getValue()), - mValidated(false) + : T(value.getValue()) {} - mutable bool mValidated; // lazy validation flag + bool isValid() const { return true; } }; template<typename T, typename BLOCK_T> @@ -2380,18 +2494,15 @@ namespace LLInitParam typedef LazyValue<T> default_value_t; ParamValue() - : mValue(), - mValidated(false) + : mValue() {} ParamValue(const default_value_t& other) - : mValue(other), - mValidated(false) + : mValue(other) {} ParamValue(const T& value) - : mValue(value), - mValidated(false) + : mValue(value) {} void setValue(const value_t& val) @@ -2414,14 +2525,14 @@ namespace LLInitParam return mValue.get().deserializeBlock(p, name_stack_range, new_name); } - void serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const self_t* diff_block = NULL) const + bool serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const self_t* diff_block = NULL) const { - if (mValue.empty()) return; + if (mValue.empty()) return false; const BaseBlock* base_block = (diff_block && !diff_block->mValue.empty()) ? &(diff_block->mValue.get().getValue()) : NULL; - mValue.get().serializeBlock(p, name_stack, base_block); + return mValue.get().serializeBlock(p, name_stack, predicate_rule, base_block); } bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const @@ -2433,26 +2544,29 @@ namespace LLInitParam { return source.mValue.empty() || mValue.get().mergeBlock(block_data, source.getValue(), overwrite); } - + bool validateBlock(bool emit_errors = true) const { return mValue.empty() || mValue.get().validateBlock(emit_errors); } + bool isValid() const + { + return validateBlock(false); + } + static BlockDescriptor& getBlockDescriptor() { return value_t::getBlockDescriptor(); } - mutable bool mValidated; // lazy validation flag - private: LazyValue<T> mValue; }; template<typename T, typename BLOCK_T> class ParamValue <BaseBlock::Lazy<T, NOT_BLOCK>, BLOCK_T> - { + { typedef ParamValue <BaseBlock::Lazy<T, NOT_BLOCK>, BLOCK_T> self_t; public: @@ -2460,18 +2574,15 @@ namespace LLInitParam typedef LazyValue<T> default_value_t; ParamValue() - : mValue(), - mValidated(false) + : mValue() {} ParamValue(const default_value_t& other) - : mValue(other), - mValidated(false) + : mValue(other) {} ParamValue(const T& value) - : mValue(value), - mValidated(false) + : mValue(value) {} void setValue(const value_t& val) @@ -2489,7 +2600,10 @@ namespace LLInitParam return mValue.get().getValue(); } - mutable bool mValidated; // lazy validation flag + bool isValid() const + { + return true; + } private: LazyValue<T> mValue; @@ -2504,12 +2618,10 @@ namespace LLInitParam typedef LLSD default_value_t; ParamValue() - : mValidated(false) {} ParamValue(const default_value_t& other) - : mValue(other), - mValidated(false) + : mValue(other) {} void setValue(const value_t& val) { mValue = val; } @@ -2519,16 +2631,13 @@ namespace LLInitParam // block param interface LL_COMMON_API bool deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack_range, bool new_name); - LL_COMMON_API void serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const BaseBlock* diff_block = NULL) const; + LL_COMMON_API bool serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const BaseBlock* diff_block = NULL) const; bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const { //TODO: implement LLSD params as schema type Any return true; } - protected: - mutable bool mValidated; // lazy validation flag - private: static void serializeElement(Parser& p, const LLSD& sd, Parser::name_stack_t& name_stack); @@ -2547,18 +2656,17 @@ namespace LLInitParam BLOCK_AUTHORITATIVE // mValue is derived from the block parameters, which are authoritative } EValueAge; - typedef ParamValue<T> derived_t; - typedef CustomParamValue<T> self_t; - typedef Block<derived_t> block_t; + typedef TypeValues<T> derived_t; + typedef CustomParamValue<T> self_t; + typedef Block<ParamValue<T> > block_t; typedef T default_value_t; - typedef T value_t; + typedef T value_t; typedef void baseblock_base_class_t; CustomParamValue(const default_value_t& value = T()) : mValue(value), - mValueAge(VALUE_AUTHORITATIVE), - mValidated(false) + mValueAge(VALUE_AUTHORITATIVE) {} bool deserializeBlock(Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name) @@ -2580,16 +2688,30 @@ namespace LLInitParam return typed_param.BaseBlock::deserializeBlock(parser, name_stack_range, new_name); } - void serializeBlock(Parser& parser, Parser::name_stack_t& name_stack, const BaseBlock* diff_block = NULL) const + bool serializeBlock(Parser& parser, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const BaseBlock* diff_block = NULL) const { const derived_t& typed_param = static_cast<const derived_t&>(*this); const derived_t* diff_param = static_cast<const derived_t*>(diff_block); + //std::string key = typed_param.getValueName(); + + //// first try to write out name of name/value pair + //if (!key.empty()) + //{ + // if (!diff_param || !ParamCompare<std::string>::equals(diff_param->getValueName(), key)) + // { + // return parser.writeValue(key, name_stack); + // } + //} // then try to serialize value directly if (!diff_param || !ParamCompare<T>::equals(typed_param.getValue(), diff_param->getValue())) { - if (!parser.writeValue(typed_param.getValue(), name_stack)) + if (parser.writeValue(typed_param.getValue(), name_stack)) + { + return true; + } + else { //RN: *always* serialize provided components of BlockValue (don't pass diff_param on), // since these tend to be viewed as the constructor arguments for the value T. It seems @@ -2606,14 +2728,15 @@ namespace LLInitParam // and serialize those params derived_t copy(typed_param); copy.updateBlockFromValue(true); - copy.block_t::serializeBlock(parser, name_stack, NULL); + return copy.block_t::serializeBlock(parser, name_stack, predicate_rule, NULL); } else { - block_t::serializeBlock(parser, name_stack, NULL); + return block_t::serializeBlock(parser, name_stack, predicate_rule, NULL); } } } + return false; } bool validateBlock(bool emit_errors = true) const @@ -2705,8 +2828,6 @@ namespace LLInitParam return block_t::mergeBlock(block_data, source, overwrite); } - mutable bool mValidated; // lazy validation flag - private: mutable T mValue; mutable EValueAge mValueAge; diff --git a/indra/llcommon/llinstancetracker.cpp b/indra/llcommon/llinstancetracker.cpp index 64a313b5ff..11fc53f8c8 100755 --- a/indra/llcommon/llinstancetracker.cpp +++ b/indra/llcommon/llinstancetracker.cpp @@ -27,8 +27,26 @@ #include "linden_common.h" // associated header #include "llinstancetracker.h" +#include "llapr.h" + // STL headers // std headers // external library headers // other Linden headers +void LLInstanceTrackerBase::StaticBase::incrementDepth() +{ + apr_atomic_inc32(&sIterationNestDepth); +} + +void LLInstanceTrackerBase::StaticBase::decrementDepth() +{ + llassert(sIterationNestDepth); + apr_atomic_dec32(&sIterationNestDepth); +} + +U32 LLInstanceTrackerBase::StaticBase::getDepth() +{ + apr_uint32_t data = apr_atomic_read32(&sIterationNestDepth); + return data; +} diff --git a/indra/llcommon/llinstancetracker.h b/indra/llcommon/llinstancetracker.h index 55187d8325..9783644e66 100755 --- a/indra/llcommon/llinstancetracker.h +++ b/indra/llcommon/llinstancetracker.h @@ -31,10 +31,7 @@ #include <map> #include <typeinfo> -#include "string_table.h" -#include <boost/utility.hpp> -#include <boost/function.hpp> -#include <boost/bind.hpp> +#include "llstringtable.h" #include <boost/iterator/transform_iterator.hpp> #include <boost/iterator/indirect_iterator.hpp> @@ -46,8 +43,6 @@ class LL_COMMON_API LLInstanceTrackerBase { protected: - - /// It's not essential to derive your STATICDATA (for use with /// getStatic()) from StaticBase; it's just that both known /// implementations do. @@ -56,31 +51,39 @@ protected: StaticBase(): sIterationNestDepth(0) {} - S32 sIterationNestDepth; + + void incrementDepth(); + void decrementDepth(); + U32 getDepth(); + private: + U32 sIterationNestDepth; }; }; LL_COMMON_API void assert_main_thread(); +enum EInstanceTrackerAllowKeyCollisions +{ + LLInstanceTrackerErrorOnCollision, + LLInstanceTrackerReplaceOnCollision +}; + /// This mix-in class adds support for tracking all instances of the specified class parameter T /// The (optional) key associates a value of type KEY with a given instance of T, for quick lookup /// If KEY is not provided, then instances are stored in a simple set -/// @NOTE: see explicit specialization below for default KEY==T* case -template<typename T, typename KEY = T*> +/// @NOTE: see explicit specialization below for default KEY==void case +/// @NOTE: this class is not thread-safe unless used as read-only +template<typename T, typename KEY = void, EInstanceTrackerAllowKeyCollisions KEY_COLLISION_BEHAVIOR = LLInstanceTrackerErrorOnCollision> class LLInstanceTracker : public LLInstanceTrackerBase { typedef LLInstanceTracker<T, KEY> self_t; - typedef typename std::map<KEY, T*> InstanceMap; + typedef typename std::multimap<KEY, T*> InstanceMap; struct StaticData: public StaticBase { InstanceMap sMap; }; static StaticData& getStatic() { static StaticData sData; return sData;} - static InstanceMap& getMap_() - { - // assert_main_thread(); fwiw this class is not thread safe, and it used by multiple threads. Bad things happen. - return getStatic().sMap; - } + static InstanceMap& getMap_() { return getStatic().sMap; } public: class instance_iter : public boost::iterator_facade<instance_iter, T, boost::forward_traversal_tag> @@ -91,12 +94,12 @@ public: instance_iter(const typename InstanceMap::iterator& it) : mIterator(it) { - ++getStatic().sIterationNestDepth; + getStatic().incrementDepth(); } ~instance_iter() { - --getStatic().sIterationNestDepth; + getStatic().decrementDepth(); } @@ -123,20 +126,20 @@ public: typedef boost::iterator_facade<key_iter, KEY, boost::forward_traversal_tag> super_t; key_iter(typename InstanceMap::iterator it) - : mIterator(it) + : mIterator(it) { - ++getStatic().sIterationNestDepth; + getStatic().incrementDepth(); } key_iter(const key_iter& other) - : mIterator(other.mIterator) + : mIterator(other.mIterator) { - ++getStatic().sIterationNestDepth; + getStatic().incrementDepth(); } ~key_iter() { - --getStatic().sIterationNestDepth; + getStatic().decrementDepth(); } @@ -174,7 +177,10 @@ public: return instance_iter(getMap_().end()); } - static S32 instanceCount() { return getMap_().size(); } + static S32 instanceCount() + { + return getMap_().size(); + } static key_iter beginKeys() { @@ -186,7 +192,7 @@ public: } protected: - LLInstanceTracker(KEY key) + LLInstanceTracker(const KEY& key) { // make sure static data outlives all instances getStatic(); @@ -195,7 +201,7 @@ protected: virtual ~LLInstanceTracker() { // it's unsafe to delete instances of this type while all instances are being iterated over. - llassert_always(getStatic().sIterationNestDepth == 0); + llassert_always(getStatic().getDepth() == 0); remove_(); } virtual void setKey(KEY key) { remove_(); add_(key); } @@ -205,17 +211,44 @@ private: LLInstanceTracker( const LLInstanceTracker& ); const LLInstanceTracker& operator=( const LLInstanceTracker& ); - void add_(KEY key) + void add_(const KEY& key) { mInstanceKey = key; - getMap_()[key] = static_cast<T*>(this); + InstanceMap& map = getMap_(); + typename InstanceMap::iterator insertion_point_it = map.lower_bound(key); + if (insertion_point_it != map.end() + && insertion_point_it->first == key) + { // found existing entry with that key + switch(KEY_COLLISION_BEHAVIOR) + { + case LLInstanceTrackerErrorOnCollision: + { + // use assert here instead of LL_ERRS(), otherwise the error will be ignored since this call is made during global object initialization + llassert_always_msg(false, "Instance with this same key already exists!"); + break; + } + case LLInstanceTrackerReplaceOnCollision: + { + // replace pointer, but leave key (should have compared equal anyway) + insertion_point_it->second = static_cast<T*>(this); + break; + } + default: + break; + } + } + else + { // new key + map.insert(insertion_point_it, std::make_pair(key, static_cast<T*>(this))); + } } void remove_() { - typename InstanceMap::iterator iter = getMap_().find(mInstanceKey); - if (iter != getMap_().end()) + InstanceMap& map = getMap_(); + typename InstanceMap::iterator iter = map.find(mInstanceKey); + if (iter != map.end()) { - getMap_().erase(iter); + map.erase(iter); } } @@ -223,12 +256,12 @@ private: KEY mInstanceKey; }; -/// explicit specialization for default case where KEY is T* +/// explicit specialization for default case where KEY is void /// use a simple std::set<T*> -template<typename T> -class LLInstanceTracker<T, T*> : public LLInstanceTrackerBase +template<typename T, EInstanceTrackerAllowKeyCollisions KEY_COLLISION_BEHAVIOR> +class LLInstanceTracker<T, void, KEY_COLLISION_BEHAVIOR> : public LLInstanceTrackerBase { - typedef LLInstanceTracker<T, T*> self_t; + typedef LLInstanceTracker<T, void> self_t; typedef typename std::set<T*> InstanceSet; struct StaticData: public StaticBase { @@ -261,18 +294,18 @@ public: instance_iter(const typename InstanceSet::iterator& it) : mIterator(it) { - ++getStatic().sIterationNestDepth; + getStatic().incrementDepth(); } instance_iter(const instance_iter& other) : mIterator(other.mIterator) { - ++getStatic().sIterationNestDepth; + getStatic().incrementDepth(); } ~instance_iter() { - --getStatic().sIterationNestDepth; + getStatic().decrementDepth(); } private: @@ -305,7 +338,7 @@ protected: virtual ~LLInstanceTracker() { // it's unsafe to delete instances of this type while all instances are being iterated over. - llassert_always(getStatic().sIterationNestDepth == 0); + llassert_always(getStatic().getDepth() == 0); getSet_().erase(static_cast<T*>(this)); } diff --git a/indra/llcommon/lllazy.cpp b/indra/llcommon/lllazy.cpp deleted file mode 100755 index 29fa040387..0000000000 --- a/indra/llcommon/lllazy.cpp +++ /dev/null @@ -1,40 +0,0 @@ -/** - * @file lllazy.cpp - * @author Nat Goodspeed - * @date 2009-01-28 - * @brief Implementation for lllazy. - * - * $LicenseInfo:firstyear=2009&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -// Precompiled header -#include "linden_common.h" -// associated header -#include "lllazy.h" -// STL headers -// std headers -// external library headers -// other Linden headers - -// lllazy.h is presently header-only. This file exists only because our CMake -// test macro ADD_BUILD_TEST requires it. -int dummy = 0; diff --git a/indra/llcommon/lllazy.h b/indra/llcommon/lllazy.h deleted file mode 100755 index 5f3bbce79e..0000000000 --- a/indra/llcommon/lllazy.h +++ /dev/null @@ -1,399 +0,0 @@ -/** - * @file lllazy.h - * @author Nat Goodspeed - * @date 2009-01-22 - * @brief Lazy instantiation of specified type. Useful in conjunction with - * Michael Feathers's "Extract and Override Getter" ("Working - * Effectively with Legacy Code", p. 352). - * - * Quoting his synopsis of steps on p.355: - * - * 1. Identify the object you need a getter for. - * 2. Extract all of the logic needed to create the object into a getter. - * 3. Replace all uses of the object with calls to the getter, and initialize - * the reference that holds the object to null in all constructors. - * 4. Add the first-time logic to the getter so that the object is constructed - * and assigned to the reference whenever the reference is null. - * 5. Subclass the class and override the getter to provide an alternative - * object for testing. - * - * It's the second half of bullet 3 (3b, as it were) that bothers me. I find - * it all too easy to imagine adding pointer initializers to all but one - * constructor... the one not exercised by my tests. That suggested using - * (e.g.) boost::scoped_ptr<MyObject> so you don't have to worry about - * destroying it either. - * - * However, introducing additional machinery allows us to encapsulate bullet 4 - * as well. - * - * $LicenseInfo:firstyear=2009&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#if ! defined(LL_LLLAZY_H) -#define LL_LLLAZY_H - -#include <boost/function.hpp> -#include <boost/scoped_ptr.hpp> -#include <boost/lambda/construct.hpp> -#include <stdexcept> - -/// LLLazyCommon simply factors out of LLLazy<T> things that don't depend on -/// its template parameter. -class LLLazyCommon -{ -public: - /** - * This exception is thrown if you try to replace an LLLazy<T>'s factory - * (or T* instance) after it already has an instance in hand. Since T - * might well be stateful, we can't know the effect of silently discarding - * and replacing an existing instance, so we disallow it. This facility is - * intended for testing, and in a test scenario we can definitely control - * that. - */ - struct InstanceChange: public std::runtime_error - { - InstanceChange(const std::string& what): std::runtime_error(what) {} - }; - -protected: - /** - * InstanceChange might be appropriate in a couple of different LLLazy<T> - * methods. Factor out the common logic. - */ - template <typename PTR> - static void ensureNoInstance(const PTR& ptr) - { - if (ptr) - { - // Too late: we've already instantiated the lazy object. We don't - // know whether it's stateful or not, so it's not safe to discard - // the existing instance in favor of a replacement. - throw InstanceChange("Too late to replace LLLazy instance"); - } - } -}; - -/** - * LLLazy<T> is useful when you have an outer class Outer that you're trying - * to bring under unit test, that contains a data member difficult to - * instantiate in a test harness. Typically the data member's class Inner has - * many thorny dependencies. Feathers generally advocates "Extract and - * Override Factory Method" (p. 350). But in C++, you can't call a derived - * class override of a virtual method from the derived class constructor, - * which limits applicability of "Extract and Override Factory Method." For - * such cases Feathers presents "Extract and Override Getter" (p. 352). - * - * So we'll assume that your class Outer contains a member like this: - * @code - * Inner mInner; - * @endcode - * - * LLLazy<Inner> can be used to replace this member. You can directly declare: - * @code - * LLLazy<Inner> mInner; - * @endcode - * and change references to mInner accordingly. - * - * (Alternatively, you can add a base class of the form - * <tt>LLLazyBase<Inner></tt>. This is discussed further in the LLLazyBase<T> - * documentation.) - * - * LLLazy<T> binds a <tt>boost::scoped_ptr<T></tt> and a factory functor - * returning T*. You can either bind that functor explicitly or let it default - * to the expression <tt>new T()</tt>. - * - * As long as LLLazy<T> remains unreferenced, its T remains uninstantiated. - * The first time you use get(), <tt>operator*()</tt> or <tt>operator->()</tt> - * it will instantiate its T and thereafter behave like a pointer to it. - * - * Thus, any existing reference to <tt>mInner.member</tt> should be replaced - * with <tt>mInner->member</tt>. Any simple reference to @c mInner should be - * replaced by <tt>*mInner</tt>. - * - * (If the original declaration was a pointer initialized in Outer's - * constructor, e.g. <tt>Inner* mInner</tt>, so much the better. In that case - * you should be able to drop in <tt>LLLazy<Inner></tt> without much change.) - * - * The support for "Extract and Override Getter" lies in the fact that you can - * replace the factory functor -- or provide an explicit T*. Presumably this - * is most useful from a test subclass -- which suggests that your @c mInner - * member should be @c protected. - * - * Note that <tt>boost::lambda::new_ptr<T>()</tt> makes a dandy factory - * functor, for either the set() method or LLLazy<T>'s constructor. If your T - * requires constructor arguments, use an expression more like - * <tt>boost::lambda::bind(boost::lambda::new_ptr<T>(), arg1, arg2, ...)</tt>. - * - * Of course the point of replacing the functor is to substitute a class that, - * though referenced as Inner*, is not an Inner; presumably this is a testing - * subclass of Inner (e.g. TestInner). Thus your test subclass TestOuter for - * the containing class Outer will contain something like this: - * @code - * class TestOuter: public Outer - * { - * public: - * TestOuter() - * { - * // mInner must be 'protected' rather than 'private' - * mInner.set(boost::lambda::new_ptr<TestInner>()); - * } - * ... - * }; - * @endcode - */ -template <typename T> -class LLLazy: public LLLazyCommon -{ -public: - /// Any nullary functor returning T* will work as a Factory - typedef boost::function<T* ()> Factory; - - /// The default LLLazy constructor uses <tt>new T()</tt> as its Factory - LLLazy(): - mFactory(boost::lambda::new_ptr<T>()) - {} - - /// Bind an explicit Factory functor - LLLazy(const Factory& factory): - mFactory(factory) - {} - - /// Reference T, instantiating it if this is the first access - const T& get() const - { - if (! mInstance) - { - // use the bound Factory functor - mInstance.reset(mFactory()); - } - return *mInstance; - } - - /// non-const get() - T& get() - { - return const_cast<T&>(const_cast<const LLLazy<T>*>(this)->get()); - } - - /// operator*() is equivalent to get() - const T& operator*() const { return get(); } - /// operator*() is equivalent to get() - T& operator*() { return get(); } - - /** - * operator->() must return (something resembling) T*. It's tempting to - * return the underlying boost::scoped_ptr<T>, but that would require - * breaking out the lazy-instantiation logic from get() into a common - * private method. Assume the pointer used for operator->() access is very - * short-lived. - */ - const T* operator->() const { return &get(); } - /// non-const operator->() - T* operator->() { return &get(); } - - /// set(Factory). This will throw InstanceChange if mInstance has already - /// been set. - void set(const Factory& factory) - { - ensureNoInstance(mInstance); - mFactory = factory; - } - - /// set(T*). This will throw InstanceChange if mInstance has already been - /// set. - void set(T* instance) - { - ensureNoInstance(mInstance); - mInstance.reset(instance); - } - -private: - Factory mFactory; - // Consider an LLLazy<T> member of a class we're accessing by const - // reference. We want to allow even const methods to touch the LLLazy<T> - // member. Hence the actual pointer must be mutable because such access - // might assign it. - mutable boost::scoped_ptr<T> mInstance; -}; - -#if (! defined(__GNUC__)) || (__GNUC__ > 3) || (__GNUC__ == 3 && __GNUC_MINOR__ > 3) -// Not gcc at all, or a gcc more recent than gcc 3.3 -#define GCC33 0 -#else -#define GCC33 1 -#endif - -/** - * LLLazyBase<T> wraps LLLazy<T>, giving you an alternative way to replace - * <tt>Inner mInner;</tt>. Instead of coding <tt>LLLazy<Inner> mInner</tt>, - * you can add LLLazyBase<Inner> to your Outer class's bases, e.g.: - * @code - * class Outer: public LLLazyBase<Inner> - * { - * ... - * }; - * @endcode - * - * This gives you @c public get() and @c protected set() methods without - * having to make your LLLazy<Inner> member @c protected. The tradeoff is that - * you must access the wrapped LLLazy<Inner> using get() and set() rather than - * with <tt>operator*()</tt> or <tt>operator->()</tt>. - * - * This mechanism can be used for more than one member, but only if they're of - * different types. That is, you can replace: - * @code - * DifficultClass mDifficult; - * AwkwardType mAwkward; - * @endcode - * with: - * @code - * class Outer: public LLLazyBase<DifficultClass>, public LLLazyBase<AwkwardType> - * { - * ... - * }; - * @endcode - * but for a situation like this: - * @code - * DifficultClass mMainDifficult, mAuxDifficult; - * @endcode - * you should directly embed LLLazy<DifficultClass> (q.v.). - * - * For multiple LLLazyBase bases, e.g. the <tt>LLLazyBase<DifficultClass>, - * LLLazyBase<AwkwardType></tt> example above, access the relevant get()/set() - * as (e.g.) <tt>LLLazyBase<DifficultClass>::get()</tt>. (This is why you - * can't have multiple LLLazyBase<T> of the same T.) For a bit of syntactic - * sugar, please see getLazy()/setLazy(). - */ -template <typename T> -class LLLazyBase -{ -public: - /// invoke default LLLazy constructor - LLLazyBase() {} - /// make wrapped LLLazy bind an explicit Factory - LLLazyBase(const typename LLLazy<T>::Factory& factory): - mInstance(factory) - {} - - /// access to LLLazy::get() - T& get() { return *mInstance; } - /// access to LLLazy::get() - const T& get() const { return *mInstance; } - -protected: - // see getLazy()/setLazy() - #if (! GCC33) - template <typename T2, class MYCLASS> friend T2& getLazy(MYCLASS* this_); - template <typename T2, class MYCLASS> friend const T2& getLazy(const MYCLASS* this_); - #else // gcc 3.3 - template <typename T2, class MYCLASS> friend T2& getLazy(const MYCLASS* this_); - #endif // gcc 3.3 - template <typename T2, class MYCLASS> friend void setLazy(MYCLASS* this_, T2* instance); - template <typename T2, class MYCLASS> - friend void setLazy(MYCLASS* this_, const typename LLLazy<T2>::Factory& factory); - - /// access to LLLazy::set(Factory) - void set(const typename LLLazy<T>::Factory& factory) - { - mInstance.set(factory); - } - - /// access to LLLazy::set(T*) - void set(T* instance) - { - mInstance.set(instance); - } - -private: - LLLazy<T> mInstance; -}; - -/** - * @name getLazy()/setLazy() - * Suppose you have something like the following: - * @code - * class Outer: public LLLazyBase<DifficultClass>, public LLLazyBase<AwkwardType> - * { - * ... - * }; - * @endcode - * - * Your methods can reference the @c DifficultClass instance using - * <tt>LLLazyBase<DifficultClass>::get()</tt>, which is admittedly a bit ugly. - * Alternatively, you can write <tt>getLazy<DifficultClass>(this)</tt>, which - * is somewhat more straightforward to read. - * - * Similarly, - * @code - * LLLazyBase<DifficultClass>::set(new TestDifficultClass()); - * @endcode - * could instead be written: - * @code - * setLazy<DifficultClass>(this, new TestDifficultClass()); - * @endcode - * - * @note - * I wanted to provide getLazy() and setLazy() without explicitly passing @c - * this. That would imply making them methods on a base class rather than free - * functions. But if <tt>LLLazyBase<T></tt> derives normally from (say) @c - * LLLazyGrandBase providing those methods, then unqualified getLazy() would - * be ambiguous: you'd have to write <tt>LLLazyBase<T>::getLazy<T>()</tt>, - * which is even uglier than <tt>LLLazyBase<T>::get()</tt>, and therefore - * pointless. You can make the compiler not care which @c LLLazyGrandBase - * instance you're talking about by making @c LLLazyGrandBase a @c virtual - * base class of @c LLLazyBase. But in that case, - * <tt>LLLazyGrandBase::getLazy<T>()</tt> can't access - * <tt>LLLazyBase<T>::get()</tt>! - * - * We want <tt>getLazy<T>()</tt> to access <tt>LLLazyBase<T>::get()</tt> as if - * in the lexical context of some subclass method. Ironically, free functions - * let us do that better than methods on a @c virtual base class -- but that - * implies passing @c this explicitly. So be it. - */ -//@{ -#if (! GCC33) -template <typename T, class MYCLASS> -T& getLazy(MYCLASS* this_) { return this_->LLLazyBase<T>::get(); } -template <typename T, class MYCLASS> -const T& getLazy(const MYCLASS* this_) { return this_->LLLazyBase<T>::get(); } -#else // gcc 3.3 -// For const-correctness, we really should have two getLazy() variants: one -// accepting const MYCLASS* and returning const T&, the other accepting -// non-const MYCLASS* and returning non-const T&. This works fine on the Mac -// (gcc 4.0.1) and Windows (MSVC 8.0), but fails on our Linux 32-bit Debian -// Sarge stations (gcc 3.3.5). Since I really don't know how to beat that aging -// compiler over the head to make it do the right thing, I'm going to have to -// move forward with the wrong thing: a single getLazy() function that accepts -// const MYCLASS* and returns non-const T&. -template <typename T, class MYCLASS> -T& getLazy(const MYCLASS* this_) { return const_cast<MYCLASS*>(this_)->LLLazyBase<T>::get(); } -#endif // gcc 3.3 -template <typename T, class MYCLASS> -void setLazy(MYCLASS* this_, T* instance) { this_->LLLazyBase<T>::set(instance); } -template <typename T, class MYCLASS> -void setLazy(MYCLASS* this_, const typename LLLazy<T>::Factory& factory) -{ - this_->LLLazyBase<T>::set(factory); -} -//@} - -#endif /* ! defined(LL_LLLAZY_H) */ diff --git a/indra/llcommon/llleap.cpp b/indra/llcommon/llleap.cpp index 0a57ef1c48..84d2a12f65 100755 --- a/indra/llcommon/llleap.cpp +++ b/indra/llcommon/llleap.cpp @@ -394,7 +394,7 @@ public: LLProcess::WritePipe& childin(mChild->getWritePipe(LLProcess::STDIN)); LLEventPump& mainloop(LLEventPumps::instance().obtain("mainloop")); LLSD nop; - F64 until(LLTimer::getElapsedSeconds() + 2); + F64 until = (LLTimer::getElapsedSeconds() + 2).value(); while (childin.size() && LLTimer::getElapsedSeconds() < until) { mainloop.post(nop); diff --git a/indra/llcommon/lllinkedqueue.h b/indra/llcommon/lllinkedqueue.h deleted file mode 100755 index 8336608809..0000000000 --- a/indra/llcommon/lllinkedqueue.h +++ /dev/null @@ -1,309 +0,0 @@ -/** - * @file lllinkedqueue.h - * @brief Declaration of linked queue classes. - * - * $LicenseInfo:firstyear=2003&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_LLLINKEDQUEUE_H -#define LL_LLLINKEDQUEUE_H - -#include "llerror.h" - -// node that actually contains the data -template <class DATA_TYPE> class LLLinkedQueueNode -{ -public: - DATA_TYPE mData; - LLLinkedQueueNode *mNextp; - LLLinkedQueueNode *mPrevp; - - -public: - LLLinkedQueueNode(); - LLLinkedQueueNode(const DATA_TYPE data); - - // destructor does not, by default, destroy associated data - // however, the mDatap must be NULL to ensure that we aren't causing memory leaks - ~LLLinkedQueueNode(); -}; - - - -template <class DATA_TYPE> class LLLinkedQueue -{ - -public: - LLLinkedQueue(); - - // destructor destroys list and nodes, but not data in nodes - ~LLLinkedQueue(); - - // Puts at end of FIFO - void push(const DATA_TYPE data); - - // Takes off front of FIFO - BOOL pop(DATA_TYPE &data); - BOOL peek(DATA_TYPE &data); - - void reset(); - - S32 getLength() const; - - BOOL isEmpty() const; - - BOOL remove(const DATA_TYPE data); - - BOOL checkData(const DATA_TYPE data) const; - -private: - // add node to end of list - // set mCurrentp to mQueuep - void addNodeAtEnd(LLLinkedQueueNode<DATA_TYPE> *nodep); - -private: - LLLinkedQueueNode<DATA_TYPE> mHead; // head node - LLLinkedQueueNode<DATA_TYPE> mTail; // tail node - S32 mLength; -}; - - -// -// Nodes -// - -template <class DATA_TYPE> -LLLinkedQueueNode<DATA_TYPE>::LLLinkedQueueNode() : - mData(), mNextp(NULL), mPrevp(NULL) -{ } - -template <class DATA_TYPE> -LLLinkedQueueNode<DATA_TYPE>::LLLinkedQueueNode(const DATA_TYPE data) : - mData(data), mNextp(NULL), mPrevp(NULL) -{ } - -template <class DATA_TYPE> -LLLinkedQueueNode<DATA_TYPE>::~LLLinkedQueueNode() -{ } - - -// -// Queue itself -// - -template <class DATA_TYPE> -LLLinkedQueue<DATA_TYPE>::LLLinkedQueue() -: mHead(), - mTail(), - mLength(0) -{ } - - -// destructor destroys list and nodes, but not data in nodes -template <class DATA_TYPE> -LLLinkedQueue<DATA_TYPE>::~LLLinkedQueue() -{ - reset(); -} - - -// put data into a node and stick it at the end of the list -template <class DATA_TYPE> -void LLLinkedQueue<DATA_TYPE>::push(const DATA_TYPE data) -{ - // make the new node - LLLinkedQueueNode<DATA_TYPE> *nodep = new LLLinkedQueueNode<DATA_TYPE>(data); - - addNodeAtEnd(nodep); -} - - -// search the list starting at mHead.mNextp and remove the link with mDatap == data -// set mCurrentp to mQueuep, or NULL if mQueuep points to node with mDatap == data -// return TRUE if found, FALSE if not found -template <class DATA_TYPE> -BOOL LLLinkedQueue<DATA_TYPE>::remove(const DATA_TYPE data) -{ - BOOL b_found = FALSE; - - LLLinkedQueueNode<DATA_TYPE> *currentp = mHead.mNextp; - - while (currentp) - { - if (currentp->mData == data) - { - b_found = TRUE; - - // if there is a next one, fix it - if (currentp->mNextp) - { - currentp->mNextp->mPrevp = currentp->mPrevp; - } - else // we are at end of list - { - mTail.mPrevp = currentp->mPrevp; - } - - // if there is a previous one, fix it - if (currentp->mPrevp) - { - currentp->mPrevp->mNextp = currentp->mNextp; - } - else // we are at beginning of list - { - mHead.mNextp = currentp->mNextp; - } - - // remove the node - delete currentp; - mLength--; - break; - } - currentp = currentp->mNextp; - } - - return b_found; -} - - -// remove all nodes from the list but do not delete associated data -template <class DATA_TYPE> -void LLLinkedQueue<DATA_TYPE>::reset() -{ - LLLinkedQueueNode<DATA_TYPE> *currentp; - LLLinkedQueueNode<DATA_TYPE> *nextp; - currentp = mHead.mNextp; - - while (currentp) - { - nextp = currentp->mNextp; - delete currentp; - currentp = nextp; - } - - // reset mHead and mCurrentp - mHead.mNextp = NULL; - mTail.mPrevp = NULL; - mLength = 0; -} - -template <class DATA_TYPE> -S32 LLLinkedQueue<DATA_TYPE>::getLength() const -{ - return mLength; -} - -template <class DATA_TYPE> -BOOL LLLinkedQueue<DATA_TYPE>::isEmpty() const -{ - return mLength <= 0; -} - -// check to see if data is in list -// set mCurrentp and mQueuep to the target of search if found, otherwise set mCurrentp to mQueuep -// return TRUE if found, FALSE if not found -template <class DATA_TYPE> -BOOL LLLinkedQueue<DATA_TYPE>::checkData(const DATA_TYPE data) const -{ - LLLinkedQueueNode<DATA_TYPE> *currentp = mHead.mNextp; - - while (currentp) - { - if (currentp->mData == data) - { - return TRUE; - } - currentp = currentp->mNextp; - } - return FALSE; -} - -template <class DATA_TYPE> -BOOL LLLinkedQueue<DATA_TYPE>::pop(DATA_TYPE &data) -{ - LLLinkedQueueNode<DATA_TYPE> *currentp; - - currentp = mHead.mNextp; - if (!currentp) - { - return FALSE; - } - - mHead.mNextp = currentp->mNextp; - if (currentp->mNextp) - { - currentp->mNextp->mPrevp = currentp->mPrevp; - } - else - { - mTail.mPrevp = currentp->mPrevp; - } - - data = currentp->mData; - delete currentp; - mLength--; - return TRUE; -} - -template <class DATA_TYPE> -BOOL LLLinkedQueue<DATA_TYPE>::peek(DATA_TYPE &data) -{ - LLLinkedQueueNode<DATA_TYPE> *currentp; - - currentp = mHead.mNextp; - if (!currentp) - { - return FALSE; - } - data = currentp->mData; - return TRUE; -} - - -////////////////////////////////////////////////////////////////////////////////////////// -// private members -////////////////////////////////////////////////////////////////////////////////////////// - - -// add node to end of list -// set mCurrentp to mQueuep -template <class DATA_TYPE> -void LLLinkedQueue<DATA_TYPE>::addNodeAtEnd(LLLinkedQueueNode<DATA_TYPE> *nodep) -{ - // add the node to the end of the list - nodep->mNextp = NULL; - nodep->mPrevp = mTail.mPrevp; - mTail.mPrevp = nodep; - - // if there's something in the list, fix its back pointer - if (nodep->mPrevp) - { - nodep->mPrevp->mNextp = nodep; - } - else // otherwise fix the head node - { - mHead.mNextp = nodep; - } - mLength++; -} - -#endif diff --git a/indra/llcommon/llliveappconfig.cpp b/indra/llcommon/llliveappconfig.cpp index 3a3dfa9f28..7c87c5a1a0 100755 --- a/indra/llcommon/llliveappconfig.cpp +++ b/indra/llcommon/llliveappconfig.cpp @@ -47,8 +47,8 @@ LLLiveAppConfig::~LLLiveAppConfig() // virtual bool LLLiveAppConfig::loadFile() { - llinfos << "LLLiveAppConfig::loadFile(): reading from " - << filename() << llendl; + LL_INFOS() << "LLLiveAppConfig::loadFile(): reading from " + << filename() << LL_ENDL; llifstream file(filename()); LLSD config; if (file.is_open()) @@ -56,15 +56,15 @@ bool LLLiveAppConfig::loadFile() LLSDSerialize::fromXML(config, file); if(!config.isMap()) { - llwarns << "Live app config not an map in " << filename() - << " Ignoring the data." << llendl; + LL_WARNS() << "Live app config not an map in " << filename() + << " Ignoring the data." << LL_ENDL; return false; } file.close(); } else { - llinfos << "Live file " << filename() << " does not exit." << llendl; + LL_INFOS() << "Live file " << filename() << " does not exit." << LL_ENDL; } // *NOTE: we do not handle the else case here because we would not // have attempted to load the file unless LLLiveFile had diff --git a/indra/llcommon/lllocalidhashmap.h b/indra/llcommon/lllocalidhashmap.h deleted file mode 100755 index 8f4f91a560..0000000000 --- a/indra/llcommon/lllocalidhashmap.h +++ /dev/null @@ -1,895 +0,0 @@ -/** - * @file lllocalidhashmap.h - * @brief Map specialized for dealing with local ids - * - * $LicenseInfo:firstyear=2003&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_LLLOCALIDHASHMAP_H -#define LL_LLLOCALIDHASHMAP_H - -#include "stdtypes.h" -#include "llerror.h" - -const S32 MAX_ITERS = 4; -// LocalID hash map - -// -// LLLocalIDHashNode -// - -template <class DATA, int SIZE> -class LLLocalIDHashNode -{ -public: - LLLocalIDHashNode(); - -public: - S32 mCount; - U32 mKey[SIZE]; - DATA mData[SIZE]; - LLLocalIDHashNode<DATA, SIZE> *mNextNodep; -}; - - -// -// LLLocalIDHashNode implementation -// -template <class DATA, int SIZE> -LLLocalIDHashNode<DATA, SIZE>::LLLocalIDHashNode() -{ - mCount = 0; - mNextNodep = NULL; -} - -// -// LLLocalIDHashMapIter -// -template <class DATA_TYPE, int SIZE> -class LLLocalIDHashMap; - -template <class DATA_TYPE, int SIZE> -class LLLocalIDHashMapIter -{ -public: - LLLocalIDHashMapIter(LLLocalIDHashMap<DATA_TYPE, SIZE> *hash_mapp); - ~LLLocalIDHashMapIter(); - - void setMap(LLLocalIDHashMap<DATA_TYPE, SIZE> *hash_mapp); - inline void first(); - inline void next(); - inline DATA_TYPE& current(); // *NOTE: Deprecate? Phoenix 2005-04-15 - inline BOOL done() const; - inline S32 currentBin() const; - inline void setBin(S32 bin); - - DATA_TYPE& operator*() const - { - return mCurHashNodep->mData[mCurHashNodeKey]; - } - DATA_TYPE* operator->() const - { - return &(operator*()); - } - - LLLocalIDHashMap<DATA_TYPE, SIZE> *mHashMapp; - LLLocalIDHashNode<DATA_TYPE, SIZE> *mCurHashNodep; - - S32 mCurHashMapNodeNum; - S32 mCurHashNodeKey; - - DATA_TYPE mNull; - - S32 mIterID; -}; - - - -template <class DATA_TYPE, int SIZE> -class LLLocalIDHashMap -{ -public: - friend class LLLocalIDHashMapIter<DATA_TYPE, SIZE>; - - LLLocalIDHashMap(); // DO NOT use this unless you explicitly setNull, or the data type constructs a "null" - // object by default - // basic constructor including sorter - LLLocalIDHashMap(const DATA_TYPE &null_data); - // Hack, this should really be a const ref, but I'm not doing it that way because the sim - // usually uses pointers. - ~LLLocalIDHashMap(); - - inline DATA_TYPE &get(const U32 local_id); - inline BOOL check(const U32 local_id) const; - inline DATA_TYPE &set(const U32 local_id, const DATA_TYPE data); - inline BOOL remove(const U32 local_id); - void removeAll(); - - void setNull(const DATA_TYPE data) { mNull = data; } - - inline S32 getLength() const; // Warning, NOT O(1!) - - void dumpIter(); - void dumpBin(U32 bin); - -protected: - // Only used by the iterator. - void addIter(LLLocalIDHashMapIter<DATA_TYPE, SIZE> *iter); - void removeIter(LLLocalIDHashMapIter<DATA_TYPE, SIZE> *iter); - - // Remove the item and shift all items afterward down the list, - // fixing up iterators as we go. - BOOL removeWithShift(const U32 local_id); - -protected: - LLLocalIDHashNode<DATA_TYPE, SIZE> mNodes[256]; - - S32 mIterCount; - LLLocalIDHashMapIter<DATA_TYPE, SIZE> *mIters[MAX_ITERS]; - - DATA_TYPE mNull; -}; - - -// -// LLLocalIDHashMap implementation -// - -template <class DATA_TYPE, int SIZE> -LLLocalIDHashMap<DATA_TYPE, SIZE>::LLLocalIDHashMap() -: mIterCount(0), - mNull() -{ - S32 i; - for (i = 0; i < MAX_ITERS; i++) - { - mIters[i] = NULL; - } -} - -template <class DATA_TYPE, int SIZE> -LLLocalIDHashMap<DATA_TYPE, SIZE>::LLLocalIDHashMap(const DATA_TYPE &null_data) -: mIterCount(0), - mNull(null_data) -{ - S32 i; - for (i = 0; i < MAX_ITERS; i++) - { - mIters[i] = NULL; - } -} - -template <class DATA_TYPE, int SIZE> -LLLocalIDHashMap<DATA_TYPE, SIZE>::~LLLocalIDHashMap() -{ - S32 i; - for (i = 0; i < MAX_ITERS; i++) - { - if (mIters[i]) - { - mIters[i]->mHashMapp = NULL; - mIterCount--; - } - } - removeAll(); -} - -template <class DATA_TYPE, int SIZE> -void LLLocalIDHashMap<DATA_TYPE, SIZE>::removeAll() -{ - S32 bin; - for (bin = 0; bin < 256; bin++) - { - LLLocalIDHashNode<DATA_TYPE, SIZE>* nodep = &mNodes[bin]; - - BOOL first = TRUE; - do // First node guaranteed to be there - { - S32 i; - const S32 count = nodep->mCount; - - // Iterate through all members of this node - for (i = 0; i < count; i++) - { - nodep->mData[i] = mNull; - } - - nodep->mCount = 0; - // Done with all objects in this node, go to the next. - - LLLocalIDHashNode<DATA_TYPE, SIZE>* curp = nodep; - nodep = nodep->mNextNodep; - - // Delete the node if it's not the first node - if (first) - { - first = FALSE; - curp->mNextNodep = NULL; - } - else - { - delete curp; - } - } while (nodep); - } -} - -template <class DATA_TYPE, int SIZE> -void LLLocalIDHashMap<DATA_TYPE, SIZE>::dumpIter() -{ - std::cout << "Hash map with " << mIterCount << " iterators" << std::endl; - - std::cout << "Hash Map Iterators:" << std::endl; - S32 i; - for (i = 0; i < MAX_ITERS; i++) - { - if (mIters[i]) - { - llinfos << i << " " << mIters[i]->mCurHashNodep << " " << mIters[i]->mCurHashNodeKey << llendl; - } - else - { - llinfos << i << "null" << llendl; - } - } -} - -template <class DATA_TYPE, int SIZE> -void LLLocalIDHashMap<DATA_TYPE, SIZE>::dumpBin(U32 bin) -{ - std::cout << "Dump bin " << bin << std::endl; - - LLLocalIDHashNode<DATA_TYPE, SIZE>* nodep = &mNodes[bin]; - S32 node = 0; - do // First node guaranteed to be there. - { - std::cout << "Bin " << bin - << " node " << node - << " count " << nodep->mCount - << " contains " << std::flush; - - S32 i; - for (i = 0; i < nodep->mCount; i++) - { - std::cout << nodep->mData[i] << " " << std::flush; - } - - std::cout << std::endl; - - nodep = nodep->mNextNodep; - node++; - } while (nodep); -} - -template <class DATA_TYPE, int SIZE> -inline S32 LLLocalIDHashMap<DATA_TYPE, SIZE>::getLength() const -{ - S32 count = 0; - S32 bin; - for (bin = 0; bin < 256; bin++) - { - const LLLocalIDHashNode<DATA_TYPE, SIZE>* nodep = &mNodes[bin]; - while (nodep) - { - count += nodep->mCount; - nodep = nodep->mNextNodep; - } - } - return count; -} - -template <class DATA_TYPE, int SIZE> -inline DATA_TYPE &LLLocalIDHashMap<DATA_TYPE, SIZE>::get(const U32 local_id) -{ - LLLocalIDHashNode<DATA_TYPE, SIZE>* nodep = &mNodes[local_id & 0xff]; - - do // First node guaranteed to be there - { - S32 i; - const S32 count = nodep->mCount; - - // Iterate through all members of this node - for (i = 0; i < count; i++) - { - if (nodep->mKey[i] == local_id) - { - // We found it. - return nodep->mData[i]; - } - } - - // Done with all objects in this node, go to the next. - nodep = nodep->mNextNodep; - } while (nodep); - - return mNull; -} - - -template <class DATA_TYPE, int SIZE> -inline BOOL LLLocalIDHashMap<DATA_TYPE, SIZE>::check(const U32 local_id) const -{ - const LLLocalIDHashNode<DATA_TYPE, SIZE>* nodep = &mNodes[local_id & 0xff]; - - do // First node guaranteed to be there - { - S32 i; - const S32 count = nodep->mCount; - - // Iterate through all members of this node - for (i = 0; i < count; i++) - { - if (nodep->mKey[i] == local_id) - { - // We found it. - return TRUE; - } - } - - // Done with all objects in this node, go to the next. - nodep = nodep->mNextNodep; - } while (nodep); - - // Didn't find anything - return FALSE; -} - - -template <class DATA_TYPE, int SIZE> -inline DATA_TYPE &LLLocalIDHashMap<DATA_TYPE, SIZE>::set(const U32 local_id, const DATA_TYPE data) -{ - // Set is just like a normal find, except that if we find a match - // we replace it with the input value. - // If we don't find a match, we append to the end of the list. - - LLLocalIDHashNode<DATA_TYPE, SIZE>* nodep = &mNodes[local_id & 0xff]; - - while (1) - { - const S32 count = nodep->mCount; - - S32 i; - for (i = 0; i < count; i++) - { - if (nodep->mKey[i] == local_id) - { - // We found a match for this key, replace the data with - // the incoming data. - nodep->mData[i] = data; - return nodep->mData[i]; - } - } - if (!nodep->mNextNodep) - { - // We've iterated through all of the keys without finding a match - if (i < SIZE) - { - // There's still some space on this node, append - // the key and data to it. - nodep->mKey[i] = local_id; - nodep->mData[i] = data; - nodep->mCount++; - - return nodep->mData[i]; - } - else - { - // This node is full, append a new node to the end. - nodep->mNextNodep = new LLLocalIDHashNode<DATA_TYPE, SIZE>; - nodep->mNextNodep->mKey[0] = local_id; - nodep->mNextNodep->mData[0] = data; - nodep->mNextNodep->mCount = 1; - - return nodep->mNextNodep->mData[0]; - } - } - - // No match on this node, go to the next - nodep = nodep->mNextNodep; - } -} - - -template <class DATA_TYPE, int SIZE> -inline BOOL LLLocalIDHashMap<DATA_TYPE, SIZE>::remove(const U32 local_id) -{ - // Remove is the trickiest operation. - // What we want to do is swap the last element of the last - // node if we find the one that we want to remove, but we have - // to deal with deleting the node from the tail if it's empty, but - // NOT if it's the only node left. - - const S32 node_index = local_id & 0xff; - - LLLocalIDHashNode<DATA_TYPE, SIZE>* nodep = &mNodes[node_index]; - - // A modification of the standard search algorithm. - do // First node guaranteed to be there - { - const S32 count = nodep->mCount; - - S32 i; - for (i = 0; i < count; i++) - { - if (nodep->mKey[i] == local_id) - { - // If we're removing the item currently pointed to by one - // or more iterators, we can just swap in the last item - // and back the iterator(s) up by one. - // Otherwise, we need to do a slow and safe shift of all - // items back to one position to fill the hole and fix up - // all iterators we find. - BOOL need_shift = FALSE; - S32 cur_iter; - if (mIterCount) - { - for (cur_iter = 0; cur_iter < MAX_ITERS; cur_iter++) - { - if (mIters[cur_iter]) - { - // We only care if the hash map node is on the one - // that we're working on. If it's before, we've already - // traversed it, if it's after, changing the order doesn't - // matter. - if (mIters[cur_iter]->mCurHashMapNodeNum == node_index) - { - if ((mIters[cur_iter]->mCurHashNodep == nodep) - && (mIters[cur_iter]->mCurHashNodeKey == i)) - { - // it's on the one we're deleting, we'll - // fix the iterator quickly below. - } - else - { - // We're trying to remove an item on this - // iterator's chain that this - // iterator doesn't point to! We need to do - // the slow remove-and-shift-down case. - need_shift = TRUE; - } - } - } - } - } - - // Removing an item that isn't pointed to by all iterators - if (need_shift) - { - return removeWithShift(local_id); - } - - // Fix the iterators that point to this node/i pair, the - // one we're deleting - for (cur_iter = 0; cur_iter < MAX_ITERS; cur_iter++) - { - if (mIters[cur_iter]) - { - // We only care if the hash map node is on the one - // that we're working on. If it's before, we've already - // traversed it, if it's after, changing the order doesn't - // matter. - if (mIters[cur_iter]->mCurHashMapNodeNum == node_index) - { - if ((mIters[cur_iter]->mCurHashNodep == nodep) - && (mIters[cur_iter]->mCurHashNodeKey == i)) - { - // We can handle the case where we're deleting - // the element we're on trivially (sort of). - if (nodep->mCount > 1) - { - // If we're not going to delete this node, - // it's OK. - mIters[cur_iter]->mCurHashNodeKey--; - } - else - { - // We're going to delete this node, because this - // is the last element on it. - - // Find the next node, and then back up one. - mIters[cur_iter]->next(); - mIters[cur_iter]->mCurHashNodeKey--; - } - } - } - } - } - - // We found the node that we want to remove. - // Find the last (and next-to-last) node, and the index of the last - // element. We could conceviably start from the node we're on, - // but that makes it more complicated, this is easier. - - LLLocalIDHashNode<DATA_TYPE, SIZE> *prevp = &mNodes[node_index]; - LLLocalIDHashNode<DATA_TYPE, SIZE> *lastp = prevp; - - // Find the last and next-to-last - while (lastp->mNextNodep) - { - prevp = lastp; - lastp = lastp->mNextNodep; - } - - // First, swap in the last to the current location. - nodep->mKey[i] = lastp->mKey[lastp->mCount - 1]; - nodep->mData[i] = lastp->mData[lastp->mCount - 1]; - - // Now, we delete the entry - lastp->mCount--; - lastp->mData[lastp->mCount] = mNull; - - if (!lastp->mCount) - { - // We deleted the last element! - if (lastp != &mNodes[local_id & 0xff]) - { - // Only blitz the node if it's not the head - // Set the previous node to point to NULL, then - // blitz the empty last node - prevp->mNextNodep = NULL; - delete lastp; - } - } - - return TRUE; - } - } - - // Iterate to the next node, we've scanned all the entries in this one. - nodep = nodep->mNextNodep; - } while (nodep); - - return FALSE; -} - -template <class DATA_TYPE, int SIZE> -BOOL LLLocalIDHashMap<DATA_TYPE, SIZE>::removeWithShift(const U32 local_id) -{ - const S32 node_index = local_id & 0xFF; - LLLocalIDHashNode<DATA_TYPE, SIZE>* nodep = &mNodes[node_index]; - LLLocalIDHashNode<DATA_TYPE, SIZE>* prevp = NULL; - BOOL found = FALSE; - - do // First node guaranteed to be there - { - const S32 count = nodep->mCount; - S32 i; - for (i = 0; i < count; i++) - { - if (nodep->mKey[i] == local_id) - { - // Found the item. Start shifting items from later - // in the list over this item. - found = TRUE; - } - - if (found) - { - // If there is an iterator on this node, we need to - // back it up. - S32 cur_iter; - for (cur_iter = 0; cur_iter <MAX_ITERS; cur_iter++) - { - LLLocalIDHashMapIter<DATA_TYPE, SIZE>* iter; - iter = mIters[cur_iter]; - // If an iterator is on this node,i pair, then back it up. - if (iter - && iter->mCurHashMapNodeNum == node_index - && iter->mCurHashNodep == nodep - && iter->mCurHashNodeKey == i) - { - if (i > 0) - { - // Don't need to move iterator nodep, since - // we're in the same node. - iter->mCurHashNodeKey--; - } - else if (prevp) - { - // need to go the previous node, last item - iter->mCurHashNodep = prevp; - iter->mCurHashNodeKey = prevp->mCount - 1; - } - else - { - // we're on the first item in the list, but - // need to go back anyhow. - - // BUG: If this deletion empties the list, - // iter->done() will be wrong until - // iter->next() is called. - iter->mCurHashNodeKey = -1; - } - } - } - - // Copy data from the next position into this position. - if (i < count-1) - { - // we're not on the last item in the node, - // so we can copy within the node - nodep->mKey[i] = nodep->mKey[i+1]; - nodep->mData[i] = nodep->mData[i+1]; - } - else if (nodep->mNextNodep) - { - // we're on the last item in the node, - // but there's a next node we can copy from - nodep->mKey[i] = nodep->mNextNodep->mKey[0]; - nodep->mData[i] = nodep->mNextNodep->mData[0]; - } - else - { - // We're on the last position in the list. - // No one to copy from. Replace with nothing. - nodep->mKey[i] = 0; - nodep->mData[i] = mNull; - } - } - } - - // Last node in chain, so delete the last node - if (found - && !nodep->mNextNodep) - { - // delete the last item off the last node - nodep->mCount--; - - if (nodep->mCount == 0) - { - // We deleted the last element! - if (nodep != &mNodes[node_index]) - { - // Always have a prevp if we're not the head. - llassert(prevp); - - // Only blitz the node if it's not the head - // Set the previous node to point to NULL, then - // blitz the empty last node - prevp->mNextNodep = NULL; - delete nodep; - nodep = NULL; - } - } - - // Deleted last item in chain, so we're done. - return found; - } - - prevp = nodep; - nodep = nodep->mNextNodep; - } while (nodep); - - return found; -} - -template <class DATA_TYPE, int SIZE> -void LLLocalIDHashMap<DATA_TYPE, SIZE>::removeIter(LLLocalIDHashMapIter<DATA_TYPE, SIZE> *iter) -{ - S32 i; - for (i = 0; i < MAX_ITERS; i++) - { - if (mIters[i] == iter) - { - mIters[i] = NULL; - mIterCount--; - return; - } - } - llerrs << "Iterator " << iter << " not found for removal in hash map!" << llendl; -} - -template <class DATA_TYPE, int SIZE> -void LLLocalIDHashMap<DATA_TYPE, SIZE>::addIter(LLLocalIDHashMapIter<DATA_TYPE, SIZE> *iter) -{ - S32 i; - for (i = 0; i < MAX_ITERS; i++) - { - if (mIters[i] == NULL) - { - mIters[i] = iter; - mIterCount++; - return; - } - } - llerrs << "More than " << MAX_ITERS << " iterating over a map simultaneously!" << llendl; -} - - - -// -// LLLocalIDHashMapIter Implementation -// -template <class DATA_TYPE, int SIZE> -LLLocalIDHashMapIter<DATA_TYPE, SIZE>::LLLocalIDHashMapIter(LLLocalIDHashMap<DATA_TYPE, SIZE> *hash_mapp) -{ - mHashMapp = NULL; - setMap(hash_mapp); -} - -template <class DATA_TYPE, int SIZE> -LLLocalIDHashMapIter<DATA_TYPE, SIZE>::~LLLocalIDHashMapIter() -{ - if (mHashMapp) - { - mHashMapp->removeIter(this); - } -} - -template <class DATA_TYPE, int SIZE> -void LLLocalIDHashMapIter<DATA_TYPE, SIZE>::setMap(LLLocalIDHashMap<DATA_TYPE, SIZE> *hash_mapp) -{ - if (mHashMapp) - { - mHashMapp->removeIter(this); - } - mHashMapp = hash_mapp; - if (mHashMapp) - { - mHashMapp->addIter(this); - } - - mCurHashNodep = NULL; - mCurHashMapNodeNum = -1; - mCurHashNodeKey = 0; -} - -template <class DATA_TYPE, int SIZE> -inline void LLLocalIDHashMapIter<DATA_TYPE, SIZE>::first() -{ - // Iterate through until we find the first non-empty node; - S32 i; - for (i = 0; i < 256; i++) - { - if (mHashMapp->mNodes[i].mCount) - { - - mCurHashNodep = &mHashMapp->mNodes[i]; - mCurHashMapNodeNum = i; - mCurHashNodeKey = 0; - //return mCurHashNodep->mData[0]; - return; - } - } - - // Completely empty! - mCurHashNodep = NULL; - //return mNull; - return; -} - -template <class DATA_TYPE, int SIZE> -inline BOOL LLLocalIDHashMapIter<DATA_TYPE, SIZE>::done() const -{ - return mCurHashNodep ? FALSE : TRUE; -} - -template <class DATA_TYPE, int SIZE> -inline S32 LLLocalIDHashMapIter<DATA_TYPE, SIZE>::currentBin() const -{ - if ( (mCurHashMapNodeNum > 255) - ||(mCurHashMapNodeNum < 0)) - { - return 0; - } - else - { - return mCurHashMapNodeNum; - } -} - -template <class DATA_TYPE, int SIZE> -inline void LLLocalIDHashMapIter<DATA_TYPE, SIZE>::setBin(S32 bin) -{ - // Iterate through until we find the first non-empty node; - S32 i; - bin = llclamp(bin, 0, 255); - for (i = bin; i < 256; i++) - { - if (mHashMapp->mNodes[i].mCount) - { - - mCurHashNodep = &mHashMapp->mNodes[i]; - mCurHashMapNodeNum = i; - mCurHashNodeKey = 0; - return; - } - } - for (i = 0; i < bin; i++) - { - if (mHashMapp->mNodes[i].mCount) - { - - mCurHashNodep = &mHashMapp->mNodes[i]; - mCurHashMapNodeNum = i; - mCurHashNodeKey = 0; - return; - } - } - // Completely empty! - mCurHashNodep = NULL; -} - -template <class DATA_TYPE, int SIZE> -inline DATA_TYPE &LLLocalIDHashMapIter<DATA_TYPE, SIZE>::current() -{ - if (!mCurHashNodep) - { - return mNull; - } - return mCurHashNodep->mData[mCurHashNodeKey]; -} - -template <class DATA_TYPE, int SIZE> -inline void LLLocalIDHashMapIter<DATA_TYPE, SIZE>::next() -{ - // No current entry, this iterator is done - if (!mCurHashNodep) - { - //return mNull; - return; - } - - // Go to the next element - mCurHashNodeKey++; - if (mCurHashNodeKey < mCurHashNodep->mCount) - { - // We're not done with this node, return the current element - //return mCurHashNodep->mData[mCurHashNodeKey]; - return; - } - - // Done with this node, move to the next - mCurHashNodep = mCurHashNodep->mNextNodep; - if (mCurHashNodep) - { - // Return the first element - mCurHashNodeKey = 0; - //return mCurHashNodep->mData[0]; - return; - } - - // Find the next non-empty node (keyed on the first byte) - mCurHashMapNodeNum++; - - S32 i; - for (i = mCurHashMapNodeNum; i < 256; i++) - { - if (mHashMapp->mNodes[i].mCount) - { - // We found one that wasn't empty - mCurHashNodep = &mHashMapp->mNodes[i]; - mCurHashMapNodeNum = i; - mCurHashNodeKey = 0; - //return mCurHashNodep->mData[0]; - return; - } - } - - // OK, we're done, nothing else to iterate - mCurHashNodep = NULL; - mHashMapp->mIterCount--; // Decrement since we're safe to do removes now - //return mNull; - return; -} - -#endif // LL_LLLOCALIDHASHMAP_H diff --git a/indra/llcommon/lllog.cpp b/indra/llcommon/lllog.cpp deleted file mode 100755 index fc4058b5c9..0000000000 --- a/indra/llcommon/lllog.cpp +++ /dev/null @@ -1,111 +0,0 @@ -/** - * @file lllog.cpp - * @author Don - * @date 2007-11-27 - * @brief Class to log messages to syslog for streambase to process. - * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" -#include "lllog.h" - -#include "llapp.h" -#include "llsd.h" -#include "llsdserialize.h" - - -class LLLogImpl -{ -public: - LLLogImpl(LLApp* app) : mApp(app) {} - ~LLLogImpl() {} - - void log(const std::string &message, LLSD& info); - bool useLegacyLogMessage(const std::string &message); - -private: - LLApp* mApp; -}; - - -//@brief Function to log a message to syslog for streambase to collect. -void LLLogImpl::log(const std::string &message, LLSD& info) -{ - static S32 sequence = 0; - LLSD log_config = mApp->getOption("log-messages"); - if (log_config.has(message)) - { - LLSD message_config = log_config[message]; - if (message_config.has("use-syslog")) - { - if (! message_config["use-syslog"].asBoolean()) - { - return; - } - } - } - llinfos << "LLLOGMESSAGE (" << (sequence++) << ") " << message - << " " << LLSDNotationStreamer(info) << llendl; -} - -//@brief Function to check if specified legacy log message should be sent. -bool LLLogImpl::useLegacyLogMessage(const std::string &message) -{ - LLSD log_config = mApp->getOption("log-messages"); - if (log_config.has(message)) - { - LLSD message_config = log_config[message]; - if (message_config.has("use-legacy")) - { - return message_config["use-legacy"].asBoolean(); - } - } - return true; -} - - -LLLog::LLLog(LLApp* app) -{ - mImpl = new LLLogImpl(app); -} - -LLLog::~LLLog() -{ - delete mImpl; - mImpl = NULL; -} - -void LLLog::log(const std::string &message, LLSD& info) -{ - if (mImpl) mImpl->log(message, info); -} - -bool LLLog::useLegacyLogMessage(const std::string &message) -{ - if (mImpl) - { - return mImpl->useLegacyLogMessage(message); - } - return true; -} - diff --git a/indra/llcommon/lllog.h b/indra/llcommon/lllog.h deleted file mode 100755 index 7964412e83..0000000000 --- a/indra/llcommon/lllog.h +++ /dev/null @@ -1,52 +0,0 @@ -/** - * @file lllog.h - * @author Don - * @date 2007-11-27 - * @brief Class to log messages to syslog for streambase to process. - * - * $LicenseInfo:firstyear=2007&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_LLLOG_H -#define LL_LLLOG_H - -#include <string> - -class LLLogImpl; -class LLApp; -class LLSD; - -class LL_COMMON_API LLLog -{ -public: - LLLog(LLApp* app); - virtual ~LLLog(); - - virtual void log(const std::string &message, LLSD& info); - virtual bool useLegacyLogMessage(const std::string &message); - -private: - LLLogImpl* mImpl; -}; - -#endif /* LL_LLLOG_H */ - diff --git a/indra/llcommon/lllslconstants.h b/indra/llcommon/lllslconstants.h deleted file mode 100755 index 926ce32d75..0000000000 --- a/indra/llcommon/lllslconstants.h +++ /dev/null @@ -1,242 +0,0 @@ -/** - * @file lllslconstants.h - * @author James Cook - * @brief Constants used in lsl. - * - * $LicenseInfo:firstyear=2006&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_LLLSLCONSTANTS_H -#define LL_LLLSLCONSTANTS_H - -// LSL: Return flags for llGetAgentInfo -const U32 AGENT_FLYING = 0x0001; -const U32 AGENT_ATTACHMENTS = 0x0002; -const U32 AGENT_SCRIPTED = 0x0004; -const U32 AGENT_MOUSELOOK = 0x0008; -const U32 AGENT_SITTING = 0x0010; -const U32 AGENT_ON_OBJECT = 0x0020; -const U32 AGENT_AWAY = 0x0040; -const U32 AGENT_WALKING = 0x0080; -const U32 AGENT_IN_AIR = 0x0100; -const U32 AGENT_TYPING = 0x0200; -const U32 AGENT_CROUCHING = 0x0400; -const U32 AGENT_BUSY = 0x0800; -const U32 AGENT_ALWAYS_RUN = 0x1000; -const U32 AGENT_AUTOPILOT = 0x2000; - -const S32 LSL_REMOTE_DATA_CHANNEL = 1; -const S32 LSL_REMOTE_DATA_REQUEST = 2; -const S32 LSL_REMOTE_DATA_REPLY = 3; - -// Constants used in extended LSL primitive setter and getters -const S32 LSL_PRIM_TYPE_LEGACY = 1; // No longer supported. -const S32 LSL_PRIM_MATERIAL = 2; -const S32 LSL_PRIM_PHYSICS = 3; -const S32 LSL_PRIM_TEMP_ON_REZ = 4; -const S32 LSL_PRIM_PHANTOM = 5; -const S32 LSL_PRIM_POSITION = 6; -const S32 LSL_PRIM_SIZE = 7; -const S32 LSL_PRIM_ROTATION = 8; -const S32 LSL_PRIM_TYPE = 9; // Replacement for LSL_PRIM_TYPE_LEGACY -const S32 LSL_PRIM_TEXTURE = 17; -const S32 LSL_PRIM_COLOR = 18; -const S32 LSL_PRIM_BUMP_SHINY = 19; -const S32 LSL_PRIM_FULLBRIGHT = 20; -const S32 LSL_PRIM_FLEXIBLE = 21; -const S32 LSL_PRIM_TEXGEN = 22; -const S32 LSL_PRIM_POINT_LIGHT = 23; -const S32 LSL_PRIM_CAST_SHADOWS = 24; -const S32 LSL_PRIM_GLOW = 25; -const S32 LSL_PRIM_TEXT = 26; -const S32 LSL_PRIM_NAME = 27; -const S32 LSL_PRIM_DESC = 28; -const S32 LSL_PRIM_ROT_LOCAL = 29; -const S32 LSL_PRIM_PHYSICS_SHAPE_TYPE = 30; -const S32 LSL_PRIM_OMEGA = 32; -const S32 LSL_PRIM_POS_LOCAL = 33; -const S32 LSL_PRIM_LINK_TARGET = 34; -const S32 LSL_PRIM_SLICE = 35; - -const S32 LSL_PRIM_PHYSICS_SHAPE_PRIM = 0; -const S32 LSL_PRIM_PHYSICS_SHAPE_NONE = 1; -const S32 LSL_PRIM_PHYSICS_SHAPE_CONVEX = 2; - -const S32 LSL_PRIM_TYPE_BOX = 0; -const S32 LSL_PRIM_TYPE_CYLINDER= 1; -const S32 LSL_PRIM_TYPE_PRISM = 2; -const S32 LSL_PRIM_TYPE_SPHERE = 3; -const S32 LSL_PRIM_TYPE_TORUS = 4; -const S32 LSL_PRIM_TYPE_TUBE = 5; -const S32 LSL_PRIM_TYPE_RING = 6; -const S32 LSL_PRIM_TYPE_SCULPT = 7; - -const S32 LSL_PRIM_HOLE_DEFAULT = 0x00; -const S32 LSL_PRIM_HOLE_CIRCLE = 0x10; -const S32 LSL_PRIM_HOLE_SQUARE = 0x20; -const S32 LSL_PRIM_HOLE_TRIANGLE= 0x30; - -const S32 LSL_PRIM_MATERIAL_STONE = 0; -const S32 LSL_PRIM_MATERIAL_METAL = 1; -const S32 LSL_PRIM_MATERIAL_GLASS = 2; -const S32 LSL_PRIM_MATERIAL_WOOD = 3; -const S32 LSL_PRIM_MATERIAL_FLESH = 4; -const S32 LSL_PRIM_MATERIAL_PLASTIC = 5; -const S32 LSL_PRIM_MATERIAL_RUBBER = 6; -const S32 LSL_PRIM_MATERIAL_LIGHT = 7; - -const S32 LSL_PRIM_SHINY_NONE = 0; -const S32 LSL_PRIM_SHINY_LOW = 1; -const S32 LSL_PRIM_SHINY_MEDIUM = 2; -const S32 LSL_PRIM_SHINY_HIGH = 3; - -const S32 LSL_PRIM_TEXGEN_DEFAULT = 0; -const S32 LSL_PRIM_TEXGEN_PLANAR = 1; - -const S32 LSL_PRIM_BUMP_NONE = 0; -const S32 LSL_PRIM_BUMP_BRIGHT = 1; -const S32 LSL_PRIM_BUMP_DARK = 2; -const S32 LSL_PRIM_BUMP_WOOD = 3; -const S32 LSL_PRIM_BUMP_BARK = 4; -const S32 LSL_PRIM_BUMP_BRICKS = 5; -const S32 LSL_PRIM_BUMP_CHECKER = 6; -const S32 LSL_PRIM_BUMP_CONCRETE = 7; -const S32 LSL_PRIM_BUMP_TILE = 8; -const S32 LSL_PRIM_BUMP_STONE = 9; -const S32 LSL_PRIM_BUMP_DISKS = 10; -const S32 LSL_PRIM_BUMP_GRAVEL = 11; -const S32 LSL_PRIM_BUMP_BLOBS = 12; -const S32 LSL_PRIM_BUMP_SIDING = 13; -const S32 LSL_PRIM_BUMP_LARGETILE = 14; -const S32 LSL_PRIM_BUMP_STUCCO = 15; -const S32 LSL_PRIM_BUMP_SUCTION = 16; -const S32 LSL_PRIM_BUMP_WEAVE = 17; - -const S32 LSL_PRIM_SCULPT_TYPE_SPHERE = 1; -const S32 LSL_PRIM_SCULPT_TYPE_TORUS = 2; -const S32 LSL_PRIM_SCULPT_TYPE_PLANE = 3; -const S32 LSL_PRIM_SCULPT_TYPE_CYLINDER = 4; -const S32 LSL_PRIM_SCULPT_TYPE_MASK = 7; -const S32 LSL_PRIM_SCULPT_FLAG_INVERT = 64; -const S32 LSL_PRIM_SCULPT_FLAG_MIRROR = 128; - -const S32 LSL_ALL_SIDES = -1; -const S32 LSL_LINK_ROOT = 1; -const S32 LSL_LINK_FIRST_CHILD = 2; -const S32 LSL_LINK_SET = -1; -const S32 LSL_LINK_ALL_OTHERS = -2; -const S32 LSL_LINK_ALL_CHILDREN = -3; -const S32 LSL_LINK_THIS = -4; - -// LSL constants for llSetForSell -const S32 SELL_NOT = 0; -const S32 SELL_ORIGINAL = 1; -const S32 SELL_COPY = 2; -const S32 SELL_CONTENTS = 3; - -// LSL constants for llSetPayPrice -const S32 PAY_PRICE_HIDE = -1; -const S32 PAY_PRICE_DEFAULT = -2; -const S32 MAX_PAY_BUTTONS = 4; -const S32 PAY_BUTTON_DEFAULT_0 = 1; -const S32 PAY_BUTTON_DEFAULT_1 = 5; -const S32 PAY_BUTTON_DEFAULT_2 = 10; -const S32 PAY_BUTTON_DEFAULT_3 = 20; - -// lsl email registration. -const S32 EMAIL_REG_SUBSCRIBE_OBJECT = 0x01; -const S32 EMAIL_REG_UNSUBSCRIBE_OBJECT = 0x02; -const S32 EMAIL_REG_UNSUBSCRIBE_SIM = 0x04; - -const S32 LIST_STAT_RANGE = 0; -const S32 LIST_STAT_MIN = 1; -const S32 LIST_STAT_MAX = 2; -const S32 LIST_STAT_MEAN = 3; -const S32 LIST_STAT_MEDIAN = 4; -const S32 LIST_STAT_STD_DEV = 5; -const S32 LIST_STAT_SUM = 6; -const S32 LIST_STAT_SUM_SQUARES = 7; -const S32 LIST_STAT_NUM_COUNT = 8; -const S32 LIST_STAT_GEO_MEAN = 9; - -const S32 STRING_TRIM_HEAD = 0x01; -const S32 STRING_TRIM_TAIL = 0x02; -const S32 STRING_TRIM = STRING_TRIM_HEAD | STRING_TRIM_TAIL; - -// llGetObjectDetails -const S32 OBJECT_UNKNOWN_DETAIL = -1; -const S32 OBJECT_NAME = 1; -const S32 OBJECT_DESC = 2; -const S32 OBJECT_POS = 3; -const S32 OBJECT_ROT = 4; -const S32 OBJECT_VELOCITY = 5; -const S32 OBJECT_OWNER = 6; -const S32 OBJECT_GROUP = 7; -const S32 OBJECT_CREATOR = 8; -const S32 OBJECT_RUNNING_SCRIPT_COUNT = 9; -const S32 OBJECT_TOTAL_SCRIPT_COUNT = 10; -const S32 OBJECT_SCRIPT_MEMORY = 11; -const S32 OBJECT_SCRIPT_TIME = 12; -const S32 OBJECT_PRIM_EQUIVALENCE = 13; -const S32 OBJECT_SERVER_COST = 14; -const S32 OBJECT_STREAMING_COST = 15; -const S32 OBJECT_PHYSICS_COST = 16; -const S32 OBJECT_CHARACTER_TIME = 17; -const S32 OBJECT_ROOT = 18; -const S32 OBJECT_ATTACHED_POINT = 19; -const S32 OBJECT_PATHFINDING_TYPE = 20; -const S32 OBJECT_PHYSICS = 21; -const S32 OBJECT_PHANTOM = 22; -const S32 OBJECT_TEMP_ON_REZ = 23; -const S32 OBJECT_RENDER_WEIGHT = 24; - -// llTextBox() magic token string - yes this is a hack. sue me. -char const* const TEXTBOX_MAGIC_TOKEN = "!!llTextBox!!"; - -// changed() event flags -const U32 CHANGED_NONE = 0x0; -const U32 CHANGED_INVENTORY = 0x1; -const U32 CHANGED_COLOR = 0x2; -const U32 CHANGED_SHAPE = 0x4; -const U32 CHANGED_SCALE = 0x8; -const U32 CHANGED_TEXTURE = 0x10; -const U32 CHANGED_LINK = 0x20; -const U32 CHANGED_ALLOWED_DROP = 0x40; -const U32 CHANGED_OWNER = 0x80; -const U32 CHANGED_REGION = 0x100; -const U32 CHANGED_TELEPORT = 0x200; -const U32 CHANGED_REGION_START = 0x400; -const U32 CHANGED_MEDIA = 0x800; - -// Possible error results -const U32 LSL_STATUS_OK = 0; -const U32 LSL_STATUS_MALFORMED_PARAMS = 1000; -const U32 LSL_STATUS_TYPE_MISMATCH = 1001; -const U32 LSL_STATUS_BOUNDS_ERROR = 1002; -const U32 LSL_STATUS_NOT_FOUND = 1003; -const U32 LSL_STATUS_NOT_SUPPORTED = 1004; -const U32 LSL_STATUS_INTERNAL_ERROR = 1999; - -// Start per-function errors below, starting at 2000: -const U32 LSL_STATUS_WHITELIST_FAILED = 2001; - -#endif diff --git a/indra/llcommon/llmap.h b/indra/llcommon/llmap.h deleted file mode 100755 index 6294a15d3b..0000000000 --- a/indra/llcommon/llmap.h +++ /dev/null @@ -1,245 +0,0 @@ -/** - * @file llmap.h - * @brief LLMap class header file - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_LLMAP_H -#define LL_LLMAP_H - -// llmap uses the fast stl library code in a manner consistant with LLSkipMap, et. al. - -template<class INDEX_TYPE, class MAPPED_TYPE> class LLMap -{ -private: - typedef typename std::map<INDEX_TYPE, MAPPED_TYPE> stl_map_t; - typedef typename stl_map_t::iterator stl_iter_t; - typedef typename stl_map_t::value_type stl_value_t; - - stl_map_t mStlMap; - stl_iter_t mCurIter; // *iterator = pair<const INDEX_TYPE, MAPPED_TYPE> - MAPPED_TYPE dummy_data; - INDEX_TYPE dummy_index; - -public: - LLMap() : mStlMap() - { - memset((void*)(&dummy_data), 0x0, sizeof(MAPPED_TYPE)); - memset((void*)(&dummy_index), 0x0, sizeof(INDEX_TYPE)); - mCurIter = mStlMap.begin(); - } - ~LLMap() - { - mStlMap.clear(); - } - - // use these functions to itterate through a list - void resetMap() - { - mCurIter = mStlMap.begin(); - } - - // get the current data and bump mCurrentp - // This is kind of screwy since it returns a reference; - // We have to have a dummy value for when we reach the end - // or in case we have an empty list. Presumably, this value - // will initialize to some NULL value that will end the iterator. - // We really shouldn't be using getNextData() or getNextKey() anyway... - MAPPED_TYPE &getNextData() - { - if (mCurIter == mStlMap.end()) - { - return dummy_data; - } - else - { - return (*mCurIter++).second; - } - } - - const INDEX_TYPE &getNextKey() - { - if (mCurIter == mStlMap.end()) - { - return dummy_index; - } - else - { - return (*mCurIter++).first; - } - } - - MAPPED_TYPE &getFirstData() - { - resetMap(); - return getNextData(); - } - - const INDEX_TYPE &getFirstKey() - { - resetMap(); - return getNextKey(); - } - - S32 getLength() - { - return mStlMap.size(); - } - - void addData(const INDEX_TYPE &index, MAPPED_TYPE pointed_to) - { - mStlMap.insert(stl_value_t(index, pointed_to)); - } - - void addData(const INDEX_TYPE &index) - { - mStlMap.insert(stl_value_t(index, dummy_data)); - } - - // if index doesn't exist, then insert a new node and return it - MAPPED_TYPE &getData(const INDEX_TYPE &index) - { - std::pair<stl_iter_t, bool> res; - res = mStlMap.insert(stl_value_t(index, dummy_data)); - return res.first->second; - } - - // if index doesn't exist, then insert a new node, return it, and set b_new_entry to true - MAPPED_TYPE &getData(const INDEX_TYPE &index, BOOL &b_new_entry) - { - std::pair<stl_iter_t, bool> res; - res = mStlMap.insert(stl_value_t(index, dummy_data)); - b_new_entry = res.second; - return res.first->second; - } - - // If there, returns the data. - // If not, returns NULL. - // Never adds entries to the map. - MAPPED_TYPE getIfThere(const INDEX_TYPE &index) - { - stl_iter_t iter; - iter = mStlMap.find(index); - if (iter == mStlMap.end()) - { - return (MAPPED_TYPE)0; - } - else - { - return (*iter).second; - } - } - - - // if index doesn't exist, then make a new node and return it - MAPPED_TYPE &operator[](const INDEX_TYPE &index) - { - return getData(index); - } - - // do a reverse look-up, return NULL if failed - INDEX_TYPE reverseLookup(const MAPPED_TYPE data) - { - stl_iter_t iter; - stl_iter_t end_iter; - iter = mStlMap.begin(); - end_iter = mStlMap.end(); - while (iter != end_iter) - { - if ((*iter).second == data) - return (*iter).first; - iter++; - } - return (INDEX_TYPE)0; - } - - BOOL removeData(const INDEX_TYPE &index) - { - mCurIter = mStlMap.find(index); - if (mCurIter == mStlMap.end()) - { - return FALSE; - } - else - { - stl_iter_t iter = mCurIter++; // incrament mCurIter to the next element - mStlMap.erase(iter); - return TRUE; - } - } - - // does this index exist? - BOOL checkData(const INDEX_TYPE &index) - { - stl_iter_t iter; - iter = mStlMap.find(index); - if (iter == mStlMap.end()) - { - return FALSE; - } - else - { - mCurIter = iter; - return TRUE; - } - } - - BOOL deleteData(const INDEX_TYPE &index) - { - mCurIter = mStlMap.find(index); - if (mCurIter == mStlMap.end()) - { - return FALSE; - } - else - { - stl_iter_t iter = mCurIter++; // incrament mCurIter to the next element - delete (*iter).second; - mStlMap.erase(iter); - return TRUE; - } - } - - void deleteAllData() - { - stl_iter_t iter; - stl_iter_t end_iter; - iter = mStlMap.begin(); - end_iter = mStlMap.end(); - while (iter != end_iter) - { - delete (*iter).second; - iter++; - } - mStlMap.clear(); - mCurIter = mStlMap.end(); - } - - void removeAllData() - { - mStlMap.clear(); - } -}; - - -#endif diff --git a/indra/llcommon/llmd5.cpp b/indra/llcommon/llmd5.cpp index 1409c55d1c..ed80af36d8 100755 --- a/indra/llcommon/llmd5.cpp +++ b/indra/llcommon/llmd5.cpp @@ -76,7 +76,6 @@ documentation and/or software. #include "llmd5.h" -#include <cassert> #include <iostream> // cerr // how many bytes to grab at a time when checking files diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp index 70ad10ad55..e0b2aa87c2 100755 --- a/indra/llcommon/llmemory.cpp +++ b/indra/llcommon/llmemory.cpp @@ -27,12 +27,9 @@ #include "linden_common.h" -//#if MEM_TRACK_MEM #include "llthread.h" -//#endif #if defined(LL_WINDOWS) -//# include <windows.h> # include <psapi.h> #elif defined(LL_DARWIN) # include <sys/types.h> @@ -46,15 +43,18 @@ #include "llsys.h" #include "llframetimer.h" +#include "lltrace.h" //---------------------------------------------------------------------------- //static char* LLMemory::reserveMem = 0; -U32 LLMemory::sAvailPhysicalMemInKB = U32_MAX ; -U32 LLMemory::sMaxPhysicalMemInKB = 0; -U32 LLMemory::sAllocatedMemInKB = 0; -U32 LLMemory::sAllocatedPageSizeInKB = 0 ; -U32 LLMemory::sMaxHeapSizeInKB = U32_MAX ; +U32Kilobytes LLMemory::sAvailPhysicalMemInKB(U32_MAX); +U32Kilobytes LLMemory::sMaxPhysicalMemInKB(0); +static LLTrace::SampleStatHandle<F64Megabytes> sAllocatedMem("allocated_mem", "active memory in use by application"); +static LLTrace::SampleStatHandle<F64Megabytes> sVirtualMem("virtual_mem", "virtual memory assigned to application"); +U32Kilobytes LLMemory::sAllocatedMemInKB(0); +U32Kilobytes LLMemory::sAllocatedPageSizeInKB(0); +U32Kilobytes LLMemory::sMaxHeapSizeInKB(U32_MAX); BOOL LLMemory::sEnableMemoryFailurePrevention = FALSE; #if __DEBUG_PRIVATE_MEM__ @@ -67,7 +67,7 @@ void ll_assert_aligned_func(uintptr_t ptr,U32 alignment) // Redundant, place to set breakpoints. if (ptr%alignment!=0) { - llwarns << "alignment check failed" << llendl; + LL_WARNS() << "alignment check failed" << LL_ENDL; } llassert(ptr%alignment==0); #endif @@ -97,9 +97,9 @@ void LLMemory::freeReserve() } //static -void LLMemory::initMaxHeapSizeGB(F32 max_heap_size_gb, BOOL prevent_heap_failure) +void LLMemory::initMaxHeapSizeGB(F32Gigabytes max_heap_size, BOOL prevent_heap_failure) { - sMaxHeapSizeInKB = (U32)(max_heap_size_gb * 1024 * 1024) ; + sMaxHeapSizeInKB = max_heap_size; sEnableMemoryFailurePrevention = prevent_heap_failure ; } @@ -112,14 +112,16 @@ void LLMemory::updateMemoryInfo() if (!GetProcessMemoryInfo(self, &counters, sizeof(counters))) { - llwarns << "GetProcessMemoryInfo failed" << llendl; + LL_WARNS() << "GetProcessMemoryInfo failed" << LL_ENDL; return ; } - sAllocatedMemInKB = (U32)(counters.WorkingSetSize / 1024) ; - sAllocatedPageSizeInKB = (U32)(counters.PagefileUsage / 1024) ; + sAllocatedMemInKB = (U32Bytes)(counters.WorkingSetSize) ; + sample(sAllocatedMem, sAllocatedMemInKB); + sAllocatedPageSizeInKB = (U32Bytes)(counters.PagefileUsage) ; + sample(sVirtualMem, sAllocatedPageSizeInKB); - U32 avail_phys, avail_virtual; + U32Kilobytes avail_phys, avail_virtual; LLMemoryInfo::getAvailableMemoryKB(avail_phys, avail_virtual) ; sMaxPhysicalMemInKB = llmin(avail_phys + sAllocatedMemInKB, sMaxHeapSizeInKB); @@ -129,13 +131,13 @@ void LLMemory::updateMemoryInfo() } else { - sAvailPhysicalMemInKB = 0 ; + sAvailPhysicalMemInKB = U32Kilobytes(0); } #else //not valid for other systems for now. - sAllocatedMemInKB = (U32)(LLMemory::getCurrentRSS() / 1024) ; - sMaxPhysicalMemInKB = U32_MAX ; - sAvailPhysicalMemInKB = U32_MAX ; + sAllocatedMemInKB = (U32Bytes)LLMemory::getCurrentRSS(); + sMaxPhysicalMemInKB = (U32Bytes)U32_MAX ; + sAvailPhysicalMemInKB = (U32Bytes)U32_MAX ; #endif return ; @@ -156,7 +158,7 @@ void* LLMemory::tryToAlloc(void* address, U32 size) { if(!VirtualFree(address, 0, MEM_RELEASE)) { - llerrs << "error happens when free some memory reservation." << llendl ; + LL_ERRS() << "error happens when free some memory reservation." << LL_ENDL ; } } return address ; @@ -174,14 +176,14 @@ void LLMemory::logMemoryInfo(BOOL update) LLPrivateMemoryPoolManager::getInstance()->updateStatistics() ; } - llinfos << "Current allocated physical memory(KB): " << sAllocatedMemInKB << llendl ; - llinfos << "Current allocated page size (KB): " << sAllocatedPageSizeInKB << llendl ; - llinfos << "Current availabe physical memory(KB): " << sAvailPhysicalMemInKB << llendl ; - llinfos << "Current max usable memory(KB): " << sMaxPhysicalMemInKB << llendl ; + LL_INFOS() << "Current allocated physical memory(KB): " << sAllocatedMemInKB << LL_ENDL ; + LL_INFOS() << "Current allocated page size (KB): " << sAllocatedPageSizeInKB << LL_ENDL ; + LL_INFOS() << "Current availabe physical memory(KB): " << sAvailPhysicalMemInKB << LL_ENDL ; + LL_INFOS() << "Current max usable memory(KB): " << sMaxPhysicalMemInKB << LL_ENDL ; - llinfos << "--- private pool information -- " << llendl ; - llinfos << "Total reserved (KB): " << LLPrivateMemoryPoolManager::getInstance()->mTotalReservedSize / 1024 << llendl ; - llinfos << "Total allocated (KB): " << LLPrivateMemoryPoolManager::getInstance()->mTotalAllocatedSize / 1024 << llendl ; + LL_INFOS() << "--- private pool information -- " << LL_ENDL ; + LL_INFOS() << "Total reserved (KB): " << LLPrivateMemoryPoolManager::getInstance()->mTotalReservedSize / 1024 << LL_ENDL ; + LL_INFOS() << "Total allocated (KB): " << LLPrivateMemoryPoolManager::getInstance()->mTotalAllocatedSize / 1024 << LL_ENDL ; } //return 0: everything is normal; @@ -190,8 +192,8 @@ void LLMemory::logMemoryInfo(BOOL update) //static bool LLMemory::isMemoryPoolLow() { - static const U32 LOW_MEMEOY_POOL_THRESHOLD_KB = 64 * 1024 ; //64 MB for emergency use - const static U32 MAX_SIZE_CHECKED_MEMORY_BLOCK = 64 * 1024 * 1024 ; //64 MB + static const U32Megabytes LOW_MEMORY_POOL_THRESHOLD(64); + const static U32Megabytes MAX_SIZE_CHECKED_MEMORY_BLOCK(64); static void* last_reserved_address = NULL ; if(!sEnableMemoryFailurePrevention) @@ -199,32 +201,32 @@ bool LLMemory::isMemoryPoolLow() return false ; //no memory failure prevention. } - if(sAvailPhysicalMemInKB < (LOW_MEMEOY_POOL_THRESHOLD_KB >> 2)) //out of physical memory + if(sAvailPhysicalMemInKB < (LOW_MEMORY_POOL_THRESHOLD / 4)) //out of physical memory { return true ; } - if(sAllocatedPageSizeInKB + (LOW_MEMEOY_POOL_THRESHOLD_KB >> 2) > sMaxHeapSizeInKB) //out of virtual address space. + if(sAllocatedPageSizeInKB + (LOW_MEMORY_POOL_THRESHOLD / 4) > sMaxHeapSizeInKB) //out of virtual address space. { return true ; } - bool is_low = (S32)(sAvailPhysicalMemInKB < LOW_MEMEOY_POOL_THRESHOLD_KB || - sAllocatedPageSizeInKB + LOW_MEMEOY_POOL_THRESHOLD_KB > sMaxHeapSizeInKB) ; + bool is_low = (S32)(sAvailPhysicalMemInKB < LOW_MEMORY_POOL_THRESHOLD + || sAllocatedPageSizeInKB + LOW_MEMORY_POOL_THRESHOLD > sMaxHeapSizeInKB) ; //check the virtual address space fragmentation if(!is_low) { if(!last_reserved_address) { - last_reserved_address = LLMemory::tryToAlloc(last_reserved_address, MAX_SIZE_CHECKED_MEMORY_BLOCK) ; + last_reserved_address = LLMemory::tryToAlloc(last_reserved_address, MAX_SIZE_CHECKED_MEMORY_BLOCK.value()) ; } else { - last_reserved_address = LLMemory::tryToAlloc(last_reserved_address, MAX_SIZE_CHECKED_MEMORY_BLOCK) ; + last_reserved_address = LLMemory::tryToAlloc(last_reserved_address, MAX_SIZE_CHECKED_MEMORY_BLOCK.value()) ; if(!last_reserved_address) //failed, try once more { - last_reserved_address = LLMemory::tryToAlloc(last_reserved_address, MAX_SIZE_CHECKED_MEMORY_BLOCK) ; + last_reserved_address = LLMemory::tryToAlloc(last_reserved_address, MAX_SIZE_CHECKED_MEMORY_BLOCK.value()) ; } } @@ -235,19 +237,19 @@ bool LLMemory::isMemoryPoolLow() } //static -U32 LLMemory::getAvailableMemKB() +U32Kilobytes LLMemory::getAvailableMemKB() { return sAvailPhysicalMemInKB ; } //static -U32 LLMemory::getMaxMemKB() +U32Kilobytes LLMemory::getMaxMemKB() { return sMaxPhysicalMemInKB ; } //static -U32 LLMemory::getAllocatedMemKB() +U32Kilobytes LLMemory::getAllocatedMemKB() { return sAllocatedMemInKB ; } @@ -263,7 +265,7 @@ U64 LLMemory::getCurrentRSS() if (!GetProcessMemoryInfo(self, &counters, sizeof(counters))) { - llwarns << "GetProcessMemoryInfo failed" << llendl; + LL_WARNS() << "GetProcessMemoryInfo failed" << LL_ENDL; return 0; } @@ -301,7 +303,7 @@ U32 LLMemory::getWorkingSetSize() // if (sysctl(ctl, 2, &page_size, &size, NULL, 0) == -1) // { -// llwarns << "Couldn't get page size" << llendl; +// LL_WARNS() << "Couldn't get page size" << LL_ENDL; // return 0; // } else { // return page_size; @@ -320,11 +322,11 @@ U64 LLMemory::getCurrentRSS() // If we ever wanted it, the process virtual size is also available as: // virtualSize = basicInfo.virtual_size; -// llinfos << "resident size is " << residentSize << llendl; +// LL_INFOS() << "resident size is " << residentSize << LL_ENDL; } else { - llwarns << "task_info failed" << llendl; + LL_WARNS() << "task_info failed" << LL_ENDL; } return residentSize; @@ -345,7 +347,7 @@ U64 LLMemory::getCurrentRSS() if (fp == NULL) { - llwarns << "couldn't open " << statPath << llendl; + LL_WARNS() << "couldn't open " << statPath << LL_ENDL; goto bail; } @@ -358,7 +360,7 @@ U64 LLMemory::getCurrentRSS() &rss); if (ret != 1) { - llwarns << "couldn't parse contents of " << statPath << llendl; + LL_WARNS() << "couldn't parse contents of " << statPath << LL_ENDL; rss = 0; } } @@ -388,12 +390,12 @@ U64 LLMemory::getCurrentRSS() sprintf(path, "/proc/%d/psinfo", (int)getpid()); int proc_fd = -1; if((proc_fd = open(path, O_RDONLY)) == -1){ - llwarns << "LLmemory::getCurrentRSS() unable to open " << path << ". Returning 0 RSS!" << llendl; + LL_WARNS() << "LLmemory::getCurrentRSS() unable to open " << path << ". Returning 0 RSS!" << LL_ENDL; return 0; } psinfo_t proc_psinfo; if(read(proc_fd, &proc_psinfo, sizeof(psinfo_t)) != sizeof(psinfo_t)){ - llwarns << "LLmemory::getCurrentRSS() Unable to read from " << path << ". Returning 0 RSS!" << llendl; + LL_WARNS() << "LLmemory::getCurrentRSS() Unable to read from " << path << ". Returning 0 RSS!" << LL_ENDL; close(proc_fd); return 0; } @@ -423,141 +425,6 @@ U32 LLMemory::getWorkingSetSize() #endif //-------------------------------------------------------------------------------------------------- -#if MEM_TRACK_MEM -#include "llframetimer.h" - -//static -LLMemTracker* LLMemTracker::sInstance = NULL ; - -LLMemTracker::LLMemTracker() -{ - mLastAllocatedMem = LLMemory::getWorkingSetSize() ; - mCapacity = 128 ; - mCurIndex = 0 ; - mCounter = 0 ; - mDrawnIndex = 0 ; - mPaused = FALSE ; - - mMutexp = new LLMutex() ; - mStringBuffer = new char*[128] ; - mStringBuffer[0] = new char[mCapacity * 128] ; - for(S32 i = 1 ; i < mCapacity ; i++) - { - mStringBuffer[i] = mStringBuffer[i-1] + 128 ; - } -} - -LLMemTracker::~LLMemTracker() -{ - delete[] mStringBuffer[0] ; - delete[] mStringBuffer; - delete mMutexp ; -} - -//static -LLMemTracker* LLMemTracker::getInstance() -{ - if(!sInstance) - { - sInstance = new LLMemTracker() ; - } - return sInstance ; -} - -//static -void LLMemTracker::release() -{ - if(sInstance) - { - delete sInstance ; - sInstance = NULL ; - } -} - -//static -void LLMemTracker::track(const char* function, const int line) -{ - static const S32 MIN_ALLOCATION = 0 ; //1KB - - if(mPaused) - { - return ; - } - - U32 allocated_mem = LLMemory::getWorkingSetSize() ; - - LLMutexLock lock(mMutexp) ; - - S32 delta_mem = allocated_mem - mLastAllocatedMem ; - mLastAllocatedMem = allocated_mem ; - - if(delta_mem <= 0) - { - return ; //occupied memory does not grow - } - - if(delta_mem < MIN_ALLOCATION) - { - return ; - } - - char* buffer = mStringBuffer[mCurIndex++] ; - F32 time = (F32)LLFrameTimer::getElapsedSeconds() ; - S32 hours = (S32)(time / (60*60)); - S32 mins = (S32)((time - hours*(60*60)) / 60); - S32 secs = (S32)((time - hours*(60*60) - mins*60)); - strcpy(buffer, function) ; - sprintf(buffer + strlen(function), " line: %d DeltaMem: %d (bytes) Time: %d:%02d:%02d", line, delta_mem, hours,mins,secs) ; - - if(mCounter < mCapacity) - { - mCounter++ ; - } - if(mCurIndex >= mCapacity) - { - mCurIndex = 0 ; - } -} - - -//static -void LLMemTracker::preDraw(BOOL pause) -{ - mMutexp->lock() ; - - mPaused = pause ; - mDrawnIndex = mCurIndex - 1; - mNumOfDrawn = 0 ; -} - -//static -void LLMemTracker::postDraw() -{ - mMutexp->unlock() ; -} - -//static -const char* LLMemTracker::getNextLine() -{ - if(mNumOfDrawn >= mCounter) - { - return NULL ; - } - mNumOfDrawn++; - - if(mDrawnIndex < 0) - { - mDrawnIndex = mCapacity - 1 ; - } - - return mStringBuffer[mDrawnIndex--] ; -} - -#endif //MEM_TRACK_MEM -//-------------------------------------------------------------------------------------------------- - - -//-------------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------------- //minimum slot size and minimal slot size interval const U32 ATOMIC_MEM_SLOT = 16 ; //bytes @@ -961,7 +828,7 @@ void LLPrivateMemoryPool::LLMemoryChunk::dump() total_size += blk_list[i]->getBufferSize() ; if((U32)blk_list[i]->getBuffer() < (U32)blk_list[i-1]->getBuffer() + blk_list[i-1]->getBufferSize()) { - llerrs << "buffer corrupted." << llendl ; + LL_ERRS() << "buffer corrupted." << LL_ENDL ; } } @@ -982,32 +849,32 @@ void LLPrivateMemoryPool::LLMemoryChunk::dump() } else { - llerrs << "gap happens" << llendl ; + LL_ERRS() << "gap happens" << LL_ENDL ; } } #endif #if 0 - llinfos << "---------------------------" << llendl ; - llinfos << "Chunk buffer: " << (U32)getBuffer() << " size: " << getBufferSize() << llendl ; + LL_INFOS() << "---------------------------" << LL_ENDL ; + LL_INFOS() << "Chunk buffer: " << (U32)getBuffer() << " size: " << getBufferSize() << LL_ENDL ; - llinfos << "available blocks ... " << llendl ; + LL_INFOS() << "available blocks ... " << LL_ENDL ; for(S32 i = 0 ; i < mBlockLevels ; i++) { LLMemoryBlock* blk = mAvailBlockList[i] ; while(blk) { - llinfos << "blk buffer " << (U32)blk->getBuffer() << " size: " << blk->getBufferSize() << llendl ; + LL_INFOS() << "blk buffer " << (U32)blk->getBuffer() << " size: " << blk->getBufferSize() << LL_ENDL ; blk = blk->mNext ; } } - llinfos << "free blocks ... " << llendl ; + LL_INFOS() << "free blocks ... " << LL_ENDL ; for(S32 i = 0 ; i < mPartitionLevels ; i++) { LLMemoryBlock* blk = mFreeSpaceList[i] ; while(blk) { - llinfos << "blk buffer " << (U32)blk->getBuffer() << " size: " << blk->getBufferSize() << llendl ; + LL_INFOS() << "blk buffer " << (U32)blk->getBuffer() << " size: " << blk->getBufferSize() << LL_ENDL ; blk = blk->mNext ; } } @@ -1403,7 +1270,7 @@ char* LLPrivateMemoryPool::allocate(U32 size) if(to_log) { - llwarns << "The memory pool overflows, now using heap directly!" << llendl ; + LL_WARNS() << "The memory pool overflows, now using heap directly!" << LL_ENDL ; to_log = false ; } @@ -1496,7 +1363,7 @@ void LLPrivateMemoryPool::destroyPool() if(mNumOfChunks > 0) { - llwarns << "There is some memory not freed when destroy the memory pool!" << llendl ; + LL_WARNS() << "There is some memory not freed when destroy the memory pool!" << LL_ENDL ; } mNumOfChunks = 0 ; @@ -1514,11 +1381,11 @@ bool LLPrivateMemoryPool::checkSize(U32 asked_size) { if(mReservedPoolSize + asked_size > mMaxPoolSize) { - llinfos << "Max pool size: " << mMaxPoolSize << llendl ; - llinfos << "Total reserved size: " << mReservedPoolSize + asked_size << llendl ; - llinfos << "Total_allocated Size: " << getTotalAllocatedSize() << llendl ; + LL_INFOS() << "Max pool size: " << mMaxPoolSize << LL_ENDL ; + LL_INFOS() << "Total reserved size: " << mReservedPoolSize + asked_size << LL_ENDL ; + LL_INFOS() << "Total_allocated Size: " << getTotalAllocatedSize() << LL_ENDL ; - //llerrs << "The pool is overflowing..." << llendl ; + //LL_ERRS() << "The pool is overflowing..." << LL_ENDL ; return false ; } @@ -1731,7 +1598,7 @@ void LLPrivateMemoryPool::removeFromHashTable(LLMemoryChunk* chunk) void LLPrivateMemoryPool::rehash() { - llinfos << "new hash factor: " << mHashFactor << llendl ; + LL_INFOS() << "new hash factor: " << mHashFactor << LL_ENDL ; mChunkHashList.clear() ; mChunkHashList.resize(mHashFactor) ; @@ -1811,7 +1678,7 @@ void LLPrivateMemoryPool::LLChunkHashElement::remove(LLPrivateMemoryPool::LLMemo } else { - llerrs << "This slot does not contain this chunk!" << llendl ; + LL_ERRS() << "This slot does not contain this chunk!" << LL_ENDL ; } } @@ -1843,12 +1710,12 @@ LLPrivateMemoryPoolManager::~LLPrivateMemoryPoolManager() #if __DEBUG_PRIVATE_MEM__ if(!sMemAllocationTracker.empty()) { - llwarns << "there is potential memory leaking here. The list of not freed memory blocks are from: " <<llendl ; + LL_WARNS() << "there is potential memory leaking here. The list of not freed memory blocks are from: " <<LL_ENDL ; S32 k = 0 ; for(mem_allocation_info_t::iterator iter = sMemAllocationTracker.begin() ; iter != sMemAllocationTracker.end() ; ++iter) { - llinfos << k++ << ", " << (U32)iter->first << " : " << iter->second << llendl ; + LL_INFOS() << k++ << ", " << (U32)iter->first << " : " << iter->second << LL_ENDL ; } sMemAllocationTracker.clear() ; } @@ -2044,7 +1911,7 @@ void LLPrivateMemoryPoolManager::freeMem(LLPrivateMemoryPool* poolp, void* addr } else { - llerrs << "private pool is used before initialized.!" << llendl ; + LL_ERRS() << "private pool is used before initialized.!" << LL_ENDL ; } } } @@ -2118,7 +1985,7 @@ void LLPrivateMemoryPoolTester::test(U32 min_size, U32 max_size, U32 stride, U32 //allocate space for p ; if(!(p = ::new char**[times]) || !(*p = ::new char*[times * levels])) { - llerrs << "memory initialization for p failed" << llendl ; + LL_ERRS() << "memory initialization for p failed" << LL_ENDL ; } //init @@ -2190,8 +2057,8 @@ void LLPrivateMemoryPoolTester::testAndTime(U32 size, U32 times) { LLTimer timer ; - llinfos << " -**********************- " << llendl ; - llinfos << "test size: " << size << " test times: " << times << llendl ; + LL_INFOS() << " -**********************- " << LL_ENDL ; + LL_INFOS() << "test size: " << size << " test times: " << times << LL_ENDL ; timer.reset() ; char** p = new char*[times] ; @@ -2203,7 +2070,7 @@ void LLPrivateMemoryPoolTester::testAndTime(U32 size, U32 times) p[i] = ALLOCATE_MEM(sPool, size) ; if(!p[i]) { - llerrs << "allocation failed" << llendl ; + LL_ERRS() << "allocation failed" << LL_ENDL ; } } //de-allocation @@ -2212,7 +2079,7 @@ void LLPrivateMemoryPoolTester::testAndTime(U32 size, U32 times) FREE_MEM(sPool, p[i]) ; p[i] = NULL ; } - llinfos << "time spent using customized memory pool: " << timer.getElapsedTimeF32() << llendl ; + LL_INFOS() << "time spent using customized memory pool: " << timer.getElapsedTimeF32() << LL_ENDL ; timer.reset() ; @@ -2223,7 +2090,7 @@ void LLPrivateMemoryPoolTester::testAndTime(U32 size, U32 times) p[i] = ::new char[size] ; if(!p[i]) { - llerrs << "allocation failed" << llendl ; + LL_ERRS() << "allocation failed" << LL_ENDL ; } } //de-allocation @@ -2232,7 +2099,7 @@ void LLPrivateMemoryPoolTester::testAndTime(U32 size, U32 times) ::delete[] p[i] ; p[i] = NULL ; } - llinfos << "time spent using standard allocator/de-allocator: " << timer.getElapsedTimeF32() << llendl ; + LL_INFOS() << "time spent using standard allocator/de-allocator: " << timer.getElapsedTimeF32() << LL_ENDL ; delete[] p; } diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h index 61e30f11cc..db52f2b1f4 100755 --- a/indra/llcommon/llmemory.h +++ b/indra/llcommon/llmemory.h @@ -27,15 +27,35 @@ #define LLMEMORY_H #include "linden_common.h" +#include "llunits.h" +#if !LL_WINDOWS +#include <stdint.h> +#endif class LLMutex ; #if LL_WINDOWS && LL_DEBUG #define LL_CHECK_MEMORY llassert(_CrtCheckMemory()); #else -#define LL_CHECK_MEMORY +#define LL_CHECK_MEMORY +#endif + + +#if LL_WINDOWS +#define LL_ALIGN_OF __alignof +#else +#define LL_ALIGN_OF __align_of__ +#endif + +#if LL_WINDOWS +#define LL_DEFAULT_HEAP_ALIGN 8 +#elif LL_DARWIN +#define LL_DEFAULT_HEAP_ALIGN 16 +#elif LL_LINUX +#define LL_DEFAULT_HEAP_ALIGN 8 #endif + LL_COMMON_API void ll_assert_aligned_func(uintptr_t ptr,U32 alignment); #ifdef SHOW_ASSERT @@ -74,7 +94,8 @@ template <typename T> T* LL_NEXT_ALIGNED_ADDRESS_64(T* address) #define LL_ALIGN_16(var) LL_ALIGN_PREFIX(16) var LL_ALIGN_POSTFIX(16) -inline void* ll_aligned_malloc( size_t size, int align ) + +inline void* ll_aligned_malloc_fallback( size_t size, int align ) { #if defined(LL_WINDOWS) return _aligned_malloc(size, align); @@ -88,7 +109,7 @@ inline void* ll_aligned_malloc( size_t size, int align ) #endif } -inline void ll_aligned_free( void* ptr ) +inline void ll_aligned_free_fallback( void* ptr ) { #if defined(LL_WINDOWS) _aligned_free(ptr); @@ -161,7 +182,7 @@ inline void* ll_aligned_malloc_32(size_t size) // returned hunk MUST be freed wi #if defined(LL_WINDOWS) return _aligned_malloc(size, 32); #elif defined(LL_DARWIN) - return ll_aligned_malloc( size, 32 ); + return ll_aligned_malloc_fallback( size, 32 ); #else void *rtn; if (LL_LIKELY(0 == posix_memalign(&rtn, 32, size))) @@ -176,12 +197,54 @@ inline void ll_aligned_free_32(void *p) #if defined(LL_WINDOWS) _aligned_free(p); #elif defined(LL_DARWIN) - ll_aligned_free( p ); + ll_aligned_free_fallback( p ); #else free(p); // posix_memalign() is compatible with heap deallocator #endif } +// general purpose dispatch functions that are forced inline so they can compile down to a single call +template<size_t ALIGNMENT> +LL_FORCE_INLINE void* ll_aligned_malloc(size_t size) +{ + if (LL_DEFAULT_HEAP_ALIGN % ALIGNMENT == 0) + { + return malloc(size); + } + else if (ALIGNMENT == 16) + { + return ll_aligned_malloc_16(size); + } + else if (ALIGNMENT == 32) + { + return ll_aligned_malloc_32(size); + } + else + { + return ll_aligned_malloc_fallback(size, ALIGNMENT); + } +} + +template<size_t ALIGNMENT> +LL_FORCE_INLINE void ll_aligned_free(void* ptr) +{ + if (ALIGNMENT == LL_DEFAULT_HEAP_ALIGN) + { + free(ptr); + } + else if (ALIGNMENT == 16) + { + ll_aligned_free_16(ptr); + } + else if (ALIGNMENT == 32) + { + return ll_aligned_free_32(ptr); + } + else + { + return ll_aligned_free_fallback(ptr); + } +} // Copy words 16-byte blocks from src to dst. Source and destination MUST NOT OVERLAP. // Source and dest must be 16-byte aligned and size must be multiple of 16. @@ -269,70 +332,25 @@ public: static U64 getCurrentRSS(); static U32 getWorkingSetSize(); static void* tryToAlloc(void* address, U32 size); - static void initMaxHeapSizeGB(F32 max_heap_size_gb, BOOL prevent_heap_failure); + static void initMaxHeapSizeGB(F32Gigabytes max_heap_size, BOOL prevent_heap_failure); static void updateMemoryInfo() ; static void logMemoryInfo(BOOL update = FALSE); static bool isMemoryPoolLow(); - static U32 getAvailableMemKB() ; - static U32 getMaxMemKB() ; - static U32 getAllocatedMemKB() ; + static U32Kilobytes getAvailableMemKB() ; + static U32Kilobytes getMaxMemKB() ; + static U32Kilobytes getAllocatedMemKB() ; private: static char* reserveMem; - static U32 sAvailPhysicalMemInKB ; - static U32 sMaxPhysicalMemInKB ; - static U32 sAllocatedMemInKB; - static U32 sAllocatedPageSizeInKB ; + static U32Kilobytes sAvailPhysicalMemInKB ; + static U32Kilobytes sMaxPhysicalMemInKB ; + static U32Kilobytes sAllocatedMemInKB; + static U32Kilobytes sAllocatedPageSizeInKB ; - static U32 sMaxHeapSizeInKB; + static U32Kilobytes sMaxHeapSizeInKB; static BOOL sEnableMemoryFailurePrevention; }; -//---------------------------------------------------------------------------- -#if MEM_TRACK_MEM -class LLMutex ; -class LL_COMMON_API LLMemTracker -{ -private: - LLMemTracker() ; - ~LLMemTracker() ; - -public: - static void release() ; - static LLMemTracker* getInstance() ; - - void track(const char* function, const int line) ; - void preDraw(BOOL pause) ; - void postDraw() ; - const char* getNextLine() ; - -private: - static LLMemTracker* sInstance ; - - char** mStringBuffer ; - S32 mCapacity ; - U32 mLastAllocatedMem ; - S32 mCurIndex ; - S32 mCounter; - S32 mDrawnIndex; - S32 mNumOfDrawn; - BOOL mPaused; - LLMutex* mMutexp ; -}; - -#define MEM_TRACK_RELEASE LLMemTracker::release() ; -#define MEM_TRACK LLMemTracker::getInstance()->track(__FUNCTION__, __LINE__) ; - -#else // MEM_TRACK_MEM - -#define MEM_TRACK_RELEASE -#define MEM_TRACK - -#endif // MEM_TRACK_MEM - -//---------------------------------------------------------------------------- - - // //class LLPrivateMemoryPool defines a private memory pool for an application to use, so the application does not //need to access the heap directly fro each memory allocation. Throught this, the allocation speed is faster, diff --git a/indra/llcommon/llmemorystream.cpp b/indra/llcommon/llmemorystream.cpp index 723d94f025..707ac8fd0f 100755 --- a/indra/llcommon/llmemorystream.cpp +++ b/indra/llcommon/llmemorystream.cpp @@ -45,7 +45,7 @@ void LLMemoryStreamBuf::reset(const U8* start, S32 length) int LLMemoryStreamBuf::underflow() { - //lldebugs << "LLMemoryStreamBuf::underflow()" << llendl; + //LL_DEBUGS() << "LLMemoryStreamBuf::underflow()" << LL_ENDL; if(gptr() < egptr()) { return *gptr(); diff --git a/indra/llcommon/llmetricperformancetester.cpp b/indra/llcommon/llmetricperformancetester.cpp index 731e58bd20..1fc821d9a9 100755 --- a/indra/llcommon/llmetricperformancetester.cpp +++ b/indra/llcommon/llmetricperformancetester.cpp @@ -29,9 +29,9 @@ #include "indra_constants.h" #include "llerror.h" #include "llsdserialize.h" -#include "llstat.h" #include "lltreeiterators.h" #include "llmetricperformancetester.h" +#include "llfasttimer.h" //---------------------------------------------------------------------------------------------- // LLMetricPerformanceTesterBasic : static methods and testers management @@ -56,7 +56,7 @@ BOOL LLMetricPerformanceTesterBasic::addTester(LLMetricPerformanceTesterBasic* t std::string name = tester->getTesterName() ; if (getTester(name)) { - llerrs << "Tester name is already used by some other tester : " << name << llendl ; + LL_ERRS() << "Tester name is already used by some other tester : " << name << LL_ENDL ; return FALSE; } @@ -91,7 +91,7 @@ LLMetricPerformanceTesterBasic* LLMetricPerformanceTesterBasic::getTester(std::s // Return TRUE if this metric is requested or if the general default "catch all" metric is requested BOOL LLMetricPerformanceTesterBasic::isMetricLogRequested(std::string name) { - return (LLFastTimer::sMetricLog && ((LLFastTimer::sLogName == name) || (LLFastTimer::sLogName == DEFAULT_METRIC_NAME))); + return (LLTrace::BlockTimer::sMetricLog && ((LLTrace::BlockTimer::sLogName == name) || (LLTrace::BlockTimer::sLogName == DEFAULT_METRIC_NAME))); } /*static*/ @@ -136,7 +136,7 @@ void LLMetricPerformanceTesterBasic::doAnalysisMetrics(std::string baseline, std std::ifstream target_is(target.c_str()); if (!base_is.is_open() || !target_is.is_open()) { - llwarns << "'-analyzeperformance' error : baseline or current target file inexistent" << llendl; + LL_WARNS() << "'-analyzeperformance' error : baseline or current target file inexistent" << LL_ENDL; base_is.close(); target_is.close(); return; @@ -176,7 +176,7 @@ LLMetricPerformanceTesterBasic::LLMetricPerformanceTesterBasic(std::string name) { if (mName == std::string()) { - llerrs << "LLMetricPerformanceTesterBasic construction invalid : Empty name passed to constructor" << llendl ; + LL_ERRS() << "LLMetricPerformanceTesterBasic construction invalid : Empty name passed to constructor" << LL_ENDL ; } mValidInstance = LLMetricPerformanceTesterBasic::addTester(this) ; @@ -194,8 +194,7 @@ void LLMetricPerformanceTesterBasic::preOutputTestResults(LLSD* sd) void LLMetricPerformanceTesterBasic::postOutputTestResults(LLSD* sd) { - LLMutexLock lock(LLFastTimer::sLogLock); - LLFastTimer::sLogQueue.push((*sd)); + LLTrace::BlockTimer::pushLog(*sd); } void LLMetricPerformanceTesterBasic::outputTestResults() @@ -242,7 +241,7 @@ void LLMetricPerformanceTesterBasic::analyzePerformance(std::ofstream* os, LLSD* (F32)((*base)[label][ mMetricStrings[index] ].asReal()), (F32)((*current)[label][ mMetricStrings[index] ].asReal())) ; break; default: - llerrs << "unsupported metric " << mMetricStrings[index] << " LLSD type: " << (S32)(*current)[label][ mMetricStrings[index] ].type() << llendl ; + LL_ERRS() << "unsupported metric " << mMetricStrings[index] << " LLSD type: " << (S32)(*current)[label][ mMetricStrings[index] ].type() << LL_ENDL ; } } } @@ -306,7 +305,7 @@ void LLMetricPerformanceTesterWithSession::analyzePerformance(std::ofstream* os, if (!mBaseSessionp || !mCurrentSessionp) { - llerrs << "Error loading test sessions." << llendl ; + LL_ERRS() << "Error loading test sessions." << LL_ENDL ; } // Compare diff --git a/indra/llcommon/llmetrics.cpp b/indra/llcommon/llmetrics.cpp index 3078139f43..d40afe5160 100755 --- a/indra/llcommon/llmetrics.cpp +++ b/indra/llcommon/llmetrics.cpp @@ -65,7 +65,7 @@ void LLMetricsImpl::recordEventDetails(const std::string& location, metrics["location"] = location; metrics["stats"] = stats; - llinfos << "LLMETRICS: " << (LLSDNotationStreamer(metrics)) << llendl; + LL_INFOS() << "LLMETRICS: " << (LLSDNotationStreamer(metrics)) << LL_ENDL; } // Store this: @@ -128,7 +128,7 @@ void LLMetricsImpl::printTotals(LLSD metadata) out_sd["stats"] = stats; - llinfos << "LLMETRICS: AGGREGATE: " << LLSDOStreamer<LLSDNotationFormatter>(out_sd) << llendl; + LL_INFOS() << "LLMETRICS: AGGREGATE: " << LLSDOStreamer<LLSDNotationFormatter>(out_sd) << LL_ENDL; } LLMetrics::LLMetrics() diff --git a/indra/llcommon/llmetrics.h b/indra/llcommon/llmetrics.h index 4f0ae56338..85a6986049 100755 --- a/indra/llcommon/llmetrics.h +++ b/indra/llcommon/llmetrics.h @@ -38,7 +38,7 @@ public: LLMetrics(); virtual ~LLMetrics(); - // Adds this event to aggregate totals and records details to syslog (llinfos) + // Adds this event to aggregate totals and records details to syslog (LL_INFOS()) virtual void recordEventDetails(const std::string& location, const std::string& mesg, bool success, diff --git a/indra/llcommon/llmortician.h b/indra/llcommon/llmortician.h index 319955ef93..9517e2db5e 100755 --- a/indra/llcommon/llmortician.h +++ b/indra/llcommon/llmortician.h @@ -28,6 +28,7 @@ #define LLMORTICIAN_H #include "stdtypes.h" +#include <list> class LL_COMMON_API LLMortician { diff --git a/indra/llcommon/llmutex.cpp b/indra/llcommon/llmutex.cpp new file mode 100644 index 0000000000..9c13ef9e30 --- /dev/null +++ b/indra/llcommon/llmutex.cpp @@ -0,0 +1,205 @@ +/** + * @file llmutex.cpp + * + * $LicenseInfo:firstyear=2004&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" +#include "llapr.h" + +#include "apr_portable.h" + +#include "llmutex.h" +#include "llthread.h" + +//============================================================================ + +LLMutex::LLMutex(apr_pool_t *poolp) : + mAPRMutexp(NULL), mCount(0), mLockingThread(NO_THREAD) +{ + //if (poolp) + //{ + // mIsLocalPool = FALSE; + // mAPRPoolp = poolp; + //} + //else + { + mIsLocalPool = TRUE; + apr_pool_create(&mAPRPoolp, NULL); // Create a subpool for this thread + } + apr_thread_mutex_create(&mAPRMutexp, APR_THREAD_MUTEX_UNNESTED, mAPRPoolp); +} + + +LLMutex::~LLMutex() +{ +#if MUTEX_DEBUG + //bad assertion, the subclass LLSignal might be "locked", and that's OK + //llassert_always(!isLocked()); // better not be locked! +#endif + if (ll_apr_is_initialized()) + { + apr_thread_mutex_destroy(mAPRMutexp); + if (mIsLocalPool) + { + apr_pool_destroy(mAPRPoolp); + } + } + mAPRMutexp = NULL; +} + + +void LLMutex::lock() +{ + if(isSelfLocked()) + { //redundant lock + mCount++; + return; + } + + apr_thread_mutex_lock(mAPRMutexp); + +#if MUTEX_DEBUG + // Have to have the lock before we can access the debug info + U32 id = LLThread::currentID(); + if (mIsLocked[id] != FALSE) + LL_ERRS() << "Already locked in Thread: " << id << LL_ENDL; + mIsLocked[id] = TRUE; +#endif + + mLockingThread = LLThread::currentID(); +} + +void LLMutex::unlock() +{ + if (mCount > 0) + { //not the root unlock + mCount--; + return; + } + +#if MUTEX_DEBUG + // Access the debug info while we have the lock + U32 id = LLThread::currentID(); + if (mIsLocked[id] != TRUE) + LL_ERRS() << "Not locked in Thread: " << id << LL_ENDL; + mIsLocked[id] = FALSE; +#endif + + mLockingThread = NO_THREAD; + apr_thread_mutex_unlock(mAPRMutexp); +} + +bool LLMutex::isLocked() +{ + apr_status_t status = apr_thread_mutex_trylock(mAPRMutexp); + if (APR_STATUS_IS_EBUSY(status)) + { + return true; + } + else + { + apr_thread_mutex_unlock(mAPRMutexp); + return false; + } +} + +bool LLMutex::isSelfLocked() +{ + return mLockingThread == LLThread::currentID(); +} + +U32 LLMutex::lockingThread() const +{ + return mLockingThread; +} + +bool LLMutex::trylock() +{ + if(isSelfLocked()) + { //redundant lock + mCount++; + return true; + } + + apr_status_t status(apr_thread_mutex_trylock(mAPRMutexp)); + if (APR_STATUS_IS_EBUSY(status)) + { + return false; + } + +#if MUTEX_DEBUG + // Have to have the lock before we can access the debug info + U32 id = LLThread::currentID(); + if (mIsLocked[id] != FALSE) + LL_ERRS() << "Already locked in Thread: " << id << LL_ENDL; + mIsLocked[id] = TRUE; +#endif + + mLockingThread = LLThread::currentID(); + return true; +} + +//============================================================================ + +LLCondition::LLCondition(apr_pool_t *poolp) : + LLMutex(poolp) +{ + // base class (LLMutex) has already ensured that mAPRPoolp is set up. + + apr_thread_cond_create(&mAPRCondp, mAPRPoolp); +} + + +LLCondition::~LLCondition() +{ + apr_thread_cond_destroy(mAPRCondp); + mAPRCondp = NULL; +} + + +void LLCondition::wait() +{ + if (!isLocked()) + { //mAPRMutexp MUST be locked before calling apr_thread_cond_wait + apr_thread_mutex_lock(mAPRMutexp); +#if MUTEX_DEBUG + // avoid asserts on destruction in non-release builds + U32 id = LLThread::currentID(); + mIsLocked[id] = TRUE; +#endif + } + apr_thread_cond_wait(mAPRCondp, mAPRMutexp); +} + +void LLCondition::signal() +{ + apr_thread_cond_signal(mAPRCondp); +} + +void LLCondition::broadcast() +{ + apr_thread_cond_broadcast(mAPRCondp); +} + + +//============================================================================ diff --git a/indra/llcommon/llmutex.h b/indra/llcommon/llmutex.h new file mode 100644 index 0000000000..3659a319a2 --- /dev/null +++ b/indra/llcommon/llmutex.h @@ -0,0 +1,141 @@ +/** + * @file llmutex.h + * @brief Base classes for mutex and condition handling. + * + * $LicenseInfo:firstyear=2004&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2012, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLMUTEX_H +#define LL_LLMUTEX_H + +#include "stdtypes.h" + +//============================================================================ + +#define MUTEX_DEBUG (LL_DEBUG || LL_RELEASE_WITH_DEBUG_INFO) + +struct apr_thread_mutex_t; +struct apr_pool_t; +struct apr_thread_cond_t; + +class LL_COMMON_API LLMutex +{ +public: + typedef enum + { + NO_THREAD = 0xFFFFFFFF + } e_locking_thread; + + LLMutex(apr_pool_t *apr_poolp = NULL); // NULL pool constructs a new pool for the mutex + virtual ~LLMutex(); + + void lock(); // blocks + bool trylock(); // non-blocking, returns true if lock held. + void unlock(); // undefined behavior when called on mutex not being held + bool isLocked(); // non-blocking, but does do a lock/unlock so not free + bool isSelfLocked(); //return true if locked in a same thread + U32 lockingThread() const; //get ID of locking thread + +protected: + apr_thread_mutex_t *mAPRMutexp; + mutable U32 mCount; + mutable U32 mLockingThread; + + apr_pool_t *mAPRPoolp; + BOOL mIsLocalPool; + +#if MUTEX_DEBUG + std::map<U32, BOOL> mIsLocked; +#endif +}; + +// Actually a condition/mutex pair (since each condition needs to be associated with a mutex). +class LL_COMMON_API LLCondition : public LLMutex +{ +public: + LLCondition(apr_pool_t* apr_poolp); // Defaults to global pool, could use the thread pool as well. + ~LLCondition(); + + void wait(); // blocks + void signal(); + void broadcast(); + +protected: + apr_thread_cond_t* mAPRCondp; +}; + +class LLMutexLock +{ +public: + LLMutexLock(LLMutex* mutex) + { + mMutex = mutex; + + if(mMutex) + mMutex->lock(); + } + ~LLMutexLock() + { + if(mMutex) + mMutex->unlock(); + } +private: + LLMutex* mMutex; +}; + +//============================================================================ + +// Scoped locking class similar in function to LLMutexLock but uses +// the trylock() method to conditionally acquire lock without +// blocking. Caller resolves the resulting condition by calling +// the isLocked() method and either punts or continues as indicated. +// +// Mostly of interest to callers needing to avoid stalls who can +// guarantee another attempt at a later time. + +class LLMutexTrylock +{ +public: + LLMutexTrylock(LLMutex* mutex) + : mMutex(mutex), + mLocked(false) + { + if (mMutex) + mLocked = mMutex->trylock(); + } + + ~LLMutexTrylock() + { + if (mMutex && mLocked) + mMutex->unlock(); + } + + bool isLocked() const + { + return mLocked; + } + +private: + LLMutex* mMutex; + bool mLocked; +}; +#endif // LL_LLTHREAD_H diff --git a/indra/llcommon/llnametable.h b/indra/llcommon/llnametable.h index d3283543f3..d3283543f3 100755..100644 --- a/indra/llcommon/llnametable.h +++ b/indra/llcommon/llnametable.h diff --git a/indra/llcommon/lloptioninterface.cpp b/indra/llcommon/lloptioninterface.cpp deleted file mode 100755 index 23fae76dc0..0000000000 --- a/indra/llcommon/lloptioninterface.cpp +++ /dev/null @@ -1,33 +0,0 @@ -/** - * @file lloptioninterface.cpp - * @brief - * - * $LicenseInfo:firstyear=2009&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "lloptioninterface.h" - - -LLOptionInterface::~LLOptionInterface() -{ - -} diff --git a/indra/llcommon/llpointer.h b/indra/llcommon/llpointer.h index 88c09c8dca..c9ebc70d19 100755 --- a/indra/llcommon/llpointer.h +++ b/indra/llcommon/llpointer.h @@ -27,6 +27,7 @@ #define LLPOINTER_H #include "llerror.h" // *TODO: consider eliminating this +#include "llmutex.h" //---------------------------------------------------------------------------- // RefCount objects should generally only be accessed by way of LLPointer<>'s @@ -97,24 +98,13 @@ public: LLPointer<Type>& operator =(Type* ptr) { - if( mPointer != ptr ) - { - unref(); - mPointer = ptr; - ref(); - } - + assign(ptr); return *this; } LLPointer<Type>& operator =(const LLPointer<Type>& ptr) { - if( mPointer != ptr.mPointer ) - { - unref(); - mPointer = ptr.mPointer; - ref(); - } + assign(ptr); return *this; } @@ -122,12 +112,7 @@ public: template<typename Subclass> LLPointer<Type>& operator =(const LLPointer<Subclass>& ptr) { - if( mPointer != ptr.get() ) - { - unref(); - mPointer = ptr.get(); - ref(); - } + assign(ptr.get()); return *this; } @@ -144,6 +129,16 @@ protected: void ref(); void unref(); #else + + void assign(const LLPointer<Type>& ptr) + { + if( mPointer != ptr.mPointer ) + { + unref(); + mPointer = ptr.mPointer; + ref(); + } + } void ref() { if (mPointer) @@ -156,12 +151,12 @@ protected: { if (mPointer) { - Type *tempp = mPointer; + Type *temp = mPointer; mPointer = NULL; - tempp->unref(); + temp->unref(); if (mPointer != NULL) { - llwarns << "Unreference did assignment to non-NULL because of destructor" << llendl; + LL_WARNS() << "Unreference did assignment to non-NULL because of destructor" << LL_ENDL; unref(); } } @@ -171,4 +166,52 @@ protected: Type* mPointer; }; +template<typename Type> +class LLCopyOnWritePointer : public LLPointer<Type> +{ +public: + typedef LLCopyOnWritePointer<Type> self_t; + typedef LLPointer<Type> pointer_t; + + LLCopyOnWritePointer() + : mStayUnique(false) + {} + + LLCopyOnWritePointer(Type* ptr) + : LLPointer<Type>(ptr), + mStayUnique(false) + {} + + LLCopyOnWritePointer(LLPointer<Type>& ptr) + : LLPointer<Type>(ptr), + mStayUnique(false) + { + if (ptr.mForceUnique) + { + makeUnique(); + } + } + + Type* write() + { + makeUnique(); + return pointer_t::mPointer; + } + + void makeUnique() + { + if (pointer_t::notNull() && pointer_t::mPointer->getNumRefs() > 1) + { + *(pointer_t* )(this) = new Type(*pointer_t::mPointer); + } + } + + const Type* operator->() const { return pointer_t::mPointer; } + const Type& operator*() const { return *pointer_t::mPointer; } + + void setStayUnique(bool stay) { makeUnique(); mStayUnique = stay; } +private: + bool mStayUnique; +}; + #endif diff --git a/indra/llcommon/lloptioninterface.h b/indra/llcommon/llpredicate.cpp index 93b465db32..1278948e24 100755..100644 --- a/indra/llcommon/lloptioninterface.h +++ b/indra/llcommon/llpredicate.cpp @@ -1,8 +1,8 @@ /** - * @file lloptioninterface.h - * @brief + * @file llpredicate.cpp + * @brief abstraction for filtering objects by predicates, with arbitrary boolean expressions * - * $LicenseInfo:firstyear=2009&license=viewerlgpl$ + * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. * @@ -23,18 +23,19 @@ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ - -#ifndef LL_LLOPTIONINTERFACE_H -#define LL_LLOPTIONINTERFACE_H - #include "linden_common.h" -class LLSD; -class LLOptionInterface +#include "llpredicate.h" + +namespace LLPredicate { -public: - virtual ~LLOptionInterface() = 0; - virtual LLSD getOption(const std::string& name) const = 0; -}; + const U32 cPredicateFlagsFromEnum[5] = + { + 0xAAAAaaaa, // 10101010101010101010101010101010 + 0xCCCCcccc, // 11001100110011001100110011001100 + 0xF0F0F0F0, // 11110000111100001111000011110000 + 0xFF00FF00, // 11111111000000001111111100000000 + 0xFFFF0000 // 11111111111111110000000000000000 + }; +} -#endif diff --git a/indra/llcommon/llpredicate.h b/indra/llcommon/llpredicate.h new file mode 100644 index 0000000000..a0e970a799 --- /dev/null +++ b/indra/llcommon/llpredicate.h @@ -0,0 +1,210 @@ +/** + * @file llpredicate.h + * @brief abstraction for filtering objects by predicates, with arbitrary boolean expressions + * + * $LicenseInfo:firstyear=2008&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLPREDICATE_H +#define LL_LLPREDICATE_H + +#include "llerror.h" + +namespace LLPredicate +{ + template<typename ENUM> class Rule; + + extern const U32 cPredicateFlagsFromEnum[5]; + + template<typename ENUM> + class Value + { + public: + typedef U32 predicate_flag_t; + static const S32 cMaxEnum = 5; + + Value(ENUM e, bool predicate_value = true) + : mPredicateFlags(predicate_value ? cPredicateFlagsFromEnum[e] : ~cPredicateFlagsFromEnum[e]) + { + llassert(0 <= e && e < cMaxEnum); + } + + Value() + : mPredicateFlags(0xFFFFffff) + {} + + Value operator!() const + { + Value new_value; + new_value.mPredicateFlags = ~mPredicateFlags; + return new_value; + } + + Value operator &&(const Value other) const + { + Value new_value; + new_value.mPredicateFlags = mPredicateFlags & other.mPredicateFlags; + return new_value; + } + + Value operator ||(const Value other) const + { + Value new_value; + new_value.mPredicateFlags = mPredicateFlags | other.mPredicateFlags; + return new_value; + } + + void set(ENUM e, bool value = true) + { + llassert(0 <= e && e < cMaxEnum); + predicate_flag_t flags_to_modify; + predicate_flag_t mask = cPredicateFlagsFromEnum[e]; + if (value) + { // add predicate "e" to flags that don't contain it already + flags_to_modify = (mPredicateFlags & ~mask); + // clear flags not containing e + mPredicateFlags &= mask; + // add back flags shifted to contain e + mPredicateFlags |= flags_to_modify << (0x1 << e); + } + else + { // remove predicate "e" from flags that contain it + flags_to_modify = (mPredicateFlags & mask); + // clear flags containing e + mPredicateFlags &= ~mask; + // add back flags shifted to not contain e + mPredicateFlags |= flags_to_modify >> (0x1 << e); + } + } + + void forget(ENUM e) + { + set(e, true); + U32 flags_with_predicate = mPredicateFlags; + set(e, false); + // ambiguous value is result of adding and removing predicate at the same time! + mPredicateFlags |= flags_with_predicate; + } + + bool allSet() const + { + return mPredicateFlags == ~0; + } + + bool noneSet() const + { + return mPredicateFlags == 0; + } + + bool someSet() const + { + return mPredicateFlags != 0; + } + + private: + predicate_flag_t mPredicateFlags; + }; + + template<typename ENUM> + class Rule + { + public: + Rule(ENUM value) + : mRule(value) + {} + + Rule(const Value<ENUM> other) + : mRule(other) + {} + + Rule() + {} + + void require(ENUM e) + { + mRule.set(e, require); + } + + void allow(ENUM e) + { + mRule.forget(e); + } + + bool check(const Value<ENUM> value) const + { + return (mRule && value).someSet(); + } + + bool requires(const Value<ENUM> value) const + { + return (mRule && value).someSet() && (!mRule && value).noneSet(); + } + + bool isAmbivalent(const Value<ENUM> value) const + { + return (mRule && value).someSet() && (!mRule && value).someSet(); + } + + bool acceptsAll() const + { + return mRule.allSet(); + } + + bool acceptsNone() const + { + return mRule.noneSet(); + } + + Rule operator!() const + { + Rule new_rule; + new_rule.mRule = !mRule; + return new_rule; + } + + Rule operator &&(const Rule other) const + { + Rule new_rule; + new_rule.mRule = mRule && other.mRule; + return new_rule; + } + + Rule operator ||(const Rule other) const + { + Rule new_rule; + new_rule.mRule = mRule || other.mRule; + return new_rule; + } + + private: + Value<ENUM> mRule; + }; +} + +template<typename ENUM> +LLPredicate::Value<ENUM> ll_make_predicate(ENUM e, bool predicate_value = true) +{ + return LLPredicate::Value<ENUM>(e, predicate_value); +} + + +#endif // LL_LLPREDICATE_H diff --git a/indra/llcommon/llpreprocessor.h b/indra/llcommon/llpreprocessor.h index 7fdb537ab5..309165da7f 100755 --- a/indra/llcommon/llpreprocessor.h +++ b/indra/llcommon/llpreprocessor.h @@ -181,4 +181,25 @@ # define LL_COMMON_API #endif // LL_COMMON_LINK_SHARED +#if LL_WINDOWS +#define LL_TYPEOF(exp) decltype(exp) +#elif LL_LINUX +#define LL_TYPEOF(exp) typeof(exp) +#elif LL_DARWIN +#define LL_TYPEOF(exp) typeof(exp) +#endif + +#define LL_TO_STRING_HELPER(x) #x +#define LL_TO_STRING(x) LL_TO_STRING_HELPER(x) +#define LL_FILE_LINENO_MSG(msg) __FILE__ "(" LL_TO_STRING(__LINE__) ") : " msg +#define LL_GLUE_IMPL(x, y) x##y +#define LL_GLUE_TOKENS(x, y) LL_GLUE_IMPL(x, y) + +#if LL_WINDOWS +#define LL_COMPILE_TIME_MESSAGE(msg) __pragma(message(LL_FILE_LINENO_MSG(msg))) +#else +// no way to get gcc 4.2 to print a user-defined diagnostic message only when a macro is used +#define LL_COMPILE_TIME_MESSAGE(msg) +#endif + #endif // not LL_LINDEN_PREPROCESSOR_H diff --git a/indra/llcommon/llpriqueuemap.h b/indra/llcommon/llpriqueuemap.h index da997c7b04..d8d3edd48a 100755 --- a/indra/llcommon/llpriqueuemap.h +++ b/indra/llcommon/llpriqueuemap.h @@ -84,7 +84,7 @@ public: pqm_iter iter = mMap.find(LLPQMKey<DATA_TYPE>(priority, data)); if (iter != mMap.end()) { - llerrs << "Pushing already existing data onto queue!" << llendl; + LL_ERRS() << "Pushing already existing data onto queue!" << LL_ENDL; } #endif mMap.insert(pqm_pair(LLPQMKey<DATA_TYPE>(priority, data), data)); @@ -112,14 +112,14 @@ public: iter = mMap.find(cur_key); if (iter == mMap.end()) { - llwarns << "Data not on priority queue!" << llendl; + LL_WARNS() << "Data not on priority queue!" << LL_ENDL; // OK, try iterating through all of the data and seeing if we just screwed up the priority // somehow. for (iter = mMap.begin(); iter != mMap.end(); iter++) { if ((*(iter)).second == data) { - llerrs << "Data on priority queue but priority not matched!" << llendl; + LL_ERRS() << "Data on priority queue but priority not matched!" << LL_ENDL; } } return; diff --git a/indra/llcommon/llprocess.h b/indra/llcommon/llprocess.h index d711ce2f74..43ccadc412 100755 --- a/indra/llcommon/llprocess.h +++ b/indra/llcommon/llprocess.h @@ -29,6 +29,7 @@ #include "llinitparam.h" #include "llsdparam.h" +#include "llwin32headerslean.h" #include "apr_thread_proc.h" #include <boost/shared_ptr.hpp> #include <boost/ptr_container/ptr_vector.hpp> @@ -38,8 +39,7 @@ #include <stdexcept> #if LL_WINDOWS -#define WIN32_LEAN_AND_MEAN -#include <windows.h> // HANDLE (eye roll) +#include "llwin32headerslean.h" // for HANDLE #elif LL_LINUX #if defined(Status) #undef Status diff --git a/indra/llcommon/llprocessor.cpp b/indra/llcommon/llprocessor.cpp index fd8f603d21..69043dc173 100755 --- a/indra/llcommon/llprocessor.cpp +++ b/indra/llcommon/llprocessor.cpp @@ -32,9 +32,7 @@ //#include <memory> #if LL_WINDOWS -# define WIN32_LEAN_AND_MEAN -# include <winsock2.h> -# include <windows.h> +# include "llwin32headerslean.h" # define _interlockedbittestandset _renamed_interlockedbittestandset # define _interlockedbittestandreset _renamed_interlockedbittestandreset # include <intrin.h> @@ -702,7 +700,7 @@ private: __cpuid(0x1, eax, ebx, ecx, edx); if(feature_infos[0] != (S32)edx) { - llerrs << "machdep.cpu.feature_bits doesn't match expected cpuid result!" << llendl; + LL_ERRS() << "machdep.cpu.feature_bits doesn't match expected cpuid result!" << LL_ENDL; } #endif // LL_RELEASE_FOR_DOWNLOAD @@ -877,7 +875,7 @@ LLProcessorInfo::LLProcessorInfo() : mImpl(NULL) LLProcessorInfo::~LLProcessorInfo() {} -F64 LLProcessorInfo::getCPUFrequency() const { return mImpl->getCPUFrequency(); } +F64MegahertzImplicit LLProcessorInfo::getCPUFrequency() const { return mImpl->getCPUFrequency(); } bool LLProcessorInfo::hasSSE() const { return mImpl->hasSSE(); } bool LLProcessorInfo::hasSSE2() const { return mImpl->hasSSE2(); } bool LLProcessorInfo::hasAltivec() const { return mImpl->hasAltivec(); } diff --git a/indra/llcommon/llprocessor.h b/indra/llcommon/llprocessor.h index 6364d3c8bb..90e5bc59ee 100755 --- a/indra/llcommon/llprocessor.h +++ b/indra/llcommon/llprocessor.h @@ -27,6 +27,8 @@ #ifndef LLPROCESSOR_H #define LLPROCESSOR_H +#include "llunits.h" + class LLProcessorInfoImpl; class LL_COMMON_API LLProcessorInfo @@ -35,7 +37,7 @@ public: LLProcessorInfo(); ~LLProcessorInfo(); - F64 getCPUFrequency() const; + F64MegahertzImplicit getCPUFrequency() const; bool hasSSE() const; bool hasSSE2() const; bool hasAltivec() const; diff --git a/indra/llcommon/llptrskiplist.h b/indra/llcommon/llptrskiplist.h deleted file mode 100755 index 67c7cde352..0000000000 --- a/indra/llcommon/llptrskiplist.h +++ /dev/null @@ -1,724 +0,0 @@ -/** - * @file llptrskiplist.h - * @brief Skip list implementation. - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_LLPTRSKIPLIST_H -#define LL_LLPTRSKIPLIST_H - -#include "llerror.h" -#include "llrand.h" -//#include "vmath.h" -#include "llrand.h" - -///////////////////////////////////////////// -// -// LLPtrSkipList implementation - skip list for pointers to objects -// - -template <class DATA_TYPE, S32 BINARY_DEPTH = 8> -class LLPtrSkipList -{ -public: - friend class LLPtrSkipNode; - - // basic constructor - LLPtrSkipList(); - // basic constructor including sorter - LLPtrSkipList(BOOL (*insert_first)(DATA_TYPE *first, DATA_TYPE *second), - BOOL (*equals)(DATA_TYPE *first, DATA_TYPE *second)); - ~LLPtrSkipList(); - - inline void setInsertFirst(BOOL (*insert_first)(const DATA_TYPE *first, const DATA_TYPE *second)); - inline void setEquals(BOOL (*equals)(const DATA_TYPE *first, const DATA_TYPE *second)); - - inline BOOL addData(DATA_TYPE *data); - - inline BOOL checkData(const DATA_TYPE *data); - - inline S32 getLength(); // returns number of items in the list - NOT constant time! - - inline BOOL removeData(const DATA_TYPE *data); - - // note that b_sort is ignored - inline BOOL moveData(const DATA_TYPE *data, LLPtrSkipList *newlist, BOOL b_sort); - - inline BOOL moveCurrentData(LLPtrSkipList *newlist, BOOL b_sort); - - // resort -- use when the value we're sorting by changes - /* IW 12/6/02 - This doesn't work! - Instead, remove the data BEFORE you change it - Then re-insert it after you change it - BOOL resortData(DATA_TYPE *data) - */ - - // remove all nodes from the list but do not delete data - inline void removeAllNodes(); - - inline BOOL deleteData(const DATA_TYPE *data); - - // remove all nodes from the list and delete data - inline void deleteAllData(); - - // place mCurrentp on first node - inline void resetList(); - - // return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp - inline DATA_TYPE *getCurrentData(); - - // same as getCurrentData() but a more intuitive name for the operation - inline DATA_TYPE *getNextData(); - - // remove the Node at mCurentOperatingp - // leave mCurrentp and mCurentOperatingp on the next entry - inline void removeCurrentData(); - - // delete the Node at mCurentOperatingp - // leave mCurrentp and mCurentOperatingp on the next entry - inline void deleteCurrentData(); - - // reset the list and return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp - inline DATA_TYPE *getFirstData(); - - // TRUE if nodes are not in sorted order - inline BOOL corrupt(); - -protected: - class LLPtrSkipNode - { - public: - LLPtrSkipNode() - : mData(NULL) - { - S32 i; - for (i = 0; i < BINARY_DEPTH; i++) - { - mForward[i] = NULL; - } - } - - LLPtrSkipNode(DATA_TYPE *data) - : mData(data) - { - S32 i; - for (i = 0; i < BINARY_DEPTH; i++) - { - mForward[i] = NULL; - } - } - - ~LLPtrSkipNode() - { - if (mData) - { - llerror("Attempting to call LLPtrSkipNode destructor with a non-null mDatap!", 1); - } - } - - // delete associated data and NULLs out pointer - void deleteData() - { - delete mData; - mData = NULL; - } - - // NULLs out pointer - void removeData() - { - mData = NULL; - } - - DATA_TYPE *mData; - LLPtrSkipNode *mForward[BINARY_DEPTH]; - }; - - static BOOL defaultEquals(const DATA_TYPE *first, const DATA_TYPE *second) - { - return first == second; - } - - - LLPtrSkipNode mHead; - LLPtrSkipNode *mUpdate[BINARY_DEPTH]; - LLPtrSkipNode *mCurrentp; - LLPtrSkipNode *mCurrentOperatingp; - S32 mLevel; - BOOL (*mInsertFirst)(const DATA_TYPE *first, const DATA_TYPE *second); - BOOL (*mEquals)(const DATA_TYPE *first, const DATA_TYPE *second); -}; - - -// basic constructor -template <class DATA_TYPE, S32 BINARY_DEPTH> -LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::LLPtrSkipList() - : mInsertFirst(NULL), mEquals(defaultEquals) -{ - if (BINARY_DEPTH < 2) - { - llerrs << "Trying to create skip list with too little depth, " - "must be 2 or greater" << llendl; - } - S32 i; - for (i = 0; i < BINARY_DEPTH; i++) - { - mUpdate[i] = NULL; - } - mLevel = 1; - mCurrentp = *(mHead.mForward); - mCurrentOperatingp = *(mHead.mForward); -} - -// basic constructor including sorter -template <class DATA_TYPE, S32 BINARY_DEPTH> -LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::LLPtrSkipList(BOOL (*insert_first)(DATA_TYPE *first, DATA_TYPE *second), - BOOL (*equals)(DATA_TYPE *first, DATA_TYPE *second)) - :mInsertFirst(insert_first), mEquals(equals) -{ - if (BINARY_DEPTH < 2) - { - llerrs << "Trying to create skip list with too little depth, " - "must be 2 or greater" << llendl; - } - mLevel = 1; - S32 i; - for (i = 0; i < BINARY_DEPTH; i++) - { - mHead.mForward[i] = NULL; - mUpdate[i] = NULL; - } - mCurrentp = *(mHead.mForward); - mCurrentOperatingp = *(mHead.mForward); -} - -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::~LLPtrSkipList() -{ - removeAllNodes(); -} - -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline void LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::setInsertFirst(BOOL (*insert_first)(const DATA_TYPE *first, const DATA_TYPE *second)) -{ - mInsertFirst = insert_first; -} - -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline void LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::setEquals(BOOL (*equals)(const DATA_TYPE *first, const DATA_TYPE *second)) -{ - mEquals = equals; -} - -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline BOOL LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::addData(DATA_TYPE *data) -{ - S32 level; - LLPtrSkipNode *current = &mHead; - LLPtrSkipNode *temp; - - // find the pointer one in front of the one we want - if (mInsertFirst) - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(mInsertFirst(temp->mData, data))) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - else - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(temp->mData < data)) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - - - // we're now just in front of where we want to be . . . take one step forward - current = *current->mForward; - - // now add the new node - S32 newlevel; - for (newlevel = 1; newlevel <= mLevel && newlevel < BINARY_DEPTH; newlevel++) - { - if (ll_frand() < 0.5f) - break; - } - - LLPtrSkipNode *snode = new LLPtrSkipNode(data); - - if (newlevel > mLevel) - { - mHead.mForward[mLevel] = NULL; - mUpdate[mLevel] = &mHead; - mLevel = newlevel; - } - - for (level = 0; level < newlevel; level++) - { - snode->mForward[level] = mUpdate[level]->mForward[level]; - mUpdate[level]->mForward[level] = snode; - } - return TRUE; -} - -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline BOOL LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::checkData(const DATA_TYPE *data) -{ - S32 level; - LLPtrSkipNode *current = &mHead; - LLPtrSkipNode *temp; - - // find the pointer one in front of the one we want - if (mInsertFirst) - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(mInsertFirst(temp->mData, data))) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - else - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(temp->mData < data)) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - - - // we're now just in front of where we want to be . . . take one step forward - current = *current->mForward; - - if (current) - { - return mEquals(current->mData, data); - } - else - { - return FALSE; - } -} - -// returns number of items in the list -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline S32 LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::getLength() -{ - U32 length = 0; - for (LLPtrSkipNode* temp = *(mHead.mForward); temp != NULL; temp = temp->mForward[0]) - { - length++; - } - return length; -} - -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline BOOL LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::removeData(const DATA_TYPE *data) -{ - S32 level; - LLPtrSkipNode *current = &mHead; - LLPtrSkipNode *temp; - - // find the pointer one in front of the one we want - if (mInsertFirst) - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(mInsertFirst(temp->mData, data))) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - else - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(temp->mData < data)) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - - - // we're now just in front of where we want to be . . . take one step forward - current = *current->mForward; - - if (!current) - { - // empty list or beyond the end! - return FALSE; - } - - // is this the one we want? - if (!mEquals(current->mData, data)) - { - // nope! - return FALSE; - } - else - { - // yes it is! change pointers as required - for (level = 0; level < mLevel; level++) - { - if (mUpdate[level]->mForward[level] != current) - { - // cool, we've fixed all the pointers! - break; - } - mUpdate[level]->mForward[level] = current->mForward[level]; - } - - // clean up cuurent - current->removeData(); - delete current; - - // clean up mHead - while ( (mLevel > 1) - &&(!mHead.mForward[mLevel - 1])) - { - mLevel--; - } - } - return TRUE; -} - -// note that b_sort is ignored -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline BOOL LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::moveData(const DATA_TYPE *data, LLPtrSkipList *newlist, BOOL b_sort) -{ - BOOL removed = removeData(data); - BOOL added = newlist->addData(data); - return removed && added; -} - -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline BOOL LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::moveCurrentData(LLPtrSkipList *newlist, BOOL b_sort) -{ - if (mCurrentOperatingp) - { - mCurrentp = mCurrentOperatingp->mForward[0]; - BOOL removed = removeData(mCurrentOperatingp); - BOOL added = newlist->addData(mCurrentOperatingp); - mCurrentOperatingp = mCurrentp; - return removed && added; - } - return FALSE; -} - -// resort -- use when the value we're sorting by changes -/* IW 12/6/02 - This doesn't work! - Instead, remove the data BEFORE you change it - Then re-insert it after you change it -BOOL resortData(DATA_TYPE *data) -{ - removeData(data); - addData(data); -} -*/ - -// remove all nodes from the list but do not delete data -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline void LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::removeAllNodes() -{ - LLPtrSkipNode *temp; - // reset mCurrentp - mCurrentp = *(mHead.mForward); - - while (mCurrentp) - { - temp = mCurrentp->mForward[0]; - mCurrentp->removeData(); - delete mCurrentp; - mCurrentp = temp; - } - - S32 i; - for (i = 0; i < BINARY_DEPTH; i++) - { - mHead.mForward[i] = NULL; - mUpdate[i] = NULL; - } - - mCurrentp = *(mHead.mForward); - mCurrentOperatingp = *(mHead.mForward); -} - -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline BOOL LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::deleteData(const DATA_TYPE *data) -{ - S32 level; - LLPtrSkipNode *current = &mHead; - LLPtrSkipNode *temp; - - // find the pointer one in front of the one we want - if (mInsertFirst) - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(mInsertFirst(temp->mData, data))) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - else - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(temp->mData < data)) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - - - // we're now just in front of where we want to be . . . take one step forward - current = *current->mForward; - - if (!current) - { - // empty list or beyond the end! - return FALSE; - } - - // is this the one we want? - if (!mEquals(current->mData, data)) - { - // nope! - return FALSE; - } - else - { - // do we need to fix current or currentop? - if (current == mCurrentp) - { - mCurrentp = current->mForward[0]; - } - - if (current == mCurrentOperatingp) - { - mCurrentOperatingp = current->mForward[0]; - } - - // yes it is! change pointers as required - for (level = 0; level < mLevel; level++) - { - if (mUpdate[level]->mForward[level] != current) - { - // cool, we've fixed all the pointers! - break; - } - mUpdate[level]->mForward[level] = current->mForward[level]; - } - - // clean up cuurent - current->deleteData(); - delete current; - - // clean up mHead - while ( (mLevel > 1) - &&(!mHead.mForward[mLevel - 1])) - { - mLevel--; - } - } - return TRUE; -} - -// remove all nodes from the list and delete data -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline void LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::deleteAllData() -{ - LLPtrSkipNode *temp; - // reset mCurrentp - mCurrentp = *(mHead.mForward); - - while (mCurrentp) - { - temp = mCurrentp->mForward[0]; - mCurrentp->deleteData(); - delete mCurrentp; - mCurrentp = temp; - } - - S32 i; - for (i = 0; i < BINARY_DEPTH; i++) - { - mHead.mForward[i] = NULL; - mUpdate[i] = NULL; - } - - mCurrentp = *(mHead.mForward); - mCurrentOperatingp = *(mHead.mForward); -} - -// place mCurrentp on first node -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline void LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::resetList() -{ - mCurrentp = *(mHead.mForward); - mCurrentOperatingp = *(mHead.mForward); -} - -// return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline DATA_TYPE *LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::getCurrentData() -{ - if (mCurrentp) - { - mCurrentOperatingp = mCurrentp; - mCurrentp = *mCurrentp->mForward; - return mCurrentOperatingp->mData; - } - else - { - //return NULL; // causes compile warning - return 0; // equivalent, but no warning - } -} - -// same as getCurrentData() but a more intuitive name for the operation -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline DATA_TYPE *LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::getNextData() -{ - if (mCurrentp) - { - mCurrentOperatingp = mCurrentp; - mCurrentp = *mCurrentp->mForward; - return mCurrentOperatingp->mData; - } - else - { - //return NULL; // causes compile warning - return 0; // equivalent, but no warning - } -} - -// remove the Node at mCurentOperatingp -// leave mCurrentp and mCurentOperatingp on the next entry -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline void LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::removeCurrentData() -{ - if (mCurrentOperatingp) - { - removeData(mCurrentOperatingp->mData); - } -} - -// delete the Node at mCurentOperatingp -// leave mCurrentp and mCurentOperatingp on the next entry -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline void LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::deleteCurrentData() -{ - if (mCurrentOperatingp) - { - deleteData(mCurrentOperatingp->mData); - } -} - -// reset the list and return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline DATA_TYPE *LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::getFirstData() -{ - mCurrentp = *(mHead.mForward); - mCurrentOperatingp = *(mHead.mForward); - if (mCurrentp) - { - mCurrentOperatingp = mCurrentp; - mCurrentp = mCurrentp->mForward[0]; - return mCurrentOperatingp->mData; - } - else - { - //return NULL; // causes compile warning - return 0; // equivalent, but no warning - } -} - -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline BOOL LLPtrSkipList<DATA_TYPE, BINARY_DEPTH>::corrupt() -{ - LLPtrSkipNode *previous = mHead.mForward[0]; - - // Empty lists are not corrupt. - if (!previous) return FALSE; - - LLPtrSkipNode *current = previous->mForward[0]; - while(current) - { - if (!mInsertFirst(previous->mData, current->mData)) - { - // prev shouldn't be in front of cur! - return TRUE; - } - current = current->mForward[0]; - } - return FALSE; -} - -#endif diff --git a/indra/llcommon/llptrskipmap.h b/indra/llcommon/llptrskipmap.h deleted file mode 100755 index 94bc71ec55..0000000000 --- a/indra/llcommon/llptrskipmap.h +++ /dev/null @@ -1,1239 +0,0 @@ -/** - * @file llptrskipmap.h - * @brief Just like a LLSkipMap, but since it's pointers, you can call - * deleteAllData - * - * $LicenseInfo:firstyear=2003&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ -#ifndef LL_LLPTRSKIPMAP_H -#define LL_LLPTRSKIPMAP_H - -#include "llerror.h" -#include "llrand.h" - -template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH = 8> -class LLPtrSkipMapNode -{ -public: - LLPtrSkipMapNode() - { - S32 i; - for (i = 0; i < BINARY_DEPTH; i++) - { - mForward[i] = NULL; - } - - U8 *zero = (U8 *)&mIndex; - - for (i = 0; i < (S32)sizeof(INDEX_T); i++) - { - *(zero + i) = 0; - } - - zero = (U8 *)&mData; - - for (i = 0; i < (S32)sizeof(DATA_T); i++) - { - *(zero + i) = 0; - } - } - - LLPtrSkipMapNode(const INDEX_T &index) - : mIndex(index) - { - - S32 i; - for (i = 0; i < BINARY_DEPTH; i++) - { - mForward[i] = NULL; - } - - U8 *zero = (U8 *)&mData; - - for (i = 0; i < (S32)sizeof(DATA_T); i++) - { - *(zero + i) = 0; - } - } - - LLPtrSkipMapNode(const INDEX_T &index, DATA_T datap) - : mIndex(index) - { - - S32 i; - for (i = 0; i < BINARY_DEPTH; i++) - { - mForward[i] = NULL; - } - - mData = datap; - } - - ~LLPtrSkipMapNode() - { - } - - // delete associated data and NULLs out pointer - void deleteData() - { - delete mData; - mData = 0; - } - - // NULLs out pointer - void removeData() - { - mData = 0; - } - - INDEX_T mIndex; - DATA_T mData; - LLPtrSkipMapNode *mForward[BINARY_DEPTH]; - -private: - // Disallow copying of LLPtrSkipMapNodes by not implementing these methods. - LLPtrSkipMapNode(const LLPtrSkipMapNode &); - LLPtrSkipMapNode &operator=(const LLPtrSkipMapNode &rhs); -}; - -//--------------------------------------------------------------------------- - -template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH = 8> -class LLPtrSkipMap -{ -public: - typedef BOOL (*compare)(const DATA_T& first, const DATA_T& second); - typedef compare insert_func; - typedef compare equals_func; - - void init(); - - // basic constructor - LLPtrSkipMap(); - - // basic constructor including sorter - LLPtrSkipMap(insert_func insert_first, equals_func equals); - - ~LLPtrSkipMap(); - - void setInsertFirst(insert_func insert_first); - void setEquals(equals_func equals); - - DATA_T &addData(const INDEX_T &index, DATA_T datap); - DATA_T &addData(const INDEX_T &index); - DATA_T &getData(const INDEX_T &index); - DATA_T &operator[](const INDEX_T &index); - - // If index present, returns data. - // If index not present, adds <index,NULL> and returns NULL. - DATA_T &getData(const INDEX_T &index, BOOL &b_new_entry); - - // returns data entry before and after index - BOOL getInterval(const INDEX_T &index, INDEX_T &index_before, INDEX_T &index_after, - DATA_T &data_before, DATA_T &data_after ); - - // Returns TRUE if data present in map. - BOOL checkData(const INDEX_T &index); - - // Returns TRUE if key is present in map. This is useful if you - // are potentially storing NULL pointers in the map - BOOL checkKey(const INDEX_T &index); - - // If there, returns the data. - // If not, returns NULL. - // Never adds entries to the map. - DATA_T getIfThere(const INDEX_T &index); - - INDEX_T reverseLookup(const DATA_T datap); - - // returns number of items in the list - S32 getLength(); // WARNING! getLength is O(n), not O(1)! - - BOOL removeData(const INDEX_T &index); - BOOL deleteData(const INDEX_T &index); - - // remove all nodes from the list but do not delete data - void removeAllData(); - void deleteAllData(); - - // place mCurrentp on first node - void resetList(); - - // return the data currently pointed to - DATA_T getCurrentDataWithoutIncrement(); - - // return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp - DATA_T getCurrentData(); - - // same as getCurrentData() but a more intuitive name for the operation - DATA_T getNextData(); - - INDEX_T getNextKey(); - - // return the key currently pointed to - INDEX_T getCurrentKeyWithoutIncrement(); - - // remove the Node at mCurentOperatingp - // leave mCurrentp and mCurentOperatingp on the next entry - void removeCurrentData(); - - void deleteCurrentData(); - - // reset the list and return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp - DATA_T getFirstData(); - - INDEX_T getFirstKey(); - - static BOOL defaultEquals(const INDEX_T &first, const INDEX_T &second) - { - return first == second; - } - -private: - // don't generate implicit copy constructor or copy assignment - LLPtrSkipMap(const LLPtrSkipMap &); - LLPtrSkipMap &operator=(const LLPtrSkipMap &); - -private: - LLPtrSkipMapNode<INDEX_T, DATA_T, BINARY_DEPTH> mHead; - LLPtrSkipMapNode<INDEX_T, DATA_T, BINARY_DEPTH> *mUpdate[BINARY_DEPTH]; - LLPtrSkipMapNode<INDEX_T, DATA_T, BINARY_DEPTH> *mCurrentp; - LLPtrSkipMapNode<INDEX_T, DATA_T, BINARY_DEPTH> *mCurrentOperatingp; - S32 mLevel; - BOOL (*mInsertFirst)(const INDEX_T &first, const INDEX_T &second); - BOOL (*mEquals)(const INDEX_T &first, const INDEX_T &second); - S32 mNumberOfSteps; -}; - -////////////////////////////////////////////////// -// -// LLPtrSkipMap implementation -// -// - -template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH> -inline LLPtrSkipMap<INDEX_T, DATA_T, BINARY_DEPTH>::LLPtrSkipMap() - : mInsertFirst(NULL), - mEquals(defaultEquals), - mNumberOfSteps(0) -{ - if (BINARY_DEPTH < 2) - { - llerrs << "Trying to create skip list with too little depth, " - "must be 2 or greater" << llendl; - } - S32 i; - for (i = 0; i < BINARY_DEPTH; i++) - { - mUpdate[i] = NULL; - } - mLevel = 1; - mCurrentp = *(mHead.mForward); - mCurrentOperatingp = *(mHead.mForward); -} - -template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH> -inline LLPtrSkipMap<INDEX_T, DATA_T, BINARY_DEPTH>::LLPtrSkipMap(insert_func insert_first, - equals_func equals) -: mInsertFirst(insert_first), - mEquals(equals), - mNumberOfSteps(0) -{ - if (BINARY_DEPTH < 2) - { - llerrs << "Trying to create skip list with too little depth, " - "must be 2 or greater" << llendl; - } - mLevel = 1; - S32 i; - for (i = 0; i < BINARY_DEPTH; i++) - { - mHead.mForward[i] = NULL; - mUpdate[i] = NULL; - } - mCurrentp = *(mHead.mForward); - mCurrentOperatingp = *(mHead.mForward); -} - -template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH> -inline LLPtrSkipMap<INDEX_T, DATA_T, BINARY_DEPTH>::~LLPtrSkipMap() -{ - removeAllData(); -} - -template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH> -inline void LLPtrSkipMap<INDEX_T, DATA_T, BINARY_DEPTH>::setInsertFirst(insert_func insert_first) -{ - mInsertFirst = insert_first; -} - -template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH> -inline void LLPtrSkipMap<INDEX_T, DATA_T, BINARY_DEPTH>::setEquals(equals_func equals) -{ - mEquals = equals; -} - -template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH> -inline DATA_T &LLPtrSkipMap<INDEX_T, DATA_T, BINARY_DEPTH>::addData(const INDEX_T &index, DATA_T datap) -{ - S32 level; - LLPtrSkipMapNode<INDEX_T, DATA_T, BINARY_DEPTH> *current = &mHead; - LLPtrSkipMapNode<INDEX_T, DATA_T, BINARY_DEPTH> *temp; - - // find the pointer one in front of the one we want - if (mInsertFirst) - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(mInsertFirst(temp->mIndex, index))) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - else - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(temp->mIndex < index)) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - - // we're now just in front of where we want to be . . . take one step forward - current = *current->mForward; - - // replace the existing data if a node is already there - if ( (current) - &&(mEquals(current->mIndex, index))) - { - current->mData = datap; - return current->mData; - } - - // now add the new node - S32 newlevel; - for (newlevel = 1; newlevel <= mLevel && newlevel < BINARY_DEPTH; newlevel++) - { - if (ll_frand() < 0.5f) - { - break; - } - } - - LLPtrSkipMapNode<INDEX_T, DATA_T, BINARY_DEPTH> *snode - = new LLPtrSkipMapNode<INDEX_T, DATA_T, BINARY_DEPTH>(index, datap); - - if (newlevel > mLevel) - { - mHead.mForward[mLevel] = NULL; - mUpdate[mLevel] = &mHead; - mLevel = newlevel; - } - - for (level = 0; level < newlevel; level++) - { - snode->mForward[level] = mUpdate[level]->mForward[level]; - mUpdate[level]->mForward[level] = snode; - } - return snode->mData; -} - -template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH> -inline DATA_T &LLPtrSkipMap<INDEX_T, DATA_T, BINARY_DEPTH>::addData(const INDEX_T &index) -{ - S32 level; - LLPtrSkipMapNode<INDEX_T, DATA_T, BINARY_DEPTH> *current = &mHead; - LLPtrSkipMapNode<INDEX_T, DATA_T, BINARY_DEPTH> *temp; - - // find the pointer one in front of the one we want - if (mInsertFirst) - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(mInsertFirst(temp->mIndex, index))) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - else - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(temp->mIndex < index)) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - - // we're now just in front of where we want to be . . . take one step forward - current = *current->mForward; - - // now add the new node - S32 newlevel; - for (newlevel = 1; newlevel <= mLevel && newlevel < BINARY_DEPTH; newlevel++) - { - if (ll_frand() < 0.5f) - break; - } - - LLPtrSkipMapNode<INDEX_T, DATA_T, BINARY_DEPTH> *snode - = new LLPtrSkipMapNode<INDEX_T, DATA_T, BINARY_DEPTH>(index); - - if (newlevel > mLevel) - { - mHead.mForward[mLevel] = NULL; - mUpdate[mLevel] = &mHead; - mLevel = newlevel; - } - - for (level = 0; level < newlevel; level++) - { - snode->mForward[level] = mUpdate[level]->mForward[level]; - mUpdate[level]->mForward[level] = snode; - } - return snode->mData; -} - -template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH> -inline DATA_T &LLPtrSkipMap<INDEX_T, DATA_T, BINARY_DEPTH>::getData(const INDEX_T &index) -{ - S32 level; - LLPtrSkipMapNode<INDEX_T, DATA_T, BINARY_DEPTH> *current = &mHead; - LLPtrSkipMapNode<INDEX_T, DATA_T, BINARY_DEPTH> *temp; - - mNumberOfSteps = 0; - - // find the pointer one in front of the one we want - if (mInsertFirst) - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(mInsertFirst(temp->mIndex, index))) - { - current = temp; - temp = *(current->mForward + level); - mNumberOfSteps++; - } - *(mUpdate + level) = current; - } - } - else - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(temp->mIndex < index)) - { - current = temp; - temp = *(current->mForward + level); - mNumberOfSteps++; - } - *(mUpdate + level) = current; - } - } - - // we're now just in front of where we want to be . . . take one step forward - current = *current->mForward; - mNumberOfSteps++; - - if ( (current) - &&(mEquals(current->mIndex, index))) - { - - return current->mData; - } - - // now add the new node - S32 newlevel; - for (newlevel = 1; newlevel <= mLevel && newlevel < BINARY_DEPTH; newlevel++) - { - if (ll_frand() < 0.5f) - break; - } - - LLPtrSkipMapNode<INDEX_T, DATA_T, BINARY_DEPTH> *snode - = new LLPtrSkipMapNode<INDEX_T, DATA_T, BINARY_DEPTH>(index); - - if (newlevel > mLevel) - { - mHead.mForward[mLevel] = NULL; - mUpdate[mLevel] = &mHead; - mLevel = newlevel; - } - - for (level = 0; level < newlevel; level++) - { - snode->mForward[level] = mUpdate[level]->mForward[level]; - mUpdate[level]->mForward[level] = snode; - } - - return snode->mData; -} - -template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH> -inline BOOL LLPtrSkipMap<INDEX_T, DATA_T, BINARY_DEPTH>::getInterval(const INDEX_T &index, - INDEX_T &index_before, - INDEX_T &index_after, - DATA_T &data_before, - DATA_T &data_after) -{ - S32 level; - LLPtrSkipMapNode<INDEX_T, DATA_T, BINARY_DEPTH> *current = &mHead; - LLPtrSkipMapNode<INDEX_T, DATA_T, BINARY_DEPTH> *temp; - - mNumberOfSteps = 0; - - // find the pointer one in front of the one we want - if (mInsertFirst) - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(mInsertFirst(temp->mIndex, index))) - { - current = temp; - temp = *(current->mForward + level); - mNumberOfSteps++; - } - *(mUpdate + level) = current; - } - } - else - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(temp->mIndex < index)) - { - current = temp; - temp = *(current->mForward + level); - mNumberOfSteps++; - } - *(mUpdate + level) = current; - } - } - - BOOL both_found = TRUE; - - if (current != &mHead) - { - index_before = current->mIndex; - data_before = current->mData; - } - else - { - data_before = 0; - index_before = 0; - both_found = FALSE; - } - - // we're now just in front of where we want to be . . . take one step forward - mNumberOfSteps++; - current = *current->mForward; - - if (current) - { - data_after = current->mData; - index_after = current->mIndex; - } - else - { - data_after = 0; - index_after = 0; - both_found = FALSE; - } - - return both_found; -} - - -template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH> -inline DATA_T &LLPtrSkipMap<INDEX_T, DATA_T, BINARY_DEPTH>::operator[](const INDEX_T &index) -{ - - return getData(index); -} - -// If index present, returns data. -// If index not present, adds <index,NULL> and returns NULL. -template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH> -inline DATA_T &LLPtrSkipMap<INDEX_T, DATA_T, BINARY_DEPTH>::getData(const INDEX_T &index, BOOL &b_new_entry) -{ - S32 level; - LLPtrSkipMapNode<INDEX_T, DATA_T, BINARY_DEPTH> *current = &mHead; - LLPtrSkipMapNode<INDEX_T, DATA_T, BINARY_DEPTH> *temp; - - mNumberOfSteps = 0; - - // find the pointer one in front of the one we want - if (mInsertFirst) - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(mInsertFirst(temp->mIndex, index))) - { - current = temp; - temp = *(current->mForward + level); - mNumberOfSteps++; - } - *(mUpdate + level) = current; - } - } - else - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(temp->mIndex < index)) - { - current = temp; - temp = *(current->mForward + level); - mNumberOfSteps++; - } - *(mUpdate + level) = current; - } - } - - // we're now just in front of where we want to be . . . take one step forward - mNumberOfSteps++; - current = *current->mForward; - - if ( (current) - &&(mEquals(current->mIndex, index))) - { - - return current->mData; - } - b_new_entry = TRUE; - addData(index); - - return current->mData; -} - -// Returns TRUE if data present in map. -template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH> -inline BOOL LLPtrSkipMap<INDEX_T, DATA_T, BINARY_DEPTH>::checkData(const INDEX_T &index) -{ - S32 level; - LLPtrSkipMapNode<INDEX_T, DATA_T, BINARY_DEPTH> *current = &mHead; - LLPtrSkipMapNode<INDEX_T, DATA_T, BINARY_DEPTH> *temp; - - // find the pointer one in front of the one we want - if (mInsertFirst) - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(mInsertFirst(temp->mIndex, index))) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - else - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(temp->mIndex < index)) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - - // we're now just in front of where we want to be . . . take one step forward - current = *current->mForward; - - if (current) - { - // Gets rid of some compiler ambiguity for the LLPointer<> templated class. - if (current->mData) - { - return mEquals(current->mIndex, index); - } - } - - return FALSE; -} - -// Returns TRUE if key is present in map. This is useful if you -// are potentially storing NULL pointers in the map -template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH> -inline BOOL LLPtrSkipMap<INDEX_T, DATA_T, BINARY_DEPTH>::checkKey(const INDEX_T &index) -{ - S32 level; - LLPtrSkipMapNode<INDEX_T, DATA_T, BINARY_DEPTH> *current = &mHead; - LLPtrSkipMapNode<INDEX_T, DATA_T, BINARY_DEPTH> *temp; - - // find the pointer one in front of the one we want - if (mInsertFirst) - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(mInsertFirst(temp->mIndex, index))) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - else - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(temp->mIndex < index)) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - - // we're now just in front of where we want to be . . . take one step forward - current = *current->mForward; - - if (current) - { - return mEquals(current->mIndex, index); - } - - return FALSE; -} - -// If there, returns the data. -// If not, returns NULL. -// Never adds entries to the map. -template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH> -inline DATA_T LLPtrSkipMap<INDEX_T, DATA_T, BINARY_DEPTH>::getIfThere(const INDEX_T &index) -{ - S32 level; - LLPtrSkipMapNode<INDEX_T, DATA_T, BINARY_DEPTH> *current = &mHead; - LLPtrSkipMapNode<INDEX_T, DATA_T, BINARY_DEPTH> *temp; - - mNumberOfSteps = 0; - - // find the pointer one in front of the one we want - if (mInsertFirst) - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(mInsertFirst(temp->mIndex, index))) - { - current = temp; - temp = *(current->mForward + level); - mNumberOfSteps++; - } - *(mUpdate + level) = current; - } - } - else - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(temp->mIndex < index)) - { - current = temp; - temp = *(current->mForward + level); - mNumberOfSteps++; - } - *(mUpdate + level) = current; - } - } - - // we're now just in front of where we want to be . . . take one step forward - mNumberOfSteps++; - current = *current->mForward; - - if (current) - { - if (mEquals(current->mIndex, index)) - { - return current->mData; - } - } - - // Avoid Linux compiler warning on returning NULL. - return (DATA_T)0; -} - -template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH> -inline INDEX_T LLPtrSkipMap<INDEX_T, DATA_T, BINARY_DEPTH>::reverseLookup(const DATA_T datap) -{ - LLPtrSkipMapNode<INDEX_T, DATA_T, BINARY_DEPTH> *current = &mHead; - - while (current) - { - if (datap == current->mData) - { - - return current->mIndex; - } - current = *current->mForward; - } - - // not found! return NULL - return INDEX_T(); -} - -// returns number of items in the list -template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH> -inline S32 LLPtrSkipMap<INDEX_T, DATA_T, BINARY_DEPTH>::getLength() -{ - U32 length = 0; - LLPtrSkipMapNode<INDEX_T, DATA_T, BINARY_DEPTH>* temp; - for (temp = *(mHead.mForward); temp != NULL; temp = temp->mForward[0]) - { - length++; - } - - return length; -} - -template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH> -inline BOOL LLPtrSkipMap<INDEX_T, DATA_T, BINARY_DEPTH>::removeData(const INDEX_T &index) -{ - S32 level; - LLPtrSkipMapNode<INDEX_T, DATA_T, BINARY_DEPTH> *current = &mHead; - LLPtrSkipMapNode<INDEX_T, DATA_T, BINARY_DEPTH> *temp; - - // find the pointer one in front of the one we want - if (mInsertFirst) - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(mInsertFirst(temp->mIndex, index))) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - else - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(temp->mIndex < index)) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - - // we're now just in front of where we want to be . . . take one step forward - current = *current->mForward; - - if (!current) - { - // empty list or beyond the end! - - return FALSE; - } - - // is this the one we want? - if (!mEquals(current->mIndex, index)) - { - // nope! - - return FALSE; - } - else - { - // do we need to fix current or currentop? - if (current == mCurrentp) - { - mCurrentp = *current->mForward; - } - - if (current == mCurrentOperatingp) - { - mCurrentOperatingp = *current->mForward; - } - // yes it is! change pointers as required - for (level = 0; level < mLevel; level++) - { - if (*((*(mUpdate + level))->mForward + level) != current) - { - // cool, we've fixed all the pointers! - break; - } - *((*(mUpdate + level))->mForward + level) = *(current->mForward + level); - } - - // clean up cuurent - current->removeData(); - delete current; - - // clean up mHead - while ( (mLevel > 1) - &&(!*(mHead.mForward + mLevel - 1))) - { - mLevel--; - } - } - - return TRUE; -} - -template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH> -inline BOOL LLPtrSkipMap<INDEX_T, DATA_T, BINARY_DEPTH>::deleteData(const INDEX_T &index) -{ - S32 level; - LLPtrSkipMapNode<INDEX_T, DATA_T, BINARY_DEPTH> *current = &mHead; - LLPtrSkipMapNode<INDEX_T, DATA_T, BINARY_DEPTH> *temp; - - // find the pointer one in front of the one we want - if (mInsertFirst) - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(mInsertFirst(temp->mIndex, index))) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - else - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(temp->mIndex < index)) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - - // we're now just in front of where we want to be . . . take one step forward - current = *current->mForward; - - if (!current) - { - // empty list or beyond the end! - - return FALSE; - } - - // is this the one we want? - if (!mEquals(current->mIndex, index)) - { - // nope! - - return FALSE; - } - else - { - // do we need to fix current or currentop? - if (current == mCurrentp) - { - mCurrentp = *current->mForward; - } - - if (current == mCurrentOperatingp) - { - mCurrentOperatingp = *current->mForward; - } - // yes it is! change pointers as required - for (level = 0; level < mLevel; level++) - { - if (*((*(mUpdate + level))->mForward + level) != current) - { - // cool, we've fixed all the pointers! - break; - } - *((*(mUpdate + level))->mForward + level) = *(current->mForward + level); - } - - // clean up cuurent - current->deleteData(); - delete current; - - // clean up mHead - while ( (mLevel > 1) - &&(!*(mHead.mForward + mLevel - 1))) - { - mLevel--; - } - } - - return TRUE; -} - -// remove all nodes from the list but do not delete data -template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH> -void LLPtrSkipMap<INDEX_T, DATA_T, BINARY_DEPTH>::removeAllData() -{ - LLPtrSkipMapNode<INDEX_T, DATA_T, BINARY_DEPTH> *temp; - // reset mCurrentp - mCurrentp = *(mHead.mForward); - - while (mCurrentp) - { - temp = mCurrentp->mForward[0]; - mCurrentp->removeData(); - delete mCurrentp; - mCurrentp = temp; - } - - S32 i; - for (i = 0; i < BINARY_DEPTH; i++) - { - mHead.mForward[i] = NULL; - mUpdate[i] = NULL; - } - - mCurrentp = *(mHead.mForward); - mCurrentOperatingp = *(mHead.mForward); -} - -template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH> -inline void LLPtrSkipMap<INDEX_T, DATA_T, BINARY_DEPTH>::deleteAllData() -{ - LLPtrSkipMapNode<INDEX_T, DATA_T, BINARY_DEPTH> *temp; - // reset mCurrentp - mCurrentp = *(mHead.mForward); - - while (mCurrentp) - { - temp = mCurrentp->mForward[0]; - mCurrentp->deleteData(); - delete mCurrentp; - mCurrentp = temp; - } - - S32 i; - for (i = 0; i < BINARY_DEPTH; i++) - { - mHead.mForward[i] = NULL; - mUpdate[i] = NULL; - } - - mCurrentp = *(mHead.mForward); - mCurrentOperatingp = *(mHead.mForward); -} - -// place mCurrentp on first node -template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH> -inline void LLPtrSkipMap<INDEX_T, DATA_T, BINARY_DEPTH>::resetList() -{ - mCurrentp = *(mHead.mForward); - mCurrentOperatingp = *(mHead.mForward); -} - - -// return the data currently pointed to -template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH> -inline DATA_T LLPtrSkipMap<INDEX_T, DATA_T, BINARY_DEPTH>::getCurrentDataWithoutIncrement() -{ - if (mCurrentOperatingp) - { - return mCurrentOperatingp->mData; - } - else - { - //return NULL; // causes warning - return (DATA_T)0; // equivalent, but no warning - } -} - -// return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp -template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH> -inline DATA_T LLPtrSkipMap<INDEX_T, DATA_T, BINARY_DEPTH>::getCurrentData() -{ - if (mCurrentp) - { - mCurrentOperatingp = mCurrentp; - mCurrentp = mCurrentp->mForward[0]; - return mCurrentOperatingp->mData; - } - else - { - //return NULL; // causes warning - return (DATA_T)0; // equivalent, but no warning - } -} - -// same as getCurrentData() but a more intuitive name for the operation -template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH> -inline DATA_T LLPtrSkipMap<INDEX_T, DATA_T, BINARY_DEPTH>::getNextData() -{ - if (mCurrentp) - { - mCurrentOperatingp = mCurrentp; - mCurrentp = mCurrentp->mForward[0]; - return mCurrentOperatingp->mData; - } - else - { - //return NULL; // causes compile warning - return (DATA_T)0; // equivalent, but removes warning - } -} - -template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH> -inline INDEX_T LLPtrSkipMap<INDEX_T, DATA_T, BINARY_DEPTH>::getNextKey() -{ - if (mCurrentp) - { - mCurrentOperatingp = mCurrentp; - mCurrentp = mCurrentp->mForward[0]; - return mCurrentOperatingp->mIndex; - } - else - { - return mHead.mIndex; - } -} - -// return the key currently pointed to -template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH> -inline INDEX_T LLPtrSkipMap<INDEX_T, DATA_T, BINARY_DEPTH>::getCurrentKeyWithoutIncrement() -{ - if (mCurrentOperatingp) - { - return mCurrentOperatingp->mIndex; - } - else - { - //return NULL; // causes compile warning - return (INDEX_T)0; // equivalent, but removes warning - } -} - - -// remove the Node at mCurentOperatingp -// leave mCurrentp and mCurentOperatingp on the next entry -template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH> -inline void LLPtrSkipMap<INDEX_T, DATA_T, BINARY_DEPTH>::removeCurrentData() -{ - if (mCurrentOperatingp) - { - removeData(mCurrentOperatingp->mIndex); - } -} - -template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH> -inline void LLPtrSkipMap<INDEX_T, DATA_T, BINARY_DEPTH>::deleteCurrentData() -{ - if (mCurrentOperatingp) - { - deleteData(mCurrentOperatingp->mIndex); - } -} - -// reset the list and return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp -template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH> -inline DATA_T LLPtrSkipMap<INDEX_T, DATA_T, BINARY_DEPTH>::getFirstData() -{ - mCurrentp = *(mHead.mForward); - mCurrentOperatingp = *(mHead.mForward); - if (mCurrentp) - { - mCurrentOperatingp = mCurrentp; - mCurrentp = mCurrentp->mForward[0]; - return mCurrentOperatingp->mData; - } - else - { - //return NULL; // causes compile warning - return (DATA_T)0; // equivalent, but removes warning - } -} - -template <class INDEX_T, class DATA_T, S32 BINARY_DEPTH> -inline INDEX_T LLPtrSkipMap<INDEX_T, DATA_T, BINARY_DEPTH>::getFirstKey() -{ - mCurrentp = *(mHead.mForward); - mCurrentOperatingp = *(mHead.mForward); - if (mCurrentp) - { - mCurrentOperatingp = mCurrentp; - mCurrentp = mCurrentp->mForward[0]; - return mCurrentOperatingp->mIndex; - } - else - { - return mHead.mIndex; - } -} - -#endif diff --git a/indra/llcommon/llptrto.h b/indra/llcommon/llptrto.h index 7091d36f6b..4082e30de6 100755 --- a/indra/llcommon/llptrto.h +++ b/indra/llcommon/llptrto.h @@ -33,7 +33,6 @@ #include "llpointer.h" #include "llrefcount.h" // LLRefCount -#include "llthread.h" // LLThreadSafeRefCount #include <boost/type_traits/is_base_of.hpp> #include <boost/type_traits/remove_pointer.hpp> #include <boost/utility/enable_if.hpp> diff --git a/indra/llcommon/llqueuedthread.cpp b/indra/llcommon/llqueuedthread.cpp index abf47a0f57..8cef4293cd 100755 --- a/indra/llcommon/llqueuedthread.cpp +++ b/indra/llcommon/llqueuedthread.cpp @@ -28,6 +28,7 @@ #include "llstl.h" #include "lltimer.h" // ms_sleep() +#include "lltracethreadrecorder.h" //============================================================================ @@ -80,7 +81,7 @@ void LLQueuedThread::shutdown() } if (timeout == 0) { - llwarns << "~LLQueuedThread (" << mName << ") timed out!" << llendl; + LL_WARNS() << "~LLQueuedThread (" << mName << ") timed out!" << LL_ENDL; } } else @@ -101,7 +102,7 @@ void LLQueuedThread::shutdown() } if (active_count) { - llwarns << "~LLQueuedThread() called with active requests: " << active_count << llendl; + LL_WARNS() << "~LLQueuedThread() called with active requests: " << active_count << LL_ENDL; } } @@ -134,8 +135,8 @@ S32 LLQueuedThread::updateQueue(F32 max_time_ms) pending = getPending(); if(pending > 0) { - unpause(); - } + unpause(); + } } else { @@ -198,11 +199,11 @@ void LLQueuedThread::printQueueStats() if (!mRequestQueue.empty()) { QueuedRequest *req = *mRequestQueue.begin(); - llinfos << llformat("Pending Requests:%d Current status:%d", mRequestQueue.size(), req->getStatus()) << llendl; + LL_INFOS() << llformat("Pending Requests:%d Current status:%d", mRequestQueue.size(), req->getStatus()) << LL_ENDL; } else { - llinfos << "Queued Thread Idle" << llendl; + LL_INFOS() << "Queued Thread Idle" << LL_ENDL; } unlockData(); } @@ -233,7 +234,7 @@ bool LLQueuedThread::addRequest(QueuedRequest* req) mRequestQueue.insert(req); mRequestHash.insert(req); #if _DEBUG -// llinfos << llformat("LLQueuedThread::Added req [%08d]",handle) << llendl; +// LL_INFOS() << llformat("LLQueuedThread::Added req [%08d]",handle) << LL_ENDL; #endif unlockData(); @@ -245,7 +246,7 @@ bool LLQueuedThread::addRequest(QueuedRequest* req) // MAIN thread bool LLQueuedThread::waitForResult(LLQueuedThread::handle_t handle, bool auto_complete) { - llassert (handle != nullHandle()) + llassert (handle != nullHandle()); bool res = false; bool waspaused = isPaused(); bool done = false; @@ -364,7 +365,7 @@ bool LLQueuedThread::completeRequest(handle_t handle) llassert_always(req->getStatus() != STATUS_QUEUED); llassert_always(req->getStatus() != STATUS_INPROGRESS); #if _DEBUG -// llinfos << llformat("LLQueuedThread::Completed req [%08d]",handle) << llendl; +// LL_INFOS() << llformat("LLQueuedThread::Completed req [%08d]",handle) << LL_ENDL; #endif mRequestHash.erase(handle); req->deleteRequest(); @@ -385,7 +386,7 @@ bool LLQueuedThread::check() { if (entry->getHashKey() > mNextHandle) { - llerrs << "Hash Error" << llendl; + LL_ERRS() << "Hash Error" << LL_ENDL; return false; } entry = entry->getNextEntry(); @@ -403,6 +404,7 @@ S32 LLQueuedThread::processNextRequest() QueuedRequest *req; // Get next request from pool lockData(); + while(1) { req = NULL; @@ -467,10 +469,11 @@ S32 LLQueuedThread::processNextRequest() ms_sleep(1); // sleep the thread a little } } + + LLTrace::get_thread_recorder()->pushToParent(); } S32 pending = getPending(); - return pending; } @@ -499,6 +502,7 @@ void LLQueuedThread::run() if (isQuitting()) { + LLTrace::get_thread_recorder()->pushToParent(); endThread(); break; } @@ -507,15 +511,16 @@ void LLQueuedThread::run() threadedUpdate(); - int res = processNextRequest(); - if (res == 0) + int pending_work = processNextRequest(); + + if (pending_work == 0) { mIdleThread = TRUE; ms_sleep(1); } //LLThread::yield(); // thread should yield after each request } - llinfos << "LLQueuedThread " << mName << " EXITING." << llendl; + LL_INFOS() << "LLQueuedThread " << mName << " EXITING." << LL_ENDL; } // virtual diff --git a/indra/llcommon/llrefcount.cpp b/indra/llcommon/llrefcount.cpp index e1876599fc..a638df2c7c 100755 --- a/indra/llcommon/llrefcount.cpp +++ b/indra/llcommon/llrefcount.cpp @@ -76,7 +76,7 @@ LLRefCount::~LLRefCount() { if (mRef != 0) { - llerrs << "deleting non-zero reference" << llendl; + LL_ERRS() << "deleting non-zero reference" << LL_ENDL; } #if LL_REF_COUNT_DEBUG @@ -95,8 +95,8 @@ void LLRefCount::ref() const if(mMutexp->isLocked()) { mCrashAtUnlock = TRUE ; - llerrs << "the mutex is locked by the thread: " << mLockedThreadID - << " Current thread: " << LLThread::currentID() << llendl ; + LL_ERRS() << "the mutex is locked by the thread: " << mLockedThreadID + << " Current thread: " << LLThread::currentID() << LL_ENDL ; } mMutexp->lock() ; @@ -123,8 +123,8 @@ S32 LLRefCount::unref() const if(mMutexp->isLocked()) { mCrashAtUnlock = TRUE ; - llerrs << "the mutex is locked by the thread: " << mLockedThreadID - << " Current thread: " << LLThread::currentID() << llendl ; + LL_ERRS() << "the mutex is locked by the thread: " << mLockedThreadID + << " Current thread: " << LLThread::currentID() << LL_ENDL ; } mMutexp->lock() ; diff --git a/indra/llcommon/llrefcount.h b/indra/llcommon/llrefcount.h index 32ae15435a..72011d04a0 100755 --- a/indra/llcommon/llrefcount.h +++ b/indra/llcommon/llrefcount.h @@ -28,6 +28,8 @@ #include <boost/noncopyable.hpp> #include <boost/intrusive_ptr.hpp> +#include "llmutex.h" +#include "llapr.h" #define LL_REF_COUNT_DEBUG 0 #if LL_REF_COUNT_DEBUG @@ -61,7 +63,7 @@ public: inline S32 unref() const { llassert(mRef >= 1); - if (0 == --mRef) + if (0 == --mRef) { delete this; return 0; @@ -87,22 +89,91 @@ private: #endif }; + +//============================================================================ + +// see llmemory.h for LLPointer<> definition + +class LL_COMMON_API LLThreadSafeRefCount +{ +public: + static void initThreadSafeRefCount(); // creates sMutex + static void cleanupThreadSafeRefCount(); // destroys sMutex + +private: + static LLMutex* sMutex; + +protected: + virtual ~LLThreadSafeRefCount(); // use unref() + +public: + LLThreadSafeRefCount(); + LLThreadSafeRefCount(const LLThreadSafeRefCount&); + LLThreadSafeRefCount& operator=(const LLThreadSafeRefCount& ref) + { + mRef = 0; + return *this; + } + + void ref() + { + mRef++; + } + + void unref() + { + llassert(mRef >= 1); + if ((--mRef) == 0) // See note in llapr.h on atomic decrement operator return value. + { + // If we hit zero, the caller should be the only smart pointer owning the object and we can delete it. + // It is technically possible for a vanilla pointer to mess this up, or another thread to + // jump in, find this object, create another smart pointer and end up dangling, but if + // the code is that bad and not thread-safe, it's trouble already. + delete this; + } + } + + S32 getNumRefs() const + { + const S32 currentVal = mRef.CurrentValue(); + return currentVal; + } + +private: + LLAtomic32< S32 > mRef; +}; + /** * intrusive pointer support * this allows you to use boost::intrusive_ptr with any LLRefCount-derived type */ +/** + * intrusive pointer support for LLThreadSafeRefCount + * this allows you to use boost::intrusive_ptr with any LLThreadSafeRefCount-derived type + */ namespace boost { - inline void intrusive_ptr_add_ref(LLRefCount* p) + inline void intrusive_ptr_add_ref(LLThreadSafeRefCount* p) { p->ref(); } - inline void intrusive_ptr_release(LLRefCount* p) + inline void intrusive_ptr_release(LLThreadSafeRefCount* p) { - p->unref(); + p->unref(); + } + + inline void intrusive_ptr_add_ref(LLRefCount* p) + { + p->ref(); + } + + inline void intrusive_ptr_release(LLRefCount* p) + { + p->unref(); } }; + #endif diff --git a/indra/llcommon/llregistry.h b/indra/llcommon/llregistry.h index bb0d60247e..29950c108d 100755 --- a/indra/llcommon/llregistry.h +++ b/indra/llcommon/llregistry.h @@ -29,7 +29,6 @@ #include <list> -#include <boost/type_traits.hpp> #include "llsingleton.h" #include "llstl.h" @@ -47,12 +46,11 @@ template <typename KEY, typename VALUE, typename COMPARATOR = LLRegistryDefaultC class LLRegistry { public: - typedef LLRegistry<KEY, VALUE, COMPARATOR> registry_t; - typedef typename boost::add_reference<typename boost::add_const<KEY>::type>::type ref_const_key_t; - typedef typename boost::add_reference<typename boost::add_const<VALUE>::type>::type ref_const_value_t; - typedef typename boost::add_reference<VALUE>::type ref_value_t; - typedef typename boost::add_pointer<typename boost::add_const<VALUE>::type>::type ptr_const_value_t; - typedef typename boost::add_pointer<VALUE>::type ptr_value_t; + typedef LLRegistry<KEY, VALUE, COMPARATOR> registry_t; + typedef const KEY& ref_const_key_t; + typedef const VALUE& ref_const_value_t; + typedef const VALUE* ptr_const_value_t; + typedef VALUE* ptr_value_t; class Registrar { @@ -64,7 +62,7 @@ public: { if (mMap.insert(std::make_pair(key, value)).second == false) { - llwarns << "Tried to register " << key << " but it was already registered!" << llendl; + LL_WARNS() << "Tried to register " << key << " but it was already registered!" << LL_ENDL; return false; } return true; @@ -309,7 +307,7 @@ public: { if (singleton_t::instance().exists(key)) { - llerrs << "Duplicate registry entry under key \"" << key << "\"" << llendl; + LL_ERRS() << "Duplicate registry entry under key \"" << key << "\"" << LL_ENDL; } singleton_t::instance().mStaticScope->add(key, value); } diff --git a/indra/llcommon/llsafehandle.h b/indra/llcommon/llsafehandle.h index 8d52d9bb15..4226bf04f0 100755 --- a/indra/llcommon/llsafehandle.h +++ b/indra/llcommon/llsafehandle.h @@ -134,7 +134,7 @@ protected: tempp->unref(); if (mPointer != NULL) { - llwarns << "Unreference did assignment to non-NULL because of destructor" << llendl; + LL_WARNS() << "Unreference did assignment to non-NULL because of destructor" << LL_ENDL; unref(); } } diff --git a/indra/llcommon/llsdparam.cpp b/indra/llcommon/llsdparam.cpp index 9f4460a988..2e7b46f885 100755 --- a/indra/llcommon/llsdparam.cpp +++ b/indra/llcommon/llsdparam.cpp @@ -30,13 +30,14 @@ // Project includes #include "llsdparam.h" #include "llsdutil.h" +#include "boost/bind.hpp" static LLInitParam::Parser::parser_read_func_map_t sReadFuncs; static LLInitParam::Parser::parser_write_func_map_t sWriteFuncs; static LLInitParam::Parser::parser_inspect_func_map_t sInspectFuncs; static const LLSD NO_VALUE_MARKER; -LLFastTimer::DeclareTimer FTM_SD_PARAM_ADAPTOR("LLSD to LLInitParam conversion"); +LLTrace::BlockTimerStatHandle FTM_SD_PARAM_ADAPTOR("LLSD to LLInitParam conversion"); // // LLParamSDParser @@ -102,13 +103,13 @@ void LLParamSDParser::readSD(const LLSD& sd, LLInitParam::BaseBlock& block, bool //readSDValues(sd, block); } -void LLParamSDParser::writeSD(LLSD& sd, const LLInitParam::BaseBlock& block) +void LLParamSDParser::writeSDImpl(LLSD& sd, const LLInitParam::BaseBlock& block, const LLInitParam::predicate_rule_t rules, const LLInitParam::BaseBlock* diff_block) { mNameStack.clear(); mWriteRootSD = &sd; name_stack_t name_stack; - block.serializeBlock(*this, name_stack); + block.serializeBlock(*this, name_stack, rules, diff_block); } /*virtual*/ std::string LLParamSDParser::getCurrentElementName() @@ -299,6 +300,7 @@ void LLParamSDParserUtilities::readSDValues(read_sd_cb_t cb, const LLSD& sd) LLInitParam::Parser::name_stack_t stack = LLInitParam::Parser::name_stack_t(); readSDValues(cb, sd, stack); } + namespace LLInitParam { // LLSD specialization @@ -329,13 +331,14 @@ namespace LLInitParam p.writeValue<LLSD::String>(sd.asString(), name_stack); } - void ParamValue<LLSD, NOT_BLOCK>::serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const BaseBlock* diff_block) const + bool ParamValue<LLSD, NOT_BLOCK>::serializeBlock(Parser& p, Parser::name_stack_t& name_stack_range, const predicate_rule_t predicate_rule, const BaseBlock* diff_block) const { // attempt to write LLSD out directly - if (!p.writeValue<LLSD>(mValue, name_stack)) + if (!p.writeValue<LLSD>(mValue, name_stack_range)) { // otherwise read from LLSD value and serialize out to parser (which could be LLSD, XUI, etc) - LLParamSDParserUtilities::readSDValues(boost::bind(&serializeElement, boost::ref(p), _1, _2), mValue, name_stack); + LLParamSDParserUtilities::readSDValues(boost::bind(&serializeElement, boost::ref(p), _1, _2), mValue, name_stack_range); } + return true; } } diff --git a/indra/llcommon/llsdparam.h b/indra/llcommon/llsdparam.h index 6ef5debd7b..1542f95e68 100755 --- a/indra/llcommon/llsdparam.h +++ b/indra/llcommon/llsdparam.h @@ -30,6 +30,7 @@ #include "llinitparam.h" #include "boost/function.hpp" +#include "llfasttimer.h" struct LL_COMMON_API LLParamSDParserUtilities { @@ -50,11 +51,28 @@ typedef LLInitParam::Parser parser_t; public: LLParamSDParser(); void readSD(const LLSD& sd, LLInitParam::BaseBlock& block, bool silent = false); - void writeSD(LLSD& sd, const LLInitParam::BaseBlock& block); + template<typename BLOCK> + void writeSD(LLSD& sd, + const BLOCK& block, + const LLInitParam::predicate_rule_t rules = LLInitParam::default_parse_rules(), + const LLInitParam::BaseBlock* diff_block = NULL) + { + if (!diff_block + && !rules.isAmbivalent(LLInitParam::HAS_DEFAULT_VALUE)) + { + diff_block = &LLInitParam::defaultValue<BLOCK>(); + } + writeSDImpl(sd, block, rules, diff_block); + } /*virtual*/ std::string getCurrentElementName(); private: + void writeSDImpl(LLSD& sd, + const LLInitParam::BaseBlock& block, + const LLInitParam::predicate_rule_t, + const LLInitParam::BaseBlock* diff_block); + void submit(LLInitParam::BaseBlock& block, const LLSD& sd, LLInitParam::Parser::name_stack_t& name_stack); template<typename T> @@ -92,7 +110,7 @@ private: }; -extern LL_COMMON_API LLFastTimer::DeclareTimer FTM_SD_PARAM_ADAPTOR; +extern LL_COMMON_API LLTrace::BlockTimerStatHandle FTM_SD_PARAM_ADAPTOR; template<typename T> class LLSDParamAdapter : public T { @@ -100,7 +118,7 @@ public: LLSDParamAdapter() {} LLSDParamAdapter(const LLSD& sd) { - LLFastTimer _(FTM_SD_PARAM_ADAPTOR); + LL_RECORD_BLOCK_TIME(FTM_SD_PARAM_ADAPTOR); LLParamSDParser parser; // don't spam for implicit parsing of LLSD, as we want to allow arbitrary freeform data and ignore most of it bool parse_silently = true; diff --git a/indra/llcommon/llsdserialize.cpp b/indra/llcommon/llsdserialize.cpp index ad4fce6f35..04d7a6ed56 100755 --- a/indra/llcommon/llsdserialize.cpp +++ b/indra/llcommon/llsdserialize.cpp @@ -81,7 +81,7 @@ void LLSDSerialize::serialize(const LLSD& sd, std::ostream& str, ELLSD_Serialize break; default: - llwarns << "serialize request for unknown ELLSD_Serialize" << llendl; + LL_WARNS() << "serialize request for unknown ELLSD_Serialize" << LL_ENDL; } if (f.notNull()) @@ -169,7 +169,7 @@ bool LLSDSerialize::deserialize(LLSD& sd, std::istream& str, S32 max_bytes) } else { - llwarns << "deserialize request for unknown ELLSD_Serialize" << llendl; + LL_WARNS() << "deserialize request for unknown ELLSD_Serialize" << LL_ENDL; } if (p.notNull()) @@ -179,7 +179,7 @@ bool LLSDSerialize::deserialize(LLSD& sd, std::istream& str, S32 max_bytes) } fail: - llwarns << "deserialize LLSD parse failure" << llendl; + LL_WARNS() << "deserialize LLSD parse failure" << LL_ENDL; return false; } @@ -445,7 +445,7 @@ S32 LLSDNotationParser::doParse(std::istream& istr, LLSD& data) const } if(istr.fail()) { - llinfos << "STREAM FAILURE reading map." << llendl; + LL_INFOS() << "STREAM FAILURE reading map." << LL_ENDL; parse_count = PARSE_FAILURE; } break; @@ -464,7 +464,7 @@ S32 LLSDNotationParser::doParse(std::istream& istr, LLSD& data) const } if(istr.fail()) { - llinfos << "STREAM FAILURE reading array." << llendl; + LL_INFOS() << "STREAM FAILURE reading array." << LL_ENDL; parse_count = PARSE_FAILURE; } break; @@ -500,7 +500,7 @@ S32 LLSDNotationParser::doParse(std::istream& istr, LLSD& data) const } if(istr.fail()) { - llinfos << "STREAM FAILURE reading boolean." << llendl; + LL_INFOS() << "STREAM FAILURE reading boolean." << LL_ENDL; parse_count = PARSE_FAILURE; } break; @@ -526,7 +526,7 @@ S32 LLSDNotationParser::doParse(std::istream& istr, LLSD& data) const } if(istr.fail()) { - llinfos << "STREAM FAILURE reading boolean." << llendl; + LL_INFOS() << "STREAM FAILURE reading boolean." << LL_ENDL; parse_count = PARSE_FAILURE; } break; @@ -539,7 +539,7 @@ S32 LLSDNotationParser::doParse(std::istream& istr, LLSD& data) const data = integer; if(istr.fail()) { - llinfos << "STREAM FAILURE reading integer." << llendl; + LL_INFOS() << "STREAM FAILURE reading integer." << LL_ENDL; parse_count = PARSE_FAILURE; } break; @@ -553,7 +553,7 @@ S32 LLSDNotationParser::doParse(std::istream& istr, LLSD& data) const data = real; if(istr.fail()) { - llinfos << "STREAM FAILURE reading real." << llendl; + LL_INFOS() << "STREAM FAILURE reading real." << LL_ENDL; parse_count = PARSE_FAILURE; } break; @@ -567,7 +567,7 @@ S32 LLSDNotationParser::doParse(std::istream& istr, LLSD& data) const data = id; if(istr.fail()) { - llinfos << "STREAM FAILURE reading uuid." << llendl; + LL_INFOS() << "STREAM FAILURE reading uuid." << LL_ENDL; parse_count = PARSE_FAILURE; } break; @@ -582,7 +582,7 @@ S32 LLSDNotationParser::doParse(std::istream& istr, LLSD& data) const } if(istr.fail()) { - llinfos << "STREAM FAILURE reading string." << llendl; + LL_INFOS() << "STREAM FAILURE reading string." << LL_ENDL; parse_count = PARSE_FAILURE; } break; @@ -604,7 +604,7 @@ S32 LLSDNotationParser::doParse(std::istream& istr, LLSD& data) const } if(istr.fail()) { - llinfos << "STREAM FAILURE reading link." << llendl; + LL_INFOS() << "STREAM FAILURE reading link." << LL_ENDL; parse_count = PARSE_FAILURE; } break; @@ -627,7 +627,7 @@ S32 LLSDNotationParser::doParse(std::istream& istr, LLSD& data) const } if(istr.fail()) { - llinfos << "STREAM FAILURE reading date." << llendl; + LL_INFOS() << "STREAM FAILURE reading date." << LL_ENDL; parse_count = PARSE_FAILURE; } break; @@ -640,15 +640,15 @@ S32 LLSDNotationParser::doParse(std::istream& istr, LLSD& data) const } if(istr.fail()) { - llinfos << "STREAM FAILURE reading data." << llendl; + LL_INFOS() << "STREAM FAILURE reading data." << LL_ENDL; parse_count = PARSE_FAILURE; } break; default: parse_count = PARSE_FAILURE; - llinfos << "Unrecognized character while parsing: int(" << (int)c - << ")" << llendl; + LL_INFOS() << "Unrecognized character while parsing: int(" << (int)c + << ")" << LL_ENDL; break; } if(PARSE_FAILURE == parse_count) @@ -909,7 +909,7 @@ S32 LLSDBinaryParser::doParse(std::istream& istr, LLSD& data) const } if(istr.fail()) { - llinfos << "STREAM FAILURE reading binary map." << llendl; + LL_INFOS() << "STREAM FAILURE reading binary map." << LL_ENDL; parse_count = PARSE_FAILURE; } break; @@ -928,7 +928,7 @@ S32 LLSDBinaryParser::doParse(std::istream& istr, LLSD& data) const } if(istr.fail()) { - llinfos << "STREAM FAILURE reading binary array." << llendl; + LL_INFOS() << "STREAM FAILURE reading binary array." << LL_ENDL; parse_count = PARSE_FAILURE; } break; @@ -953,7 +953,7 @@ S32 LLSDBinaryParser::doParse(std::istream& istr, LLSD& data) const data = (S32)ntohl(value_nbo); if(istr.fail()) { - llinfos << "STREAM FAILURE reading binary integer." << llendl; + LL_INFOS() << "STREAM FAILURE reading binary integer." << LL_ENDL; } break; } @@ -965,7 +965,7 @@ S32 LLSDBinaryParser::doParse(std::istream& istr, LLSD& data) const data = ll_ntohd(real_nbo); if(istr.fail()) { - llinfos << "STREAM FAILURE reading binary real." << llendl; + LL_INFOS() << "STREAM FAILURE reading binary real." << LL_ENDL; } break; } @@ -977,7 +977,7 @@ S32 LLSDBinaryParser::doParse(std::istream& istr, LLSD& data) const data = id; if(istr.fail()) { - llinfos << "STREAM FAILURE reading binary uuid." << llendl; + LL_INFOS() << "STREAM FAILURE reading binary uuid." << LL_ENDL; } break; } @@ -998,8 +998,8 @@ S32 LLSDBinaryParser::doParse(std::istream& istr, LLSD& data) const } if(istr.fail()) { - llinfos << "STREAM FAILURE reading binary (notation-style) string." - << llendl; + LL_INFOS() << "STREAM FAILURE reading binary (notation-style) string." + << LL_ENDL; parse_count = PARSE_FAILURE; } break; @@ -1018,7 +1018,7 @@ S32 LLSDBinaryParser::doParse(std::istream& istr, LLSD& data) const } if(istr.fail()) { - llinfos << "STREAM FAILURE reading binary string." << llendl; + LL_INFOS() << "STREAM FAILURE reading binary string." << LL_ENDL; parse_count = PARSE_FAILURE; } break; @@ -1037,7 +1037,7 @@ S32 LLSDBinaryParser::doParse(std::istream& istr, LLSD& data) const } if(istr.fail()) { - llinfos << "STREAM FAILURE reading binary link." << llendl; + LL_INFOS() << "STREAM FAILURE reading binary link." << LL_ENDL; parse_count = PARSE_FAILURE; } break; @@ -1050,7 +1050,7 @@ S32 LLSDBinaryParser::doParse(std::istream& istr, LLSD& data) const data = LLDate(real); if(istr.fail()) { - llinfos << "STREAM FAILURE reading binary date." << llendl; + LL_INFOS() << "STREAM FAILURE reading binary date." << LL_ENDL; parse_count = PARSE_FAILURE; } break; @@ -1079,7 +1079,7 @@ S32 LLSDBinaryParser::doParse(std::istream& istr, LLSD& data) const } if(istr.fail()) { - llinfos << "STREAM FAILURE reading binary." << llendl; + LL_INFOS() << "STREAM FAILURE reading binary." << LL_ENDL; parse_count = PARSE_FAILURE; } break; @@ -1087,8 +1087,8 @@ S32 LLSDBinaryParser::doParse(std::istream& istr, LLSD& data) const default: parse_count = PARSE_FAILURE; - llinfos << "Unrecognized character while parsing: int(" << (int)c - << ")" << llendl; + LL_INFOS() << "Unrecognized character while parsing: int(" << (int)c + << ")" << LL_ENDL; break; } if(PARSE_FAILURE == parse_count) @@ -2017,7 +2017,7 @@ std::string zip_llsd(LLSD& data) S32 ret = deflateInit(&strm, Z_BEST_COMPRESSION); if (ret != Z_OK) { - llwarns << "Failed to compress LLSD block." << llendl; + LL_WARNS() << "Failed to compress LLSD block." << LL_ENDL; return std::string(); } @@ -2044,7 +2044,7 @@ std::string zip_llsd(LLSD& data) if (strm.avail_out >= CHUNK) { free(output); - llwarns << "Failed to compress LLSD block." << llendl; + LL_WARNS() << "Failed to compress LLSD block." << LL_ENDL; return std::string(); } @@ -2056,7 +2056,7 @@ std::string zip_llsd(LLSD& data) else { free(output); - llwarns << "Failed to compress LLSD block." << llendl; + LL_WARNS() << "Failed to compress LLSD block." << LL_ENDL; return std::string(); } } @@ -2073,7 +2073,7 @@ std::string zip_llsd(LLSD& data) LLSD test_sd; if (!unzip_llsd(test_sd, test, result.size())) { - llerrs << "Invalid compression result!" << llendl; + LL_ERRS() << "Invalid compression result!" << LL_ENDL; } #endif @@ -2163,7 +2163,7 @@ bool unzip_llsd(LLSD& data, std::istream& is, S32 size) if (!LLSDSerialize::fromBinary(data, istr, cur_size)) { - llwarns << "Failed to unzip LLSD block" << llendl; + LL_WARNS() << "Failed to unzip LLSD block" << LL_ENDL; free(result); return false; } diff --git a/indra/llcommon/llsdserialize_xml.cpp b/indra/llcommon/llsdserialize_xml.cpp index 614a2d5636..4e2af0e589 100755 --- a/indra/llcommon/llsdserialize_xml.cpp +++ b/indra/llcommon/llsdserialize_xml.cpp @@ -406,7 +406,7 @@ S32 LLSDXMLParser::Impl::parse(std::istream& input, LLSD& data) } if (mEmitErrors) { - llinfos << "LLSDXMLParser::Impl::parse: XML_STATUS_ERROR parsing:" << (char*) buffer << llendl; + LL_INFOS() << "LLSDXMLParser::Impl::parse: XML_STATUS_ERROR parsing:" << (char*) buffer << LL_ENDL; } data = LLSD(); return LLSDParser::PARSE_FAILURE; @@ -487,7 +487,7 @@ S32 LLSDXMLParser::Impl::parseLines(std::istream& input, LLSD& data) { if (mEmitErrors) { - llinfos << "LLSDXMLParser::Impl::parseLines: XML_STATUS_ERROR" << llendl; + LL_INFOS() << "LLSDXMLParser::Impl::parseLines: XML_STATUS_ERROR" << LL_ENDL; } return LLSDParser::PARSE_FAILURE; } @@ -549,7 +549,7 @@ void LLSDXMLParser::Impl::parsePart(const char* buf, int len) XML_Status status = XML_Parse(mParser, buf, len, false); if (status == XML_STATUS_ERROR) { - llinfos << "Unexpected XML parsing error at start" << llendl; + LL_INFOS() << "Unexpected XML parsing error at start" << LL_ENDL; } } } diff --git a/indra/llcommon/llsdutil.h b/indra/llcommon/llsdutil.h index 532d3f9341..d0b536c39a 100755 --- a/indra/llcommon/llsdutil.h +++ b/indra/llcommon/llsdutil.h @@ -29,7 +29,7 @@ #ifndef LL_LLSDUTIL_H #define LL_LLSDUTIL_H -class LLSD; +#include "llsd.h" // U32 LL_COMMON_API LLSD ll_sd_from_U32(const U32); diff --git a/indra/llcommon/llsecondlifeurls.cpp b/indra/llcommon/llsecondlifeurls.cpp deleted file mode 100755 index 9154e05e43..0000000000 --- a/indra/llcommon/llsecondlifeurls.cpp +++ /dev/null @@ -1,84 +0,0 @@ -/** - * @file llsecondlifeurls.cpp - * @brief Urls used in the product - * - * $LicenseInfo:firstyear=2005&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" -#include "llsecondlifeurls.h" -/* -const std::string CREATE_ACCOUNT_URL ( - "http://join.secondlife.com/"); - -const std::string MANAGE_ACCOUNT ( - "http://secondlife.com/account/"); // *TODO: NOT USED - -const std::string AUCTION_URL ( - "http://secondlife.com/auctions/auction-detail.php?id="); - -const std::string EVENTS_URL ( - "http://secondlife.com/events/"); -*/ -const std::string TIER_UP_URL ( - "http://secondlife.com/app/landtier"); // *TODO: Translate (simulator) - -const std::string DIRECTX_9_URL ( - "http://secondlife.com/support/"); // *TODO: NOT USED -/* -const std::string LAND_URL ( - "http://secondlife.com/app/landtier"); // *TODO: NOT USED - -const std::string UPGRADE_TO_PREMIUM_URL ( - "http://secondlife.com/app/upgrade/"); // *TODO: NOT USED - -const std::string AMD_AGP_URL ( - "http://secondlife.com/support/"); // *TODO: NOT USED - -const std::string VIA_URL ( - "http://secondlife.com/support/"); // *TODO: NOT USED - -const std::string SUPPORT_URL ( - "http://secondlife.com/support/"); - -const std::string INTEL_CHIPSET_URL ( - "http://secondlife.com/support/"); // *TODO: NOT USED - -const std::string SIS_CHIPSET_URL ( - "http://secondlife.com/support/"); // *TODO: NOT USED - -const std::string BLOGS_URL ( - "http://blog.secondlife.com/"); // *TODO: NOT USED - -const std::string BUY_CURRENCY_URL ( - "http://secondlife.com/app/currency/"); - -const std::string LSL_DOC_URL ( - "http://secondlife.com/app/lsldoc/"); // *TODO: NOT USED - -const std::string SL_KB_URL ( - "http://secondlife.com/knowledgebase/"); // *TODO: NOT USED - -const std::string RELEASE_NOTES_BASE_URL ( - "http://secondlife.com/app/releasenotes/"); -*/ - diff --git a/indra/llcommon/llsecondlifeurls.h b/indra/llcommon/llsecondlifeurls.h deleted file mode 100755 index 62f357ffed..0000000000 --- a/indra/llcommon/llsecondlifeurls.h +++ /dev/null @@ -1,76 +0,0 @@ -/** - * @file llsecondlifeurls.h - * @brief Global URLs to pages on our web site - * - * $LicenseInfo:firstyear=2004&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_LLSECONDLIFEURLS_H -#define LL_LLSECONDLIFEURLS_H -/* -// Account registration web page -LL_COMMON_API extern const std::string CREATE_ACCOUNT_URL; - -// Manage Account -LL_COMMON_API extern const std::string MANAGE_ACCOUNT; - -LL_COMMON_API extern const std::string AUCTION_URL; - -LL_COMMON_API extern const std::string EVENTS_URL; -*/ -// Tier up to a new land level. -LL_COMMON_API extern const std::string TIER_UP_URL; - - -// Tier up to a new land level. -LL_COMMON_API extern const std::string LAND_URL; - -// How to get DirectX 9 -LL_COMMON_API extern const std::string DIRECTX_9_URL; - -/* -// Upgrade from basic membership to premium membership -LL_COMMON_API extern const std::string UPGRADE_TO_PREMIUM_URL; - - -// Out of date VIA chipset -LL_COMMON_API extern const std::string VIA_URL; - -// Support URL -LL_COMMON_API extern const std::string SUPPORT_URL; - -// Linden Blogs page -LL_COMMON_API extern const std::string BLOGS_URL; - -// Currency page -LL_COMMON_API extern const std::string BUY_CURRENCY_URL; - -// LSL script wiki -LL_COMMON_API extern const std::string LSL_DOC_URL; - -// SL KnowledgeBase page -LL_COMMON_API extern const std::string SL_KB_URL; - -// Release Notes Redirect URL for Server and Viewer -LL_COMMON_API extern const std::string RELEASE_NOTES_BASE_URL; -*/ -#endif diff --git a/indra/llcommon/llsingleton.h b/indra/llcommon/llsingleton.h index 40002313f1..6e6291a165 100755 --- a/indra/llcommon/llsingleton.h +++ b/indra/llcommon/llsingleton.h @@ -67,6 +67,11 @@ private: INITIALIZED, DELETED } EInitState; + + static DERIVED_TYPE* constructSingleton() + { + return new DERIVED_TYPE(); + } // stores pointer to singleton instance struct SingletonLifetimeManager @@ -79,7 +84,7 @@ private: static void construct() { sData.mInitState = CONSTRUCTING; - sData.mInstance = new DERIVED_TYPE(); + sData.mInstance = constructSingleton(); sData.mInitState = INITIALIZING; } @@ -138,18 +143,21 @@ public: llassert(false); return NULL; case CONSTRUCTING: - llerrs << "Tried to access singleton " << typeid(DERIVED_TYPE).name() << " from singleton constructor!" << llendl; + LL_ERRS() << "Tried to access singleton " << typeid(DERIVED_TYPE).name() << " from singleton constructor!" << LL_ENDL; return NULL; case INITIALIZING: // go ahead and flag ourselves as initialized so we can be reentrant during initialization sData.mInitState = INITIALIZED; + // initialize singleton after constructing it so that it can reference other singletons which in turn depend on it, + // thus breaking cyclic dependencies sData.mInstance->initSingleton(); return sData.mInstance; case INITIALIZED: return sData.mInstance; case DELETED: - llwarns << "Trying to access deleted singleton " << typeid(DERIVED_TYPE).name() << " creating new instance" << llendl; + LL_WARNS() << "Trying to access deleted singleton " << typeid(DERIVED_TYPE).name() << " creating new instance" << LL_ENDL; SingletonLifetimeManager::construct(); + // same as first time construction sData.mInitState = INITIALIZED; sData.mInstance->initSingleton(); return sData.mInstance; @@ -190,6 +198,8 @@ private: struct SingletonData { + // explicitly has a default constructor so that member variables are zero initialized in BSS + // and only changed by singleton logic, not constructor running during startup EInitState mInitState; DERIVED_TYPE* mInstance; }; diff --git a/indra/llcommon/llskiplist.h b/indra/llcommon/llskiplist.h deleted file mode 100755 index ed132381f9..0000000000 --- a/indra/llcommon/llskiplist.h +++ /dev/null @@ -1,517 +0,0 @@ -/** - * @file llskiplist.h - * @brief skip list implementation - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ -#ifndef LL_LLSKIPLIST_H -#define LL_LLSKIPLIST_H - -#include "llrand.h" -#include "llrand.h" - -// NOTA BENE: Insert first needs to be < NOT <= -// Binary depth must be >= 2 -template <class DATA_TYPE, S32 BINARY_DEPTH = 10> -class LLSkipList -{ -public: - typedef BOOL (*compare)(const DATA_TYPE& first, const DATA_TYPE& second); - typedef compare insert_func; - typedef compare equals_func; - - void init(); - - // basic constructor - LLSkipList(); - - // basic constructor including sorter - LLSkipList(insert_func insert_first, equals_func equals); - ~LLSkipList(); - - inline void setInsertFirst(insert_func insert_first); - inline void setEquals(equals_func equals); - - inline BOOL addData(const DATA_TYPE& data); - inline BOOL checkData(const DATA_TYPE& data); - - // returns number of items in the list - inline S32 getLength() const; // NOT a constant time operation, traverses entire list! - - inline BOOL moveData(const DATA_TYPE& data, LLSkipList *newlist); - - inline BOOL removeData(const DATA_TYPE& data); - - // remove all nodes from the list but do not delete data - inline void removeAllNodes(); - - // place mCurrentp on first node - inline void resetList(); - - // return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp - inline DATA_TYPE getCurrentData(); - - // same as getCurrentData() but a more intuitive name for the operation - inline DATA_TYPE getNextData(); - - // remove the Node at mCurentOperatingp - // leave mCurrentp and mCurentOperatingp on the next entry - inline void removeCurrentData(); - - // reset the list and return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp - inline DATA_TYPE getFirstData(); - - class LLSkipNode - { - public: - LLSkipNode() - : mData(0) - { - S32 i; - for (i = 0; i < BINARY_DEPTH; i++) - { - mForward[i] = NULL; - } - } - - LLSkipNode(DATA_TYPE data) - : mData(data) - { - S32 i; - for (i = 0; i < BINARY_DEPTH; i++) - { - mForward[i] = NULL; - } - } - - ~LLSkipNode() - { - } - - DATA_TYPE mData; - LLSkipNode *mForward[BINARY_DEPTH]; - - private: - // Disallow copying of LLSkipNodes by not implementing these methods. - LLSkipNode(const LLSkipNode &); - LLSkipNode &operator=(const LLSkipNode &); - }; - - static BOOL defaultEquals(const DATA_TYPE& first, const DATA_TYPE& second) - { - return first == second; - } - -private: - LLSkipNode mHead; - LLSkipNode *mUpdate[BINARY_DEPTH]; - LLSkipNode *mCurrentp; - LLSkipNode *mCurrentOperatingp; - S32 mLevel; - insert_func mInsertFirst; - equals_func mEquals; - -private: - // Disallow copying of LLSkipNodes by not implementing these methods. - LLSkipList(const LLSkipList &); - LLSkipList &operator=(const LLSkipList &); -}; - - -/////////////////////// -// -// Implementation -// - - -// Binary depth must be >= 2 -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline void LLSkipList<DATA_TYPE, BINARY_DEPTH>::init() -{ - S32 i; - for (i = 0; i < BINARY_DEPTH; i++) - { - mHead.mForward[i] = NULL; - mUpdate[i] = NULL; - } - mLevel = 1; - mCurrentp = *(mHead.mForward); - mCurrentOperatingp = *(mHead.mForward); -} - - -// basic constructor -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline LLSkipList<DATA_TYPE, BINARY_DEPTH>::LLSkipList() -: mInsertFirst(NULL), - mEquals(defaultEquals) -{ - init(); -} - -// basic constructor including sorter -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline LLSkipList<DATA_TYPE, BINARY_DEPTH>::LLSkipList(insert_func insert, - equals_func equals) -: mInsertFirst(insert), - mEquals(equals) -{ - init(); -} - -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline LLSkipList<DATA_TYPE, BINARY_DEPTH>::~LLSkipList() -{ - removeAllNodes(); -} - -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline void LLSkipList<DATA_TYPE, BINARY_DEPTH>::setInsertFirst(insert_func insert_first) -{ - mInsertFirst = insert_first; -} - -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline void LLSkipList<DATA_TYPE, BINARY_DEPTH>::setEquals(equals_func equals) -{ - mEquals = equals; -} - -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline BOOL LLSkipList<DATA_TYPE, BINARY_DEPTH>::addData(const DATA_TYPE& data) -{ - S32 level; - LLSkipNode *current = &mHead; - LLSkipNode *temp; - // find the pointer one in front of the one we want - if (mInsertFirst) - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(mInsertFirst(temp->mData, data))) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - else - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(temp->mData < data)) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - // we're now just in front of where we want to be . . . take one step forward - current = *current->mForward; - - // now add the new node - S32 newlevel; - for (newlevel = 1; newlevel <= mLevel && newlevel < BINARY_DEPTH; newlevel++) - { - if (ll_frand() < 0.5f) - break; - } - - LLSkipNode *snode = new LLSkipNode(data); - - if (newlevel > mLevel) - { - mHead.mForward[mLevel] = NULL; - mUpdate[mLevel] = &mHead; - mLevel = newlevel; - } - - for (level = 0; level < newlevel; level++) - { - snode->mForward[level] = mUpdate[level]->mForward[level]; - mUpdate[level]->mForward[level] = snode; - } - return TRUE; -} - -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline BOOL LLSkipList<DATA_TYPE, BINARY_DEPTH>::checkData(const DATA_TYPE& data) -{ - S32 level; - LLSkipNode *current = &mHead; - LLSkipNode *temp; - // find the pointer one in front of the one we want - if (mInsertFirst) - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(mInsertFirst(temp->mData, data))) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - else - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(temp->mData < data)) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - // we're now just in front of where we want to be . . . take one step forward - current = *current->mForward; - - - if (current) - { - return mEquals(current->mData, data); - } - - return FALSE; -} - -// returns number of items in the list -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline S32 LLSkipList<DATA_TYPE, BINARY_DEPTH>::getLength() const -{ - U32 length = 0; - for (LLSkipNode* temp = *(mHead.mForward); temp != NULL; temp = temp->mForward[0]) - { - length++; - } - return length; -} - - -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline BOOL LLSkipList<DATA_TYPE, BINARY_DEPTH>::moveData(const DATA_TYPE& data, LLSkipList *newlist) -{ - BOOL removed = removeData(data); - BOOL added = newlist->addData(data); - return removed && added; -} - - -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline BOOL LLSkipList<DATA_TYPE, BINARY_DEPTH>::removeData(const DATA_TYPE& data) -{ - S32 level; - LLSkipNode *current = &mHead; - LLSkipNode *temp; - // find the pointer one in front of the one we want - if (mInsertFirst) - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(mInsertFirst(temp->mData, data))) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - else - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(temp->mData < data)) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - // we're now just in front of where we want to be . . . take one step forward - current = *current->mForward; - - - if (!current) - { - // empty list or beyond the end! - return FALSE; - } - - // is this the one we want? - if (!mEquals(current->mData, data)) - { - // nope! - return FALSE; - } - else - { - // do we need to fix current or currentop? - if (current == mCurrentp) - { - mCurrentp = current->mForward[0]; - } - - if (current == mCurrentOperatingp) - { - mCurrentOperatingp = current->mForward[0]; - } - // yes it is! change pointers as required - for (level = 0; level < mLevel; level++) - { - if (mUpdate[level]->mForward[level] != current) - { - // cool, we've fixed all the pointers! - break; - } - mUpdate[level]->mForward[level] = current->mForward[level]; - } - - // clean up cuurent - delete current; - - // clean up mHead - while ( (mLevel > 1) - &&(!mHead.mForward[mLevel - 1])) - { - mLevel--; - } - } - return TRUE; -} - -// remove all nodes from the list but do not delete data -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline void LLSkipList<DATA_TYPE, BINARY_DEPTH>::removeAllNodes() -{ - LLSkipNode *temp; - // reset mCurrentp - mCurrentp = *(mHead.mForward); - - while (mCurrentp) - { - temp = mCurrentp->mForward[0]; - delete mCurrentp; - mCurrentp = temp; - } - - S32 i; - for (i = 0; i < BINARY_DEPTH; i++) - { - mHead.mForward[i] = NULL; - mUpdate[i] = NULL; - } - - mCurrentp = *(mHead.mForward); - mCurrentOperatingp = *(mHead.mForward); -} - -// place mCurrentp on first node -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline void LLSkipList<DATA_TYPE, BINARY_DEPTH>::resetList() -{ - mCurrentp = *(mHead.mForward); - mCurrentOperatingp = *(mHead.mForward); -} - -// return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline DATA_TYPE LLSkipList<DATA_TYPE, BINARY_DEPTH>::getCurrentData() -{ - if (mCurrentp) - { - mCurrentOperatingp = mCurrentp; - mCurrentp = mCurrentp->mForward[0]; - return mCurrentOperatingp->mData; - } - else - { - //return NULL; // causes compile warning - return (DATA_TYPE)0; // equivalent, but no warning - } -} - -// same as getCurrentData() but a more intuitive name for the operation -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline DATA_TYPE LLSkipList<DATA_TYPE, BINARY_DEPTH>::getNextData() -{ - if (mCurrentp) - { - mCurrentOperatingp = mCurrentp; - mCurrentp = mCurrentp->mForward[0]; - return mCurrentOperatingp->mData; - } - else - { - //return NULL; // causes compile warning - return (DATA_TYPE)0; // equivalent, but no warning - } -} - -// remove the Node at mCurentOperatingp -// leave mCurrentp and mCurentOperatingp on the next entry -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline void LLSkipList<DATA_TYPE, BINARY_DEPTH>::removeCurrentData() -{ - if (mCurrentOperatingp) - { - removeData(mCurrentOperatingp->mData); - } -} - -// reset the list and return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp -template <class DATA_TYPE, S32 BINARY_DEPTH> -inline DATA_TYPE LLSkipList<DATA_TYPE, BINARY_DEPTH>::getFirstData() -{ - mCurrentp = *(mHead.mForward); - mCurrentOperatingp = *(mHead.mForward); - if (mCurrentp) - { - mCurrentOperatingp = mCurrentp; - mCurrentp = mCurrentp->mForward[0]; - return mCurrentOperatingp->mData; - } - else - { - //return NULL; // causes compile warning - return (DATA_TYPE)0; // equivalent, but no warning - } -} - - -#endif diff --git a/indra/llcommon/llskipmap.h b/indra/llcommon/llskipmap.h deleted file mode 100755 index 49ff2928d1..0000000000 --- a/indra/llcommon/llskipmap.h +++ /dev/null @@ -1,1022 +0,0 @@ -/** - * @file llskipmap.h - * @brief Associative container based on the skiplist algorithm. - * - * $LicenseInfo:firstyear=2003&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_LLSKIPMAP_H -#define LL_LLSKIPMAP_H - -#include "llerror.h" - -template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH = 8> -class LLSkipMap -{ -public: - // basic constructor - LLSkipMap(); - - // basic constructor including sorter - LLSkipMap(BOOL (*insert_first)(const INDEX_TYPE &first, const INDEX_TYPE &second), - BOOL (*equals)(const INDEX_TYPE &first, const INDEX_TYPE &second)); - - ~LLSkipMap(); - - void setInsertFirst(BOOL (*insert_first)(const INDEX_TYPE &first, const INDEX_TYPE &second)); - void setEquals(BOOL (*equals)(const INDEX_TYPE &first, const INDEX_TYPE &second)); - - DATA_TYPE &addData(const INDEX_TYPE &index, DATA_TYPE datap); - DATA_TYPE &addData(const INDEX_TYPE &index); - DATA_TYPE &getData(const INDEX_TYPE &index); - DATA_TYPE &operator[](const INDEX_TYPE &index); - - // If index present, returns data. - // If index not present, adds <index,NULL> and returns NULL. - DATA_TYPE &getData(const INDEX_TYPE &index, BOOL &b_new_entry); - - // Returns TRUE if data present in map. - BOOL checkData(const INDEX_TYPE &index); - - // Returns TRUE if key is present in map. This is useful if you - // are potentially storing NULL pointers in the map - BOOL checkKey(const INDEX_TYPE &index); - - // If there, returns the data. - // If not, returns NULL. - // Never adds entries to the map. - DATA_TYPE getIfThere(const INDEX_TYPE &index); - - INDEX_TYPE reverseLookup(const DATA_TYPE datap); - - // returns number of items in the list - S32 getLength(); // WARNING! getLength is O(n), not O(1)! - - BOOL removeData(const INDEX_TYPE &index); - - // remove all nodes from the list but do not delete data - void removeAllData(); - - // place mCurrentp on first node - void resetList(); - - // return the data currently pointed to - DATA_TYPE getCurrentDataWithoutIncrement(); - - // return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp - DATA_TYPE getCurrentData(); - - // same as getCurrentData() but a more intuitive name for the operation - DATA_TYPE getNextData(); - - INDEX_TYPE getNextKey(); - - // return the key currently pointed to - INDEX_TYPE getCurrentKeyWithoutIncrement(); - - // The internal iterator is at the end of the list. - BOOL notDone() const; - - // remove the Node at mCurentOperatingp - // leave mCurrentp and mCurentOperatingp on the next entry - void removeCurrentData(); - - void deleteCurrentData(); - - // reset the list and return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp - DATA_TYPE getFirstData(); - - INDEX_TYPE getFirstKey(); - - class LLSkipMapNode - { - public: - LLSkipMapNode() - { - S32 i; - for (i = 0; i < BINARY_DEPTH; i++) - { - mForward[i] = NULL; - } - - U8 *zero = (U8 *)&mIndex; - - for (i = 0; i < (S32)sizeof(INDEX_TYPE); i++) - { - *(zero + i) = 0; - } - - zero = (U8 *)&mData; - - for (i = 0; i < (S32)sizeof(DATA_TYPE); i++) - { - *(zero + i) = 0; - } - } - - LLSkipMapNode(const INDEX_TYPE &index) - : mIndex(index) - { - - S32 i; - for (i = 0; i < BINARY_DEPTH; i++) - { - mForward[i] = NULL; - } - - U8 *zero = (U8 *)&mData; - - for (i = 0; i < (S32)sizeof(DATA_TYPE); i++) - { - *(zero + i) = 0; - } - } - - LLSkipMapNode(const INDEX_TYPE &index, DATA_TYPE datap) - : mIndex(index) - { - - S32 i; - for (i = 0; i < BINARY_DEPTH; i++) - { - mForward[i] = NULL; - } - - mData = datap; - } - - ~LLSkipMapNode() - { - } - - - INDEX_TYPE mIndex; - DATA_TYPE mData; - LLSkipMapNode *mForward[BINARY_DEPTH]; - - private: - // Disallow copying of LLSkipMapNodes by not implementing these methods. - LLSkipMapNode(const LLSkipMapNode &); - LLSkipMapNode &operator=(const LLSkipMapNode &rhs); - }; - - static BOOL defaultEquals(const INDEX_TYPE &first, const INDEX_TYPE &second) - { - return first == second; - } - -private: - // don't generate implicit copy constructor or copy assignment - LLSkipMap(const LLSkipMap &); - LLSkipMap &operator=(const LLSkipMap &); - -private: - LLSkipMapNode mHead; - LLSkipMapNode *mUpdate[BINARY_DEPTH]; - LLSkipMapNode *mCurrentp; - LLSkipMapNode *mCurrentOperatingp; - S32 mLevel; - BOOL (*mInsertFirst)(const INDEX_TYPE &first, const INDEX_TYPE &second); - BOOL (*mEquals)(const INDEX_TYPE &first, const INDEX_TYPE &second); - S32 mNumberOfSteps; -}; - -////////////////////////////////////////////////// -// -// LLSkipMap implementation -// - -template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH> -inline LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::LLSkipMap() - : mInsertFirst(NULL), - mEquals(defaultEquals) -{ - // Skipmaps must have binary depth of at least 2 - cassert(BINARY_DEPTH >= 2); - - S32 i; - for (i = 0; i < BINARY_DEPTH; i++) - { - mUpdate[i] = NULL; - } - mLevel = 1; - mCurrentp = *(mHead.mForward); - mCurrentOperatingp = *(mHead.mForward); -} - -template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH> -inline LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::LLSkipMap(BOOL (*insert_first)(const INDEX_TYPE &first, const INDEX_TYPE &second), - BOOL (*equals)(const INDEX_TYPE &first, const INDEX_TYPE &second)) - : mInsertFirst(insert_first), - mEquals(equals) -{ - // Skipmaps must have binary depth of at least 2 - cassert(BINARY_DEPTH >= 2); - - mLevel = 1; - S32 i; - for (i = 0; i < BINARY_DEPTH; i++) - { - mHead.mForward[i] = NULL; - mUpdate[i] = NULL; - } - mCurrentp = *(mHead.mForward); - mCurrentOperatingp = *(mHead.mForward); -} - -template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH> -inline LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::~LLSkipMap() -{ - removeAllData(); -} - -template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH> -inline void LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::setInsertFirst(BOOL (*insert_first)(const INDEX_TYPE &first, const INDEX_TYPE &second)) -{ - mInsertFirst = insert_first; -} - -template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH> -inline void LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::setEquals(BOOL (*equals)(const INDEX_TYPE &first, const INDEX_TYPE &second)) -{ - mEquals = equals; -} - -template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH> -inline DATA_TYPE &LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::addData(const INDEX_TYPE &index, DATA_TYPE datap) -{ - S32 level; - LLSkipMapNode *current = &mHead; - LLSkipMapNode *temp; - - // find the pointer one in front of the one we want - if (mInsertFirst) - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(mInsertFirst(temp->mIndex, index))) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - else - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(temp->mIndex < index)) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - - // we're now just in front of where we want to be . . . take one step forward - current = *current->mForward; - - // replace the existing data if a node is already there - if ( (current) - &&(mEquals(current->mIndex, index))) - { - current->mData = datap; - return current->mData; - } - - // now add the new node - S32 newlevel; - for (newlevel = 1; newlevel <= mLevel && newlevel < BINARY_DEPTH; newlevel++) - { - if (rand() & 1) - { - break; - } - } - - LLSkipMapNode *snode = new LLSkipMapNode(index, datap); - - if (newlevel > mLevel) - { - mHead.mForward[mLevel] = NULL; - mUpdate[mLevel] = &mHead; - mLevel = newlevel; - } - - for (level = 0; level < newlevel; level++) - { - snode->mForward[level] = mUpdate[level]->mForward[level]; - mUpdate[level]->mForward[level] = snode; - } - return snode->mData; -} - -template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH> -inline DATA_TYPE &LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::addData(const INDEX_TYPE &index) -{ - S32 level; - LLSkipMapNode *current = &mHead; - LLSkipMapNode *temp; - - // find the pointer one in front of the one we want - if (mInsertFirst) - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(mInsertFirst(temp->mIndex, index))) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - else - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(temp->mIndex < index)) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - - // we're now just in front of where we want to be . . . take one step forward - current = *current->mForward; - - // now add the new node - S32 newlevel; - for (newlevel = 1; newlevel <= mLevel && newlevel < BINARY_DEPTH; newlevel++) - { - if (rand() & 1) - break; - } - - LLSkipMapNode *snode = new LLSkipMapNode(index); - - if (newlevel > mLevel) - { - mHead.mForward[mLevel] = NULL; - mUpdate[mLevel] = &mHead; - mLevel = newlevel; - } - - for (level = 0; level < newlevel; level++) - { - snode->mForward[level] = mUpdate[level]->mForward[level]; - mUpdate[level]->mForward[level] = snode; - } - return snode->mData; -} - -template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH> -inline DATA_TYPE &LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::getData(const INDEX_TYPE &index) -{ - S32 level; - LLSkipMapNode *current = &mHead; - LLSkipMapNode *temp; - - mNumberOfSteps = 0; - - // find the pointer one in front of the one we want - if (mInsertFirst) - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(mInsertFirst(temp->mIndex, index))) - { - current = temp; - temp = *(current->mForward + level); - mNumberOfSteps++; - } - *(mUpdate + level) = current; - } - } - else - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(temp->mIndex < index)) - { - current = temp; - temp = *(current->mForward + level); - mNumberOfSteps++; - } - *(mUpdate + level) = current; - } - } - - // we're now just in front of where we want to be . . . take one step forward - current = *current->mForward; - mNumberOfSteps++; - - if ( (current) - &&(mEquals(current->mIndex, index))) - { - - return current->mData; - } - - // now add the new node - S32 newlevel; - for (newlevel = 1; newlevel <= mLevel && newlevel < BINARY_DEPTH; newlevel++) - { - if (rand() & 1) - break; - } - - LLSkipMapNode *snode = new LLSkipMapNode(index); - - if (newlevel > mLevel) - { - mHead.mForward[mLevel] = NULL; - mUpdate[mLevel] = &mHead; - mLevel = newlevel; - } - - for (level = 0; level < newlevel; level++) - { - snode->mForward[level] = mUpdate[level]->mForward[level]; - mUpdate[level]->mForward[level] = snode; - } - - return snode->mData; -} - -template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH> -inline DATA_TYPE &LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::operator[](const INDEX_TYPE &index) -{ - - return getData(index); -} - -// If index present, returns data. -// If index not present, adds <index,NULL> and returns NULL. -template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH> -inline DATA_TYPE &LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::getData(const INDEX_TYPE &index, BOOL &b_new_entry) -{ - S32 level; - LLSkipMapNode *current = &mHead; - LLSkipMapNode *temp; - - mNumberOfSteps = 0; - - // find the pointer one in front of the one we want - if (mInsertFirst) - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(mInsertFirst(temp->mIndex, index))) - { - current = temp; - temp = *(current->mForward + level); - mNumberOfSteps++; - } - *(mUpdate + level) = current; - } - } - else - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(temp->mIndex < index)) - { - current = temp; - temp = *(current->mForward + level); - mNumberOfSteps++; - } - *(mUpdate + level) = current; - } - } - - // we're now just in front of where we want to be . . . take one step forward - mNumberOfSteps++; - current = *current->mForward; - - if ( (current) - &&(mEquals(current->mIndex, index))) - { - - return current->mData; - } - b_new_entry = TRUE; - addData(index); - - return current->mData; -} - -// Returns TRUE if data present in map. -template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH> -inline BOOL LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::checkData(const INDEX_TYPE &index) -{ - S32 level; - LLSkipMapNode *current = &mHead; - LLSkipMapNode *temp; - - // find the pointer one in front of the one we want - if (mInsertFirst) - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(mInsertFirst(temp->mIndex, index))) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - else - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(temp->mIndex < index)) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - - // we're now just in front of where we want to be . . . take one step forward - current = *current->mForward; - - if (current) - { - // Gets rid of some compiler ambiguity for the LLPointer<> templated class. - if (current->mData) - { - return mEquals(current->mIndex, index); - } - } - - return FALSE; -} - -// Returns TRUE if key is present in map. This is useful if you -// are potentially storing NULL pointers in the map -template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH> -inline BOOL LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::checkKey(const INDEX_TYPE &index) -{ - S32 level; - LLSkipMapNode *current = &mHead; - LLSkipMapNode *temp; - - // find the pointer one in front of the one we want - if (mInsertFirst) - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(mInsertFirst(temp->mIndex, index))) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - else - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(temp->mIndex < index)) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - - // we're now just in front of where we want to be . . . take one step forward - current = *current->mForward; - - if (current) - { - return mEquals(current->mIndex, index); - } - - return FALSE; -} - -// If there, returns the data. -// If not, returns NULL. -// Never adds entries to the map. -template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH> -inline DATA_TYPE LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::getIfThere(const INDEX_TYPE &index) -{ - S32 level; - LLSkipMapNode *current = &mHead; - LLSkipMapNode *temp; - - mNumberOfSteps = 0; - - // find the pointer one in front of the one we want - if (mInsertFirst) - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(mInsertFirst(temp->mIndex, index))) - { - current = temp; - temp = *(current->mForward + level); - mNumberOfSteps++; - } - *(mUpdate + level) = current; - } - } - else - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(temp->mIndex < index)) - { - current = temp; - temp = *(current->mForward + level); - mNumberOfSteps++; - } - *(mUpdate + level) = current; - } - } - - // we're now just in front of where we want to be . . . take one step forward - mNumberOfSteps++; - current = *current->mForward; - - if (current) - { - if (mEquals(current->mIndex, index)) - { - return current->mData; - } - } - - // Avoid Linux compiler warning on returning NULL. - return DATA_TYPE(); -} - -template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH> -inline INDEX_TYPE LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::reverseLookup(const DATA_TYPE datap) -{ - LLSkipMapNode *current = &mHead; - - while (current) - { - if (datap == current->mData) - { - - return current->mIndex; - } - current = *current->mForward; - } - - // not found! return NULL - return INDEX_TYPE(); -} - -// returns number of items in the list -template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH> -inline S32 LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::getLength() -{ - U32 length = 0; - for (LLSkipMapNode* temp = *(mHead.mForward); temp != NULL; temp = temp->mForward[0]) - { - length++; - } - - return length; -} - -template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH> -inline BOOL LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::removeData(const INDEX_TYPE &index) -{ - S32 level; - LLSkipMapNode *current = &mHead; - LLSkipMapNode *temp; - - // find the pointer one in front of the one we want - if (mInsertFirst) - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(mInsertFirst(temp->mIndex, index))) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - else - { - for (level = mLevel - 1; level >= 0; level--) - { - temp = *(current->mForward + level); - while ( (temp) - &&(temp->mIndex < index)) - { - current = temp; - temp = *(current->mForward + level); - } - *(mUpdate + level) = current; - } - } - - // we're now just in front of where we want to be . . . take one step forward - current = *current->mForward; - - if (!current) - { - // empty list or beyond the end! - - return FALSE; - } - - // is this the one we want? - if (!mEquals(current->mIndex, index)) - { - // nope! - - return FALSE; - } - else - { - // do we need to fix current or currentop? - if (current == mCurrentp) - { - mCurrentp = *current->mForward; - } - - if (current == mCurrentOperatingp) - { - mCurrentOperatingp = *current->mForward; - } - // yes it is! change pointers as required - for (level = 0; level < mLevel; level++) - { - if (*((*(mUpdate + level))->mForward + level) != current) - { - // cool, we've fixed all the pointers! - break; - } - *((*(mUpdate + level))->mForward + level) = *(current->mForward + level); - } - - delete current; - - // clean up mHead - while ( (mLevel > 1) - &&(!*(mHead.mForward + mLevel - 1))) - { - mLevel--; - } - } - - return TRUE; -} - - -// remove all nodes from the list but do not delete data -template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH> -void LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::removeAllData() -{ - LLSkipMapNode *temp; - // reset mCurrentp - mCurrentp = *(mHead.mForward); - - while (mCurrentp) - { - temp = mCurrentp->mForward[0]; - delete mCurrentp; - mCurrentp = temp; - } - - S32 i; - for (i = 0; i < BINARY_DEPTH; i++) - { - mHead.mForward[i] = NULL; - mUpdate[i] = NULL; - } - - mCurrentp = *(mHead.mForward); - mCurrentOperatingp = *(mHead.mForward); -} - - -// place mCurrentp on first node -template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH> -inline void LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::resetList() -{ - mCurrentp = *(mHead.mForward); - mCurrentOperatingp = *(mHead.mForward); -} - - -// return the data currently pointed to -template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH> -inline DATA_TYPE LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::getCurrentDataWithoutIncrement() -{ - if (mCurrentOperatingp) - { - return mCurrentOperatingp->mData; - } - else - { - return DATA_TYPE(); - } -} - -// return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp -template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH> -inline DATA_TYPE LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::getCurrentData() -{ - if (mCurrentp) - { - mCurrentOperatingp = mCurrentp; - mCurrentp = mCurrentp->mForward[0]; - return mCurrentOperatingp->mData; - } - else - { - // Basic types, like int, have default constructors that initialize - // them to zero. g++ 2.95 supports this. "int()" is zero. - // This also is nice for LLUUID() - return DATA_TYPE(); - } -} - -// same as getCurrentData() but a more intuitive name for the operation -template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH> -inline DATA_TYPE LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::getNextData() -{ - if (mCurrentp) - { - mCurrentOperatingp = mCurrentp; - mCurrentp = mCurrentp->mForward[0]; - return mCurrentOperatingp->mData; - } - else - { - // Basic types, like int, have default constructors that initialize - // them to zero. g++ 2.95 supports this. "int()" is zero. - // This also is nice for LLUUID() - return DATA_TYPE(); - } -} - -template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH> -inline INDEX_TYPE LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::getNextKey() -{ - if (mCurrentp) - { - mCurrentOperatingp = mCurrentp; - mCurrentp = mCurrentp->mForward[0]; - return mCurrentOperatingp->mIndex; - } - else - { - return mHead.mIndex; - } -} - -// return the key currently pointed to -template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH> -inline INDEX_TYPE LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::getCurrentKeyWithoutIncrement() -{ - if (mCurrentOperatingp) - { - return mCurrentOperatingp->mIndex; - } - else - { - // See comment for getNextData() - return INDEX_TYPE(); - } -} - -template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH> -inline BOOL LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::notDone() const -{ - if (mCurrentOperatingp) - { - return TRUE; - } - else - { - return FALSE; - } -} - - -// remove the Node at mCurentOperatingp -// leave mCurrentp and mCurentOperatingp on the next entry -template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH> -inline void LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::removeCurrentData() -{ - if (mCurrentOperatingp) - { - removeData(mCurrentOperatingp->mIndex); - } -} - -template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH> -inline void LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::deleteCurrentData() -{ - if (mCurrentOperatingp) - { - deleteData(mCurrentOperatingp->mIndex); - } -} - -// reset the list and return the data currently pointed to, set mCurentOperatingp to that node and bump mCurrentp -template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH> -inline DATA_TYPE LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::getFirstData() -{ - mCurrentp = *(mHead.mForward); - mCurrentOperatingp = *(mHead.mForward); - if (mCurrentp) - { - mCurrentOperatingp = mCurrentp; - mCurrentp = mCurrentp->mForward[0]; - return mCurrentOperatingp->mData; - } - else - { - // See comment for getNextData() - return DATA_TYPE(); - } -} - -template <class INDEX_TYPE, class DATA_TYPE, S32 BINARY_DEPTH> -inline INDEX_TYPE LLSkipMap<INDEX_TYPE, DATA_TYPE, BINARY_DEPTH>::getFirstKey() -{ - mCurrentp = *(mHead.mForward); - mCurrentOperatingp = *(mHead.mForward); - if (mCurrentp) - { - mCurrentOperatingp = mCurrentp; - mCurrentp = mCurrentp->mForward[0]; - return mCurrentOperatingp->mIndex; - } - else - { - return mHead.mIndex; - } -} - -#endif diff --git a/indra/llcommon/llsortedvector.h b/indra/llcommon/llsortedvector.h deleted file mode 100755 index 391b82ee44..0000000000 --- a/indra/llcommon/llsortedvector.h +++ /dev/null @@ -1,152 +0,0 @@ -/** - * @file llsortedvector.h - * @author Nat Goodspeed - * @date 2012-04-08 - * @brief LLSortedVector class wraps a vector that we maintain in sorted - * order so we can perform binary-search lookups. - * - * $LicenseInfo:firstyear=2012&license=viewerlgpl$ - * Copyright (c) 2012, Linden Research, Inc. - * $/LicenseInfo$ - */ - -#if ! defined(LL_LLSORTEDVECTOR_H) -#define LL_LLSORTEDVECTOR_H - -#include <vector> -#include <algorithm> - -/** - * LLSortedVector contains a std::vector<std::pair> that we keep sorted on the - * first of the pair. This makes insertion somewhat more expensive than simple - * std::vector::push_back(), but allows us to use binary search for lookups. - * It's intended for small aggregates where lookup is far more performance- - * critical than insertion; in such cases a binary search on a small, sorted - * std::vector can be more performant than a std::map lookup. - */ -template <typename KEY, typename VALUE> -class LLSortedVector -{ -public: - typedef LLSortedVector<KEY, VALUE> self; - typedef KEY key_type; - typedef VALUE mapped_type; - typedef std::pair<key_type, mapped_type> value_type; - typedef std::vector<value_type> PairVector; - typedef typename PairVector::iterator iterator; - typedef typename PairVector::const_iterator const_iterator; - - /// Empty - LLSortedVector() {} - - /// Fixed initial size - LLSortedVector(std::size_t size): - mVector(size) - {} - - /// Bulk load - template <typename ITER> - LLSortedVector(ITER begin, ITER end): - mVector(begin, end) - { - // Allow caller to dump in a bunch of (pairs convertible to) - // value_type if desired, but make sure we sort afterwards. - std::sort(mVector.begin(), mVector.end()); - } - - /// insert(key, value) - std::pair<iterator, bool> insert(const key_type& key, const mapped_type& value) - { - return insert(value_type(key, value)); - } - - /// insert(value_type) - std::pair<iterator, bool> insert(const value_type& pair) - { - typedef std::pair<iterator, bool> iterbool; - iterator found = std::lower_bound(mVector.begin(), mVector.end(), pair, - less<value_type>()); - // have to check for end() before it's even valid to dereference - if (found == mVector.end()) - { - std::size_t index(mVector.size()); - mVector.push_back(pair); - // don't forget that push_back() invalidates 'found' - return iterbool(mVector.begin() + index, true); - } - if (found->first == pair.first) - { - return iterbool(found, false); - } - // remember that insert() invalidates 'found' -- save index - std::size_t index(found - mVector.begin()); - mVector.insert(found, pair); - // okay, convert from index back to iterator - return iterbool(mVector.begin() + index, true); - } - - iterator begin() { return mVector.begin(); } - iterator end() { return mVector.end(); } - const_iterator begin() const { return mVector.begin(); } - const_iterator end() const { return mVector.end(); } - - bool empty() const { return mVector.empty(); } - std::size_t size() const { return mVector.size(); } - - /// find - iterator find(const key_type& key) - { - iterator found = std::lower_bound(mVector.begin(), mVector.end(), - value_type(key, mapped_type()), - less<value_type>()); - if (found == mVector.end() || found->first != key) - return mVector.end(); - return found; - } - - const_iterator find(const key_type& key) const - { - return const_cast<self*>(this)->find(key); - } - -private: - // Define our own 'less' comparator so we can specialize without messing - // with std::less. - template <typename T> - struct less: public std::less<T> {}; - - // Specialize 'less' for an LLSortedVector::value_type involving - // std::type_info*. This is one of LLSortedVector's foremost use cases. We - // specialize 'less' rather than just defining a specific comparator - // because LLSortedVector should be usable for other key_types as well. - template <typename T> - struct less< std::pair<std::type_info*, T> >: - public std::binary_function<std::pair<std::type_info*, T>, - std::pair<std::type_info*, T>, - bool> - { - bool operator()(const std::pair<std::type_info*, T>& lhs, - const std::pair<std::type_info*, T>& rhs) const - { - return lhs.first->before(*rhs.first); - } - }; - - // Same as above, but with const std::type_info*. - template <typename T> - struct less< std::pair<const std::type_info*, T> >: - public std::binary_function<std::pair<const std::type_info*, T>, - std::pair<const std::type_info*, T>, - bool> - { - bool operator()(const std::pair<const std::type_info*, T>& lhs, - const std::pair<const std::type_info*, T>& rhs) const - { - return lhs.first->before(*rhs.first); - } - }; - - PairVector mVector; -}; - -#endif /* ! defined(LL_LLSORTEDVECTOR_H) */ diff --git a/indra/llcommon/llstack.h b/indra/llcommon/llstack.h deleted file mode 100755 index 315de6ba2d..0000000000 --- a/indra/llcommon/llstack.h +++ /dev/null @@ -1,48 +0,0 @@ -/** - * @file llstack.h - * @brief LLStack template class - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_LLSTACK_H -#define LL_LLSTACK_H - -#include "linked_lists.h" - -template <class DATA_TYPE> class LLStack -{ -private: - LLLinkedList<DATA_TYPE> mStack; - -public: - LLStack() {} - ~LLStack() {} - - void push(DATA_TYPE *data) { mStack.addData(data); } - DATA_TYPE *pop() { DATA_TYPE *tempp = mStack.getFirstData(); mStack.removeCurrentData(); return tempp; } - void deleteAllData() { mStack.deleteAllData(); } - void removeAllNodes() { mStack.removeAllNodes(); } -}; - -#endif - diff --git a/indra/llcommon/llstacktrace.cpp b/indra/llcommon/llstacktrace.cpp index ccd7ef91c2..e0e9056380 100755 --- a/indra/llcommon/llstacktrace.cpp +++ b/indra/llcommon/llstacktrace.cpp @@ -32,7 +32,7 @@ #include <iostream> #include <sstream> -#include "windows.h" +#include "llwin32headerslean.h" #include "Dbghelp.h" typedef USHORT NTAPI RtlCaptureStackBackTrace_Function( diff --git a/indra/llcommon/llstat.cpp b/indra/llcommon/llstat.cpp deleted file mode 100755 index 3678c8e1c1..0000000000 --- a/indra/llcommon/llstat.cpp +++ /dev/null @@ -1,404 +0,0 @@ -/** - * @file llstat.cpp - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" - -#include "llstat.h" -#include "lllivefile.h" -#include "llerrorcontrol.h" -#include "llframetimer.h" -#include "timing.h" -#include "llsd.h" -#include "llsdserialize.h" -#include "llstl.h" -#include "u64.h" - - -// statics -//------------------------------------------------------------------------ -LLTimer LLStat::sTimer; -LLFrameTimer LLStat::sFrameTimer; - -void LLStat::reset() -{ - mNumValues = 0; - mLastValue = 0.f; - delete[] mBins; - mBins = new ValueEntry[mNumBins]; - mCurBin = mNumBins-1; - mNextBin = 0; -} - -LLStat::LLStat(std::string name, S32 num_bins, BOOL use_frame_timer) -: mUseFrameTimer(use_frame_timer), - mNumBins(num_bins), - mName(name), - mBins(NULL) -{ - llassert(mNumBins > 0); - mLastTime = 0.f; - - reset(); - - if (!mName.empty()) - { - stat_map_t::iterator iter = getStatList().find(mName); - if (iter != getStatList().end()) - llwarns << "LLStat with duplicate name: " << mName << llendl; - getStatList().insert(std::make_pair(mName, this)); - } -} - -LLStat::stat_map_t& LLStat::getStatList() -{ - static LLStat::stat_map_t stat_list; - return stat_list; -} - - -LLStat::~LLStat() -{ - delete[] mBins; - - if (!mName.empty()) - { - // handle multiple entries with the same name - stat_map_t::iterator iter = getStatList().find(mName); - while (iter != getStatList().end() && iter->second != this) - ++iter; - getStatList().erase(iter); - } -} - -void LLStat::start() -{ - if (mUseFrameTimer) - { - mBins[mNextBin].mBeginTime = sFrameTimer.getElapsedSeconds(); - } - else - { - mBins[mNextBin].mBeginTime = sTimer.getElapsedTimeF64(); - } -} - -void LLStat::addValue(const F32 value) -{ - if (mNumValues < mNumBins) - { - mNumValues++; - } - - // Increment the bin counters. - mCurBin++; - if (mCurBin >= mNumBins) - { - mCurBin = 0; - } - mNextBin++; - if (mNextBin >= mNumBins) - { - mNextBin = 0; - } - - mBins[mCurBin].mValue = value; - if (mUseFrameTimer) - { - mBins[mCurBin].mTime = sFrameTimer.getElapsedSeconds(); - } - else - { - mBins[mCurBin].mTime = sTimer.getElapsedTimeF64(); - } - mBins[mCurBin].mDT = (F32)(mBins[mCurBin].mTime - mBins[mCurBin].mBeginTime); - - //this value is used to prime the min/max calls - mLastTime = mBins[mCurBin].mTime; - mLastValue = value; - - // Set the begin time for the next stat segment. - mBins[mNextBin].mBeginTime = mBins[mCurBin].mTime; - mBins[mNextBin].mTime = mBins[mCurBin].mTime; - mBins[mNextBin].mDT = 0.f; -} - - -F32 LLStat::getMax() const -{ - S32 i; - F32 current_max = mLastValue; - if (mNumBins == 0) - { - current_max = 0.f; - } - else - { - for (i = 0; (i < mNumBins) && (i < mNumValues); i++) - { - // Skip the bin we're currently filling. - if (i == mNextBin) - { - continue; - } - if (mBins[i].mValue > current_max) - { - current_max = mBins[i].mValue; - } - } - } - return current_max; -} - -F32 LLStat::getMean() const -{ - S32 i; - F32 current_mean = 0.f; - S32 samples = 0; - for (i = 0; (i < mNumBins) && (i < mNumValues); i++) - { - // Skip the bin we're currently filling. - if (i == mNextBin) - { - continue; - } - current_mean += mBins[i].mValue; - samples++; - } - - // There will be a wrap error at 2^32. :) - if (samples != 0) - { - current_mean /= samples; - } - else - { - current_mean = 0.f; - } - return current_mean; -} - -F32 LLStat::getMin() const -{ - S32 i; - F32 current_min = mLastValue; - - if (mNumBins == 0) - { - current_min = 0.f; - } - else - { - for (i = 0; (i < mNumBins) && (i < mNumValues); i++) - { - // Skip the bin we're currently filling. - if (i == mNextBin) - { - continue; - } - if (mBins[i].mValue < current_min) - { - current_min = mBins[i].mValue; - } - } - } - return current_min; -} - -F32 LLStat::getPrev(S32 age) const -{ - S32 bin; - bin = mCurBin - age; - - while (bin < 0) - { - bin += mNumBins; - } - - if (bin == mNextBin) - { - // Bogus for bin we're currently working on. - return 0.f; - } - return mBins[bin].mValue; -} - -F32 LLStat::getPrevPerSec(S32 age) const -{ - S32 bin; - bin = mCurBin - age; - - while (bin < 0) - { - bin += mNumBins; - } - - if (bin == mNextBin) - { - // Bogus for bin we're currently working on. - return 0.f; - } - return mBins[bin].mValue / mBins[bin].mDT; -} - -F32 LLStat::getCurrent() const -{ - return mBins[mCurBin].mValue; -} - -F32 LLStat::getCurrentPerSec() const -{ - return mBins[mCurBin].mValue / mBins[mCurBin].mDT; -} - -F32 LLStat::getMeanPerSec() const -{ - S32 i; - F32 value = 0.f; - F32 dt = 0.f; - - for (i = 0; (i < mNumBins) && (i < mNumValues); i++) - { - // Skip the bin we're currently filling. - if (i == mNextBin) - { - continue; - } - value += mBins[i].mValue; - dt += mBins[i].mDT; - } - - if (dt > 0.f) - { - return value/dt; - } - else - { - return 0.f; - } -} - -F32 LLStat::getMeanDuration() const -{ - F32 dur = 0.0f; - S32 count = 0; - for (S32 i=0; (i < mNumBins) && (i < mNumValues); i++) - { - if (i == mNextBin) - { - continue; - } - dur += mBins[i].mDT; - count++; - } - - if (count > 0) - { - dur /= F32(count); - return dur; - } - else - { - return 0.f; - } -} - -F32 LLStat::getMaxPerSec() const -{ - F32 value; - - if (mNextBin != 0) - { - value = mBins[0].mValue/mBins[0].mDT; - } - else if (mNumValues > 0) - { - value = mBins[1].mValue/mBins[1].mDT; - } - else - { - value = 0.f; - } - - for (S32 i = 0; (i < mNumBins) && (i < mNumValues); i++) - { - // Skip the bin we're currently filling. - if (i == mNextBin) - { - continue; - } - value = llmax(value, mBins[i].mValue/mBins[i].mDT); - } - return value; -} - -F32 LLStat::getMinPerSec() const -{ - S32 i; - F32 value; - - if (mNextBin != 0) - { - value = mBins[0].mValue/mBins[0].mDT; - } - else if (mNumValues > 0) - { - value = mBins[1].mValue/mBins[0].mDT; - } - else - { - value = 0.f; - } - - for (i = 0; (i < mNumBins) && (i < mNumValues); i++) - { - // Skip the bin we're currently filling. - if (i == mNextBin) - { - continue; - } - value = llmin(value, mBins[i].mValue/mBins[i].mDT); - } - return value; -} - -U32 LLStat::getNumValues() const -{ - return mNumValues; -} - -S32 LLStat::getNumBins() const -{ - return mNumBins; -} - -S32 LLStat::getNextBin() const -{ - return mNextBin; -} - -F64 LLStat::getLastTime() const -{ - return mLastTime; -} diff --git a/indra/llcommon/llstat.h b/indra/llcommon/llstat.h deleted file mode 100755 index 38377a010b..0000000000 --- a/indra/llcommon/llstat.h +++ /dev/null @@ -1,116 +0,0 @@ -/** - * @file llstat.h - * @brief Runtime statistics accumulation. - * - * $LicenseInfo:firstyear=2001&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_LLSTAT_H -#define LL_LLSTAT_H - -#include <map> - -#include "lltimer.h" -#include "llframetimer.h" - -class LLSD; - -// ---------------------------------------------------------------------------- -class LL_COMMON_API LLStat -{ -private: - typedef std::multimap<std::string, LLStat*> stat_map_t; - - static stat_map_t& getStatList(); - -public: - LLStat(std::string name = std::string(), S32 num_bins = 32, BOOL use_frame_timer = FALSE); - ~LLStat(); - - void start(); // Start the timer for the current "frame", otherwise uses the time tracked from - // the last addValue - void reset(); - void addValue(const F32 value = 1.f); // Adds the current value being tracked, and tracks the DT. - void addValue(const S32 value) { addValue((F32)value); } - void addValue(const U32 value) { addValue((F32)value); } - - S32 getNextBin() const; - - F32 getPrev(S32 age) const; // Age is how many "addValues" previously - zero is current - F32 getPrevPerSec(S32 age) const; // Age is how many "addValues" previously - zero is current - F32 getCurrent() const; - F32 getCurrentPerSec() const; - - F32 getMin() const; - F32 getMinPerSec() const; - F32 getMean() const; - F32 getMeanPerSec() const; - F32 getMeanDuration() const; - F32 getMax() const; - F32 getMaxPerSec() const; - - U32 getNumValues() const; - S32 getNumBins() const; - - F64 getLastTime() const; -private: - BOOL mUseFrameTimer; - U32 mNumValues; - U32 mNumBins; - F32 mLastValue; - F64 mLastTime; - - struct ValueEntry - { - ValueEntry() - : mValue(0.f), - mBeginTime(0.0), - mTime(0.0), - mDT(0.f) - {} - F32 mValue; - F64 mBeginTime; - F64 mTime; - F32 mDT; - }; - ValueEntry* mBins; - S32 mCurBin; - S32 mNextBin; - - std::string mName; - - static LLTimer sTimer; - static LLFrameTimer sFrameTimer; - -public: - static LLStat* getStat(const std::string& name) - { - // return the first stat that matches 'name' - stat_map_t::iterator iter = getStatList().find(name); - if (iter != getStatList().end()) - return iter->second; - else - return NULL; - } -}; - -#endif // LL_STAT_ diff --git a/indra/llcommon/llstatenums.h b/indra/llcommon/llstatenums.h index 81c4085d16..6515a3e3cb 100755..100644 --- a/indra/llcommon/llstatenums.h +++ b/indra/llcommon/llstatenums.h @@ -26,50 +26,6 @@ #ifndef LL_LLSTATENUMS_H #define LL_LLSTATENUMS_H -enum -{ - LL_SIM_STAT_TIME_DILATION = 0, - LL_SIM_STAT_FPS = 1, - LL_SIM_STAT_PHYSFPS = 2, - LL_SIM_STAT_AGENTUPS = 3, - LL_SIM_STAT_FRAMEMS = 4, - LL_SIM_STAT_NETMS = 5, - LL_SIM_STAT_SIMOTHERMS = 6, - LL_SIM_STAT_SIMPHYSICSMS = 7, - LL_SIM_STAT_AGENTMS = 8, - LL_SIM_STAT_IMAGESMS = 9, - LL_SIM_STAT_SCRIPTMS = 10, - LL_SIM_STAT_NUMTASKS = 11, - LL_SIM_STAT_NUMTASKSACTIVE = 12, - LL_SIM_STAT_NUMAGENTMAIN = 13, - LL_SIM_STAT_NUMAGENTCHILD = 14, - LL_SIM_STAT_NUMSCRIPTSACTIVE = 15, - LL_SIM_STAT_LSLIPS = 16, - LL_SIM_STAT_INPPS = 17, - LL_SIM_STAT_OUTPPS = 18, - LL_SIM_STAT_PENDING_DOWNLOADS = 19, - LL_SIM_STAT_PENDING_UPLOADS = 20, - LL_SIM_STAT_VIRTUAL_SIZE_KB = 21, - LL_SIM_STAT_RESIDENT_SIZE_KB = 22, - LL_SIM_STAT_PENDING_LOCAL_UPLOADS = 23, - LL_SIM_STAT_TOTAL_UNACKED_BYTES = 24, - LL_SIM_STAT_PHYSICS_PINNED_TASKS = 25, - LL_SIM_STAT_PHYSICS_LOD_TASKS = 26, - LL_SIM_STAT_SIMPHYSICSSTEPMS = 27, - LL_SIM_STAT_SIMPHYSICSSHAPEMS = 28, - LL_SIM_STAT_SIMPHYSICSOTHERMS = 29, - LL_SIM_STAT_SIMPHYSICSMEMORY = 30, - LL_SIM_STAT_SCRIPT_EPS = 31, - LL_SIM_STAT_SIMSPARETIME = 32, - LL_SIM_STAT_SIMSLEEPTIME = 33, - LL_SIM_STAT_IOPUMPTIME = 34, - LL_SIM_STAT_PCTSCRIPTSRUN = 35, - LL_SIM_STAT_REGION_IDLE = 36, // dataserver only - LL_SIM_STAT_REGION_IDLE_POSSIBLE = 37, // dataserver only - LL_SIM_STAT_SIMAISTEPTIMEMS = 38, - LL_SIM_STAT_SKIPPEDAISILSTEPS_PS = 39, - LL_SIM_STAT_PCTSTEPPEDCHARACTERS = 40 -}; #endif diff --git a/indra/llcommon/llstl.h b/indra/llcommon/llstl.h index 0a39288f5a..02f10fa2ba 100755 --- a/indra/llcommon/llstl.h +++ b/indra/llcommon/llstl.h @@ -31,8 +31,8 @@ #include <algorithm> #include <map> #include <vector> +#include <list> #include <set> -#include <deque> #include <typeinfo> // Use to compare the first element only of a pair @@ -125,7 +125,7 @@ struct DeletePairedPointerArray // compiler, the second unary_function template parameter can be set // to void. // -// Here's a snippit showing how you use this object: +// Here's a snippet showing how you use this object: // // typedef std::map<int, widget*> map_type; // map_type widget_map; @@ -170,6 +170,49 @@ struct CopyNewPointer } }; +template<typename T, typename ALLOC> +void delete_and_clear(std::list<T*, ALLOC>& list) +{ + std::for_each(list.begin(), list.end(), DeletePointer()); + list.clear(); +} + +template<typename T, typename ALLOC> +void delete_and_clear(std::vector<T*, ALLOC>& vector) +{ + std::for_each(vector.begin(), vector.end(), DeletePointer()); + vector.clear(); +} + +template<typename T, typename COMPARE, typename ALLOC> +void delete_and_clear(std::set<T*, COMPARE, ALLOC>& set) +{ + std::for_each(set.begin(), set.end(), DeletePointer()); + set.clear(); +} + +template<typename K, typename V, typename COMPARE, typename ALLOC> +void delete_and_clear(std::map<K, V*, COMPARE, ALLOC>& map) +{ + std::for_each(map.begin(), map.end(), DeletePairedPointer()); + map.clear(); +} + +template<typename T> +void delete_and_clear(T*& ptr) +{ + delete ptr; + ptr = NULL; +} + + +template<typename T> +void delete_and_clear_array(T*& ptr) +{ + delete[] ptr; + ptr = NULL; +} + // Simple function to help with finding pointers in maps. // For example: // typedef map_t; @@ -229,7 +272,6 @@ inline T get_if_there(const std::map<K,T>& inmap, const K& key, T default_value) } }; -// Useful for replacing the removeObj() functionality of LLDynamicArray // Example: // for (std::vector<T>::iterator iter = mList.begin(); iter != mList.end(); ) // { @@ -238,8 +280,8 @@ inline T get_if_there(const std::map<K,T>& inmap, const K& key, T default_value) // else // ++iter; // } -template <typename T, typename Iter> -inline Iter vector_replace_with_last(std::vector<T>& invec, Iter iter) +template <typename T> +inline typename std::vector<T>::iterator vector_replace_with_last(std::vector<T>& invec, typename std::vector<T>::iterator iter) { typename std::vector<T>::iterator last = invec.end(); --last; if (iter == invec.end()) @@ -259,7 +301,6 @@ inline Iter vector_replace_with_last(std::vector<T>& invec, Iter iter) } }; -// Useful for replacing the removeObj() functionality of LLDynamicArray // Example: // vector_replace_with_last(mList, x); template <typename T> @@ -522,4 +563,151 @@ namespace std }; } // std + +/** + * Implementation for ll_template_cast() (q.v.). + * + * Default implementation: trying to cast two completely unrelated types + * returns 0. Typically you'd specify T and U as pointer types, but in fact T + * can be any type that can be initialized with 0. + */ +template <typename T, typename U> +struct ll_template_cast_impl +{ + T operator()(U) + { + return 0; + } +}; + +/** + * ll_template_cast<T>(some_value) is for use in a template function when + * some_value might be of arbitrary type, but you want to recognize type T + * specially. + * + * It's designed for use with pointer types. Example: + * @code + * struct SpecialClass + * { + * void someMethod(const std::string&) const; + * }; + * + * template <class REALCLASS> + * void somefunc(const REALCLASS& instance) + * { + * const SpecialClass* ptr = ll_template_cast<const SpecialClass*>(&instance); + * if (ptr) + * { + * ptr->someMethod("Call method only available on SpecialClass"); + * } + * } + * @endcode + * + * Why is this better than dynamic_cast<>? Because unless OtherClass is + * polymorphic, the following won't even compile (gcc 4.0.1): + * @code + * OtherClass other; + * SpecialClass* ptr = dynamic_cast<SpecialClass*>(&other); + * @endcode + * to say nothing of this: + * @code + * void function(int); + * SpecialClass* ptr = dynamic_cast<SpecialClass*>(&function); + * @endcode + * ll_template_cast handles these kinds of cases by returning 0. + */ +template <typename T, typename U> +T ll_template_cast(U value) +{ + return ll_template_cast_impl<T, U>()(value); +} + +/** + * Implementation for ll_template_cast() (q.v.). + * + * Implementation for identical types: return same value. + */ +template <typename T> +struct ll_template_cast_impl<T, T> +{ + T operator()(T value) + { + return value; + } +}; + +/** + * LL_TEMPLATE_CONVERTIBLE(dest, source) asserts that, for a value @c s of + * type @c source, <tt>ll_template_cast<dest>(s)</tt> will return @c s -- + * presuming that @c source can be converted to @c dest by the normal rules of + * C++. + * + * By default, <tt>ll_template_cast<dest>(s)</tt> will return 0 unless @c s's + * type is literally identical to @c dest. (This is because of the + * straightforward application of template specialization rules.) That can + * lead to surprising results, e.g.: + * + * @code + * Foo myFoo; + * const Foo* fooptr = ll_template_cast<const Foo*>(&myFoo); + * @endcode + * + * Here @c fooptr will be 0 because <tt>&myFoo</tt> is of type <tt>Foo*</tt> + * -- @em not <tt>const Foo*</tt>. (Declaring <tt>const Foo myFoo;</tt> would + * force the compiler to do the right thing.) + * + * More disappointingly: + * @code + * struct Base {}; + * struct Subclass: public Base {}; + * Subclass object; + * Base* ptr = ll_template_cast<Base*>(&object); + * @endcode + * + * Here @c ptr will be 0 because <tt>&object</tt> is of type + * <tt>Subclass*</tt> rather than <tt>Base*</tt>. We @em want this cast to + * succeed, but without our help ll_template_cast can't recognize it. + * + * The following would suffice: + * @code + * LL_TEMPLATE_CONVERTIBLE(Base*, Subclass*); + * ... + * Base* ptr = ll_template_cast<Base*>(&object); + * @endcode + * + * However, as noted earlier, this is easily fooled: + * @code + * const Base* ptr = ll_template_cast<const Base*>(&object); + * @endcode + * would still produce 0 because we haven't yet seen: + * @code + * LL_TEMPLATE_CONVERTIBLE(const Base*, Subclass*); + * @endcode + * + * @TODO + * This macro should use Boost type_traits facilities for stripping and + * re-adding @c const and @c volatile qualifiers so that invoking + * LL_TEMPLATE_CONVERTIBLE(dest, source) will automatically generate all + * permitted permutations. It's really not fair to the coder to require + * separate: + * @code + * LL_TEMPLATE_CONVERTIBLE(Base*, Subclass*); + * LL_TEMPLATE_CONVERTIBLE(const Base*, Subclass*); + * LL_TEMPLATE_CONVERTIBLE(const Base*, const Subclass*); + * @endcode + * + * (Naturally we omit <tt>LL_TEMPLATE_CONVERTIBLE(Base*, const Subclass*)</tt> + * because that's not permitted by normal C++ assignment anyway.) + */ +#define LL_TEMPLATE_CONVERTIBLE(DEST, SOURCE) \ +template <> \ +struct ll_template_cast_impl<DEST, SOURCE> \ +{ \ + DEST operator()(SOURCE wrapper) \ + { \ + return wrapper; \ + } \ +} + + #endif // LL_LLSTL_H diff --git a/indra/llcommon/llstring.cpp b/indra/llcommon/llstring.cpp index 22c8681983..76979f29f6 100755 --- a/indra/llcommon/llstring.cpp +++ b/indra/llcommon/llstring.cpp @@ -28,15 +28,15 @@ #include "llstring.h" #include "llerror.h" +#include "llfasttimer.h" +#include "llsd.h" #if LL_WINDOWS -#define WIN32_LEAN_AND_MEAN -#include <winsock2.h> -#include <windows.h> +#include "llwin32headerslean.h" #include <winnls.h> // for WideCharToMultiByte #endif -LLFastTimer::DeclareTimer FT_STRING_FORMAT("String Format"); +LLTrace::BlockTimerStatHandle FT_STRING_FORMAT("String Format"); std::string ll_safe_string(const char* in) @@ -110,7 +110,7 @@ bool _read_file_into_string(std::string& str, const std::string& filename) llifstream ifs(filename, llifstream::binary); if (!ifs.is_open()) { - llinfos << "Unable to open file " << filename << llendl; + LL_INFOS() << "Unable to open file " << filename << LL_ENDL; return false; } @@ -188,7 +188,7 @@ S32 wchar_to_utf8chars(llwchar in_char, char* outchars) } else { - llwarns << "Invalid Unicode character " << cur_char << "!" << llendl; + LL_WARNS() << "Invalid Unicode character " << cur_char << "!" << LL_ENDL; *outchars++ = LL_UNKNOWN_CHAR; } return outchars - base; @@ -1195,7 +1195,7 @@ bool LLStringUtil::formatDatetime(std::string& replacement, std::string token, template<> S32 LLStringUtil::format(std::string& s, const format_map_t& substitutions) { - LLFastTimer ft(FT_STRING_FORMAT); + LL_RECORD_BLOCK_TIME(FT_STRING_FORMAT); S32 res = 0; std::string output; @@ -1268,7 +1268,7 @@ S32 LLStringUtil::format(std::string& s, const format_map_t& substitutions) template<> S32 LLStringUtil::format(std::string& s, const LLSD& substitutions) { - LLFastTimer ft(FT_STRING_FORMAT); + LL_RECORD_BLOCK_TIME(FT_STRING_FORMAT); S32 res = 0; if (!substitutions.isMap()) diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h index f9702868c8..0177f48bf5 100755 --- a/indra/llcommon/llstring.h +++ b/indra/llcommon/llstring.h @@ -29,10 +29,12 @@ #include <string> #include <cstdio> -#include <locale> +//#include <locale> #include <iomanip> -#include "llsd.h" -#include "llfasttimer.h" +#include <algorithm> +#include <vector> +#include <map> +#include "llformat.h" #if LL_LINUX || LL_SOLARIS #include <wctype.h> @@ -49,6 +51,7 @@ #endif const char LL_UNKNOWN_CHAR = '?'; +class LLSD; #if LL_DARWIN || LL_LINUX || LL_SOLARIS // Template specialization of char_traits for U16s. Only necessary on Mac and Linux (exists on Windows already) @@ -518,10 +521,13 @@ 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); +#if LL_WINDOWS +inline std::string wstring_to_utf8str(const llutf16string &utf16str) { return utf16str_to_utf8str(utf16str);} +#endif + // Length of this UTF32 string in bytes when transformed to UTF8 LL_COMMON_API S32 wstring_utf8_length(const LLWString& wstr); diff --git a/indra/llcommon/llstringtable.cpp b/indra/llcommon/llstringtable.cpp index 7ad3805351..f288999964 100755 --- a/indra/llcommon/llstringtable.cpp +++ b/indra/llcommon/llstringtable.cpp @@ -317,7 +317,7 @@ void LLStringTable::removeString(const char *str) mUniqueEntries--; if (mUniqueEntries < 0) { - llerror("LLStringTable:removeString trying to remove too many strings!", 0); + LL_ERRS() << "LLStringTable:removeString trying to remove too many strings!" << LL_ENDL; } delete iter->second; mStringHash.erase(iter); @@ -343,7 +343,7 @@ void LLStringTable::removeString(const char *str) mUniqueEntries--; if (mUniqueEntries < 0) { - llerror("LLStringTable:removeString trying to remove too many strings!", 0); + LL_ERRS() << "LLStringTable:removeString trying to remove too many strings!" << LL_ENDL; } strlist->remove(entry); delete entry; diff --git a/indra/llcommon/llsys.cpp b/indra/llcommon/llsys.cpp index e63045659e..07fe259e47 100755 --- a/indra/llcommon/llsys.cpp +++ b/indra/llcommon/llsys.cpp @@ -42,6 +42,7 @@ #include "llprocessor.h" #include "llerrorcontrol.h" #include "llevents.h" +#include "llformat.h" #include "lltimer.h" #include "llsdserialize.h" #include "llsdutil.h" @@ -58,9 +59,7 @@ using namespace llsd; #if LL_WINDOWS -# define WIN32_LEAN_AND_MEAN -# include <winsock2.h> -# include <windows.h> +# include "llwin32headerslean.h" # include <psapi.h> // GetPerformanceInfo() et al. #elif LL_DARWIN # include <errno.h> @@ -645,7 +644,7 @@ S32 LLOSInfo::getMaxOpenFiles() } else { - llerrs << "LLOSInfo::getMaxOpenFiles: sysconf error for _SC_OPEN_MAX" << llendl; + LL_ERRS() << "LLOSInfo::getMaxOpenFiles: sysconf error for _SC_OPEN_MAX" << LL_ENDL; } } } @@ -704,12 +703,12 @@ U32 LLOSInfo::getProcessVirtualSizeKB() sprintf(proc_ps, "/proc/%d/psinfo", (int)getpid()); int proc_fd = -1; if((proc_fd = open(proc_ps, O_RDONLY)) == -1){ - llwarns << "unable to open " << proc_ps << llendl; + LL_WARNS() << "unable to open " << proc_ps << LL_ENDL; return 0; } psinfo_t proc_psinfo; if(read(proc_fd, &proc_psinfo, sizeof(psinfo_t)) != sizeof(psinfo_t)){ - llwarns << "Unable to read " << proc_ps << llendl; + LL_WARNS() << "Unable to read " << proc_ps << LL_ENDL; close(proc_fd); return 0; } @@ -750,12 +749,12 @@ U32 LLOSInfo::getProcessResidentSizeKB() sprintf(proc_ps, "/proc/%d/psinfo", (int)getpid()); int proc_fd = -1; if((proc_fd = open(proc_ps, O_RDONLY)) == -1){ - llwarns << "unable to open " << proc_ps << llendl; + LL_WARNS() << "unable to open " << proc_ps << LL_ENDL; return 0; } psinfo_t proc_psinfo; if(read(proc_fd, &proc_psinfo, sizeof(psinfo_t)) != sizeof(psinfo_t)){ - llwarns << "Unable to read " << proc_ps << llendl; + LL_WARNS() << "Unable to read " << proc_ps << LL_ENDL; close(proc_fd); return 0; } @@ -870,7 +869,7 @@ LLMemoryInfo::LLMemoryInfo() } #if LL_WINDOWS -static U32 LLMemoryAdjustKBResult(U32 inKB) +static U32Kilobytes LLMemoryAdjustKBResult(U32Kilobytes inKB) { // Moved this here from llfloaterabout.cpp @@ -881,16 +880,16 @@ static U32 LLMemoryAdjustKBResult(U32 inKB) // returned from the GetMemoryStatusEx function. Here we keep the // original adjustment from llfoaterabout.cpp until this can be // fixed somehow. - inKB += 1024; + inKB += U32Megabytes(1); return inKB; } #endif -U32 LLMemoryInfo::getPhysicalMemoryKB() const +U32Kilobytes LLMemoryInfo::getPhysicalMemoryKB() const { #if LL_WINDOWS - return LLMemoryAdjustKBResult(mStatsMap["Total Physical KB"].asInteger()); + return LLMemoryAdjustKBResult(U32Kilobytes(mStatsMap["Total Physical KB"].asInteger())); #elif LL_DARWIN // This might work on Linux as well. Someone check... @@ -900,17 +899,17 @@ U32 LLMemoryInfo::getPhysicalMemoryKB() const size_t len = sizeof(phys); sysctl(mib, 2, &phys, &len, NULL, 0); - return (U32)(phys >> 10); + return U64Bytes(phys); #elif LL_LINUX U64 phys = 0; phys = (U64)(getpagesize()) * (U64)(get_phys_pages()); - return (U32)(phys >> 10); + return U64Bytes(phys); #elif LL_SOLARIS U64 phys = 0; phys = (U64)(getpagesize()) * (U64)(sysconf(_SC_PHYS_PAGES)); - return (U32)(phys >> 10); + return U64Bytes(phys); #else return 0; @@ -918,32 +917,32 @@ U32 LLMemoryInfo::getPhysicalMemoryKB() const #endif } -U32 LLMemoryInfo::getPhysicalMemoryClamped() const +U32Bytes LLMemoryInfo::getPhysicalMemoryClamped() const { // Return the total physical memory in bytes, but clamp it // to no more than U32_MAX - U32 phys_kb = getPhysicalMemoryKB(); - if (phys_kb >= 4194304 /* 4GB in KB */) + U32Kilobytes phys_kb = getPhysicalMemoryKB(); + if (phys_kb >= U32Gigabytes(4)) { - return U32_MAX; + return U32Bytes(U32_MAX); } else { - return phys_kb << 10; + return phys_kb; } } //static -void LLMemoryInfo::getAvailableMemoryKB(U32& avail_physical_mem_kb, U32& avail_virtual_mem_kb) +void LLMemoryInfo::getAvailableMemoryKB(U32Kilobytes& avail_physical_mem_kb, U32Kilobytes& avail_virtual_mem_kb) { #if LL_WINDOWS // Sigh, this shouldn't be a static method, then we wouldn't have to // reload this data separately from refresh() LLSD statsMap(loadStatsMap()); - avail_physical_mem_kb = statsMap["Avail Physical KB"].asInteger(); - avail_virtual_mem_kb = statsMap["Avail Virtual KB"].asInteger(); + avail_physical_mem_kb = (U32Kilobytes)statsMap["Avail Physical KB"].asInteger(); + avail_virtual_mem_kb = (U32Kilobytes)statsMap["Avail Virtual KB"].asInteger(); #elif LL_DARWIN // mStatsMap is derived from vm_stat, look for (e.g.) "kb free": @@ -960,8 +959,8 @@ void LLMemoryInfo::getAvailableMemoryKB(U32& avail_physical_mem_kb, U32& avail_v // Pageins: 2097212. // Pageouts: 41759. // Object cache: 841598 hits of 7629869 lookups (11% hit rate) - avail_physical_mem_kb = -1 ; - avail_virtual_mem_kb = -1 ; + avail_physical_mem_kb = (U32Kilobytes)-1 ; + avail_virtual_mem_kb = (U32Kilobytes)-1 ; #elif LL_LINUX // mStatsMap is derived from MEMINFO_FILE: @@ -1012,15 +1011,15 @@ void LLMemoryInfo::getAvailableMemoryKB(U32& avail_physical_mem_kb, U32& avail_v // DirectMap4k: 434168 kB // DirectMap2M: 477184 kB // (could also run 'free', but easier to read a file than run a program) - avail_physical_mem_kb = -1 ; - avail_virtual_mem_kb = -1 ; + avail_physical_mem_kb = (U32Kilobytes)-1 ; + avail_virtual_mem_kb = (U32Kilobytes)-1 ; #else //do not know how to collect available memory info for other systems. //leave it blank here for now. - avail_physical_mem_kb = -1 ; - avail_virtual_mem_kb = -1 ; + avail_physical_mem_kb = (U32Kilobytes)-1 ; + avail_virtual_mem_kb = (U32Kilobytes)-1 ; #endif } @@ -1433,9 +1432,14 @@ public: LL_CONT << "slowest framerate for last " << int(prevSize * MEM_INFO_THROTTLE) << " seconds "; } + + S32 precision = LL_CONT.precision(); + LL_CONT << std::fixed << std::setprecision(1) << framerate << '\n' - << LLMemoryInfo() << LL_ENDL; + << LLMemoryInfo(); + LL_CONT.precision(precision); + LL_CONT << LL_ENDL; return false; } @@ -1482,7 +1486,7 @@ BOOL gunzip_file(const std::string& srcfile, const std::string& dstfile) size_t nwrit = fwrite(buffer, sizeof(U8), bytes, dst); if (nwrit < (size_t) bytes) { - llwarns << "Short write on " << tmpfile << ": Wrote " << nwrit << " of " << bytes << " bytes." << llendl; + LL_WARNS() << "Short write on " << tmpfile << ": Wrote " << nwrit << " of " << bytes << " bytes." << LL_ENDL; goto err; } } while(gzeof(src) == 0); @@ -1515,14 +1519,14 @@ BOOL gzip_file(const std::string& srcfile, const std::string& dstfile) { if (gzwrite(dst, buffer, bytes) <= 0) { - llwarns << "gzwrite failed: " << gzerror(dst, NULL) << llendl; + LL_WARNS() << "gzwrite failed: " << gzerror(dst, NULL) << LL_ENDL; goto err; } } if (ferror(src)) { - llwarns << "Error reading " << srcfile << llendl; + LL_WARNS() << "Error reading " << srcfile << LL_ENDL; goto err; } diff --git a/indra/llcommon/llsys.h b/indra/llcommon/llsys.h index cfed0fff17..962367f69f 100755 --- a/indra/llcommon/llsys.h +++ b/indra/llcommon/llsys.h @@ -33,7 +33,7 @@ // use an LLCPUInfo object: // // LLCPUInfo info; -// llinfos << info << llendl; +// LL_INFOS() << info << LL_ENDL; // #include "llsd.h" @@ -105,22 +105,22 @@ class LL_COMMON_API LLMemoryInfo Here's how you use an LLMemoryInfo: LLMemoryInfo info; -<br> llinfos << info << llendl; +<br> LL_INFOS() << info << LL_ENDL; */ { public: LLMemoryInfo(); ///< Default constructor void stream(std::ostream& s) const; ///< output text info to s - U32 getPhysicalMemoryKB() const; ///< Memory size in KiloBytes + U32Kilobytes getPhysicalMemoryKB() const; /*! Memory size in bytes, if total memory is >= 4GB then U32_MAX will ** be returned. */ - U32 getPhysicalMemoryClamped() const; ///< Memory size in clamped bytes + U32Bytes getPhysicalMemoryClamped() const; ///< Memory size in clamped bytes //get the available memory infomation in KiloBytes. - static void getAvailableMemoryKB(U32& avail_physical_mem_kb, U32& avail_virtual_mem_kb); + static void getAvailableMemoryKB(U32Kilobytes& avail_physical_mem_kb, U32Kilobytes& avail_virtual_mem_kb); // Retrieve a map of memory statistics. The keys of the map are platform- // dependent. The values are in kilobytes to try to avoid integer overflow. diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp index e67d1bc57b..51c89e1eaf 100755 --- a/indra/llcommon/llthread.cpp +++ b/indra/llcommon/llthread.cpp @@ -29,13 +29,49 @@ #include "apr_portable.h" #include "llthread.h" +#include "llmutex.h" #include "lltimer.h" +#include "lltrace.h" +#include "lltracethreadrecorder.h" #if LL_LINUX || LL_SOLARIS #include <sched.h> #endif + +#ifdef LL_WINDOWS +const DWORD MS_VC_EXCEPTION=0x406D1388; + +#pragma pack(push,8) +typedef struct tagTHREADNAME_INFO +{ + DWORD dwType; // Must be 0x1000. + LPCSTR szName; // Pointer to name (in user addr space). + DWORD dwThreadID; // Thread ID (-1=caller thread). + DWORD dwFlags; // Reserved for future use, must be zero. +} THREADNAME_INFO; +#pragma pack(pop) + +void set_thread_name( DWORD dwThreadID, const char* threadName) +{ + THREADNAME_INFO info; + info.dwType = 0x1000; + info.szName = threadName; + info.dwThreadID = dwThreadID; + info.dwFlags = 0; + + __try + { + ::RaiseException( MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(DWORD), (DWORD*)&info ); + } + __except(EXCEPTION_CONTINUE_EXECUTION) + { + } +} +#endif + + //---------------------------------------------------------------------------- // Usage: // void run_func(LLThread* thread) @@ -56,19 +92,24 @@ // //---------------------------------------------------------------------------- -#if !LL_DARWIN -U32 ll_thread_local sThreadID = 0; +#if LL_DARWIN +// statically allocated thread local storage not supported in Darwin executable formats +#elif LL_WINDOWS +U32 __declspec(thread) sThreadID = 0; +#elif LL_LINUX +U32 __thread sThreadID = 0; #endif U32 LLThread::sIDIter = 0; + LL_COMMON_API void assert_main_thread() { static U32 s_thread_id = LLThread::currentID(); if (LLThread::currentID() != s_thread_id) { - llwarns << "Illegal execution from thread id " << (S32) LLThread::currentID() - << " outside main thread " << (S32) s_thread_id << llendl; + LL_WARNS() << "Illegal execution from thread id " << (S32) LLThread::currentID() + << " outside main thread " << (S32) s_thread_id << LL_ENDL; } } @@ -86,6 +127,13 @@ void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap { LLThread *threadp = (LLThread *)datap; +#ifdef LL_WINDOWS + set_thread_name(-1, threadp->mName.c_str()); +#endif + + // for now, hard code all LLThreads to report to single master thread recorder, which is known to be running on main thread + threadp->mRecorder = new LLTrace::ThreadRecorder(*LLTrace::get_master_thread_recorder()); + #if !LL_DARWIN sThreadID = threadp->mID; #endif @@ -93,21 +141,26 @@ void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap // Run the user supplied function threadp->run(); - //llinfos << "LLThread::staticRun() Exiting: " << threadp->mName << llendl; + //LL_INFOS() << "LLThread::staticRun() Exiting: " << threadp->mName << LL_ENDL; + + delete threadp->mRecorder; + threadp->mRecorder = NULL; // We're done with the run function, this thread is done executing now. + //NB: we are using this flag to sync across threads...we really need memory barriers here threadp->mStatus = STOPPED; return NULL; } - LLThread::LLThread(const std::string& name, apr_pool_t *poolp) : mPaused(FALSE), mName(name), mAPRThreadp(NULL), - mStatus(STOPPED) + mStatus(STOPPED), + mRecorder(NULL) { + mID = ++sIDIter; // Thread creation probably CAN be paranoid about APR being initialized, if necessary @@ -150,10 +203,10 @@ void LLThread::shutdown() // First, set the flag that indicates that we're ready to die setQuitting(); - //llinfos << "LLThread::~LLThread() Killing thread " << mName << " Status: " << mStatus << llendl; + //LL_INFOS() << "LLThread::~LLThread() Killing thread " << mName << " Status: " << mStatus << LL_ENDL; // Now wait a bit for the thread to exit // It's unclear whether I should even bother doing this - this destructor - // should netver get called unless we're already stopped, really... + // should never get called unless we're already stopped, really... S32 counter = 0; const S32 MAX_WAIT = 600; while (counter < MAX_WAIT) @@ -172,8 +225,10 @@ void LLThread::shutdown() if (!isStopped()) { // This thread just wouldn't stop, even though we gave it time - //llwarns << "LLThread::~LLThread() exiting thread before clean exit!" << llendl; + //LL_WARNS() << "LLThread::~LLThread() exiting thread before clean exit!" << LL_ENDL; // Put a stake in its heart. + delete mRecorder; + apr_thread_exit(mAPRThreadp, -1); return; } @@ -191,6 +246,14 @@ void LLThread::shutdown() apr_pool_destroy(mAPRPoolp); mAPRPoolp = 0; } + + if (mRecorder) + { + // missed chance to properly shut down recorder (needs to be done in thread context) + // probably due to abnormal thread termination + // so just leak it and remove it from parent + LLTrace::get_master_thread_recorder()->removeChildRecorder(mRecorder); + } } @@ -212,9 +275,10 @@ void LLThread::start() else { mStatus = STOPPED; - llwarns << "failed to start thread " << mName << llendl; + LL_WARNS() << "failed to start thread " << mName << LL_ENDL; ll_apr_warn_status(status); } + } //============================================================================ @@ -283,7 +347,13 @@ void LLThread::setQuitting() // static U32 LLThread::currentID() { +#if LL_DARWIN + // statically allocated thread local storage not supported in Darwin executable formats return (U32)apr_os_thread_current(); +#else + return sThreadID; +#endif + } // static @@ -316,185 +386,6 @@ void LLThread::wakeLocked() //============================================================================ -LLMutex::LLMutex(apr_pool_t *poolp) : - mAPRMutexp(NULL), mCount(0), mLockingThread(NO_THREAD) -{ - //if (poolp) - //{ - // mIsLocalPool = FALSE; - // mAPRPoolp = poolp; - //} - //else - { - mIsLocalPool = TRUE; - apr_pool_create(&mAPRPoolp, NULL); // Create a subpool for this thread - } - apr_thread_mutex_create(&mAPRMutexp, APR_THREAD_MUTEX_UNNESTED, mAPRPoolp); -} - - -LLMutex::~LLMutex() -{ -#if MUTEX_DEBUG - //bad assertion, the subclass LLSignal might be "locked", and that's OK - //llassert_always(!isLocked()); // better not be locked! -#endif - apr_thread_mutex_destroy(mAPRMutexp); - mAPRMutexp = NULL; - if (mIsLocalPool) - { - apr_pool_destroy(mAPRPoolp); - } -} - - -void LLMutex::lock() -{ - if(isSelfLocked()) - { //redundant lock - mCount++; - return; - } - - apr_thread_mutex_lock(mAPRMutexp); - -#if MUTEX_DEBUG - // Have to have the lock before we can access the debug info - U32 id = LLThread::currentID(); - if (mIsLocked[id] != FALSE) - llerrs << "Already locked in Thread: " << id << llendl; - mIsLocked[id] = TRUE; -#endif - -#if LL_DARWIN - mLockingThread = LLThread::currentID(); -#else - mLockingThread = sThreadID; -#endif -} - -bool LLMutex::trylock() -{ - if(isSelfLocked()) - { //redundant lock - mCount++; - return true; - } - - apr_status_t status(apr_thread_mutex_trylock(mAPRMutexp)); - if (APR_STATUS_IS_EBUSY(status)) - { - return false; - } - -#if MUTEX_DEBUG - // Have to have the lock before we can access the debug info - U32 id = LLThread::currentID(); - if (mIsLocked[id] != FALSE) - llerrs << "Already locked in Thread: " << id << llendl; - mIsLocked[id] = TRUE; -#endif - -#if LL_DARWIN - mLockingThread = LLThread::currentID(); -#else - mLockingThread = sThreadID; -#endif - return true; -} - -void LLMutex::unlock() -{ - if (mCount > 0) - { //not the root unlock - mCount--; - return; - } - -#if MUTEX_DEBUG - // Access the debug info while we have the lock - U32 id = LLThread::currentID(); - if (mIsLocked[id] != TRUE) - llerrs << "Not locked in Thread: " << id << llendl; - mIsLocked[id] = FALSE; -#endif - - mLockingThread = NO_THREAD; - apr_thread_mutex_unlock(mAPRMutexp); -} - -bool LLMutex::isLocked() -{ - apr_status_t status = apr_thread_mutex_trylock(mAPRMutexp); - if (APR_STATUS_IS_EBUSY(status)) - { - return true; - } - else - { - apr_thread_mutex_unlock(mAPRMutexp); - return false; - } -} - -bool LLMutex::isSelfLocked() -{ -#if LL_DARWIN - return mLockingThread == LLThread::currentID(); -#else - return mLockingThread == sThreadID; -#endif -} - -U32 LLMutex::lockingThread() const -{ - return mLockingThread; -} - -//============================================================================ - -LLCondition::LLCondition(apr_pool_t *poolp) : - LLMutex(poolp) -{ - // base class (LLMutex) has already ensured that mAPRPoolp is set up. - - apr_thread_cond_create(&mAPRCondp, mAPRPoolp); -} - - -LLCondition::~LLCondition() -{ - apr_thread_cond_destroy(mAPRCondp); - mAPRCondp = NULL; -} - - -void LLCondition::wait() -{ - if (!isLocked()) - { //mAPRMutexp MUST be locked before calling apr_thread_cond_wait - apr_thread_mutex_lock(mAPRMutexp); -#if MUTEX_DEBUG - // avoid asserts on destruction in non-release builds - U32 id = LLThread::currentID(); - mIsLocked[id] = TRUE; -#endif - } - apr_thread_cond_wait(mAPRCondp, mAPRMutexp); -} - -void LLCondition::signal() -{ - apr_thread_cond_signal(mAPRCondp); -} - -void LLCondition::broadcast() -{ - apr_thread_cond_broadcast(mAPRCondp); -} - -//============================================================================ - //---------------------------------------------------------------------------- //static @@ -533,11 +424,10 @@ LLThreadSafeRefCount::~LLThreadSafeRefCount() { if (mRef != 0) { - llerrs << "deleting non-zero reference" << llendl; + LL_ERRS() << "deleting non-zero reference" << LL_ENDL; } } - //============================================================================ LLResponder::~LLResponder() diff --git a/indra/llcommon/llthread.h b/indra/llcommon/llthread.h index 8c7143304f..6f9ec10fd3 100755 --- a/indra/llcommon/llthread.h +++ b/indra/llcommon/llthread.h @@ -31,20 +31,20 @@ #include "llapr.h" #include "apr_thread_cond.h" #include "boost/intrusive_ptr.hpp" +#include "llmutex.h" +#include "llrefcount.h" -class LLThread; -class LLMutex; -class LLCondition; +LL_COMMON_API void assert_main_thread(); -#if LL_WINDOWS -#define ll_thread_local __declspec(thread) -#else -#define ll_thread_local __thread -#endif +namespace LLTrace +{ + class ThreadRecorder; +} class LL_COMMON_API LLThread { private: + friend class LLMutex; static U32 sIDIter; public: @@ -98,11 +98,11 @@ private: BOOL mPaused; // static function passed to APR thread creation routine - static void *APR_THREAD_FUNC staticRun(apr_thread_t *apr_threadp, void *datap); + static void *APR_THREAD_FUNC staticRun(struct apr_thread_t *apr_threadp, void *datap); protected: std::string mName; - LLCondition* mRunCondition; + class LLCondition* mRunCondition; LLMutex* mDataLock; apr_thread_t *mAPRThreadp; @@ -110,6 +110,7 @@ protected: BOOL mIsLocalPool; EThreadStatus mStatus; U32 mID; + LLTrace::ThreadRecorder* mRecorder; //a local apr_pool for APRFile operations in this thread. If it exists, LLAPRFile::sAPRFilePoolp should not be used. //Note: this pool is used by APRFile ONLY, do NOT use it for any other purposes. @@ -140,117 +141,6 @@ protected: // mDataLock->unlock(); }; -//============================================================================ - -#define MUTEX_DEBUG (LL_DEBUG || LL_RELEASE_WITH_DEBUG_INFO) - -class LL_COMMON_API LLMutex -{ -public: - typedef enum - { - NO_THREAD = 0xFFFFFFFF - } e_locking_thread; - - LLMutex(apr_pool_t *apr_poolp); // NULL pool constructs a new pool for the mutex - virtual ~LLMutex(); - - void lock(); // blocks - bool trylock(); // non-blocking, returns true if lock held. - void unlock(); // undefined behavior when called on mutex not being held - bool isLocked(); // non-blocking, but does do a lock/unlock so not free - bool isSelfLocked(); //return true if locked in a same thread - U32 lockingThread() const; //get ID of locking thread - -protected: - apr_thread_mutex_t *mAPRMutexp; - mutable U32 mCount; - mutable U32 mLockingThread; - - apr_pool_t *mAPRPoolp; - BOOL mIsLocalPool; - -#if MUTEX_DEBUG - std::map<U32, BOOL> mIsLocked; -#endif -}; - -//============================================================================ - -// Actually a condition/mutex pair (since each condition needs to be associated with a mutex). -class LL_COMMON_API LLCondition : public LLMutex -{ -public: - LLCondition(apr_pool_t *apr_poolp); // Defaults to global pool, could use the thread pool as well. - ~LLCondition(); - - void wait(); // blocks - void signal(); - void broadcast(); - -protected: - apr_thread_cond_t *mAPRCondp; -}; - -//============================================================================ - -class LLMutexLock -{ -public: - LLMutexLock(LLMutex* mutex) - { - mMutex = mutex; - - if(mMutex) - mMutex->lock(); - } - ~LLMutexLock() - { - if(mMutex) - mMutex->unlock(); - } -private: - LLMutex* mMutex; -}; - -//============================================================================ - -// Scoped locking class similar in function to LLMutexLock but uses -// the trylock() method to conditionally acquire lock without -// blocking. Caller resolves the resulting condition by calling -// the isLocked() method and either punts or continues as indicated. -// -// Mostly of interest to callers needing to avoid stalls who can -// guarantee another attempt at a later time. - -class LLMutexTrylock -{ -public: - LLMutexTrylock(LLMutex* mutex) - : mMutex(mutex), - mLocked(false) - { - if (mMutex) - mLocked = mMutex->trylock(); - } - - ~LLMutexTrylock() - { - if (mMutex && mLocked) - mMutex->unlock(); - } - - bool isLocked() const - { - return mLocked; - } - -private: - LLMutex* mMutex; - bool mLocked; -}; - -//============================================================================ void LLThread::lockData() { @@ -265,76 +155,6 @@ void LLThread::unlockData() //============================================================================ -// see llmemory.h for LLPointer<> definition - -class LL_COMMON_API LLThreadSafeRefCount -{ -public: - static void initThreadSafeRefCount(); // creates sMutex - static void cleanupThreadSafeRefCount(); // destroys sMutex - -private: - static LLMutex* sMutex; - -protected: - virtual ~LLThreadSafeRefCount(); // use unref() - -public: - LLThreadSafeRefCount(); - LLThreadSafeRefCount(const LLThreadSafeRefCount&); - LLThreadSafeRefCount& operator=(const LLThreadSafeRefCount& ref) - { - mRef = 0; - return *this; - } - - void ref() - { - mRef++; - } - - void unref() - { - llassert(mRef >= 1); - if ((--mRef) == 0) // See note in llapr.h on atomic decrement operator return value. - { - // If we hit zero, the caller should be the only smart pointer owning the object and we can delete it. - // It is technically possible for a vanilla pointer to mess this up, or another thread to - // jump in, find this object, create another smart pointer and end up dangling, but if - // the code is that bad and not thread-safe, it's trouble already. - delete this; - } - } - - S32 getNumRefs() const - { - const S32 currentVal = mRef.CurrentValue(); - return currentVal; - } - -private: - LLAtomic32< S32 > mRef; -}; - - -/** - * intrusive pointer support for LLThreadSafeRefCount - * this allows you to use boost::intrusive_ptr with any LLThreadSafeRefCount-derived type - */ -namespace boost -{ - inline void intrusive_ptr_add_ref(LLThreadSafeRefCount* p) - { - p->ref(); - } - - inline void intrusive_ptr_release(LLThreadSafeRefCount* p) - { - p->unref(); - } -}; -//============================================================================ - // Simple responder for self destructing callbacks // Pure virtual class class LL_COMMON_API LLResponder : public LLThreadSafeRefCount diff --git a/indra/llcommon/llthreadlocalstorage.cpp b/indra/llcommon/llthreadlocalstorage.cpp new file mode 100644 index 0000000000..8cef05caac --- /dev/null +++ b/indra/llcommon/llthreadlocalstorage.cpp @@ -0,0 +1,119 @@ +/** + * @file llthreadlocalstorage.cpp + * @author Richard + * @date 2013-1-11 + * @brief implementation of thread local storage utility classes + * + * $LicenseInfo:firstyear=2013&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" +#include "llthreadlocalstorage.h" +#include "llapr.h" + +// +//LLThreadLocalPointerBase +// +bool LLThreadLocalPointerBase::sInitialized = false; + +void LLThreadLocalPointerBase::set( void* value ) +{ + llassert(sInitialized && mThreadKey); + + apr_status_t result = apr_threadkey_private_set((void*)value, mThreadKey); + if (result != APR_SUCCESS) + { + ll_apr_warn_status(result); + LL_ERRS() << "Failed to set thread local data" << LL_ENDL; + } +} + +void* LLThreadLocalPointerBase::get() const +{ + // llassert(sInitialized); + void* ptr; + apr_status_t result = + apr_threadkey_private_get(&ptr, mThreadKey); + if (result != APR_SUCCESS) + { + ll_apr_warn_status(result); + LL_ERRS() << "Failed to get thread local data" << LL_ENDL; + } + return ptr; +} + + +void LLThreadLocalPointerBase::initStorage( ) +{ + apr_status_t result = apr_threadkey_private_create(&mThreadKey, NULL, gAPRPoolp); + if (result != APR_SUCCESS) + { + ll_apr_warn_status(result); + LL_ERRS() << "Failed to allocate thread local data" << LL_ENDL; + } +} + +void LLThreadLocalPointerBase::destroyStorage() +{ + if (sInitialized) + { + if (mThreadKey) + { + apr_status_t result = apr_threadkey_private_delete(mThreadKey); + if (result != APR_SUCCESS) + { + ll_apr_warn_status(result); + LL_ERRS() << "Failed to delete thread local data" << LL_ENDL; + } + } + } +} + +//static +void LLThreadLocalPointerBase::initAllThreadLocalStorage() +{ + if (!sInitialized) + { + for (LLInstanceTracker<LLThreadLocalPointerBase>::instance_iter it = beginInstances(), end_it = endInstances(); + it != end_it; + ++it) + { + (*it).initStorage(); + } + sInitialized = true; + } +} + +//static +void LLThreadLocalPointerBase::destroyAllThreadLocalStorage() +{ + if (sInitialized) + { + //for (LLInstanceTracker<LLThreadLocalPointerBase>::instance_iter it = beginInstances(), end_it = endInstances(); + // it != end_it; + // ++it) + //{ + // (*it).destroyStorage(); + //} + sInitialized = false; + } +} diff --git a/indra/llcommon/llthreadlocalstorage.h b/indra/llcommon/llthreadlocalstorage.h new file mode 100644 index 0000000000..ec3b52c8cb --- /dev/null +++ b/indra/llcommon/llthreadlocalstorage.h @@ -0,0 +1,185 @@ +/** + * @file llthreadlocalstorage.h + * @author Richard + * @brief Class wrappers for thread local storage + * + * $LicenseInfo:firstyear=2004&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLTHREADLOCALSTORAGE_H +#define LL_LLTHREADLOCALSTORAGE_H + +#include "llinstancetracker.h" + +class LLThreadLocalPointerBase : public LLInstanceTracker<LLThreadLocalPointerBase> +{ +public: + LLThreadLocalPointerBase() + : mThreadKey(NULL) + { + if (sInitialized) + { + initStorage(); + } + } + + LLThreadLocalPointerBase( const LLThreadLocalPointerBase& other) + : mThreadKey(NULL) + { + if (sInitialized) + { + initStorage(); + } + } + + ~LLThreadLocalPointerBase() + { + destroyStorage(); + } + + static void initAllThreadLocalStorage(); + static void destroyAllThreadLocalStorage(); + +protected: + void set(void* value); + + void* get() const; + + void initStorage(); + void destroyStorage(); + +protected: + struct apr_threadkey_t* mThreadKey; + static bool sInitialized; +}; + +template <typename T> +class LLThreadLocalPointer : public LLThreadLocalPointerBase +{ +public: + + LLThreadLocalPointer() + {} + + explicit LLThreadLocalPointer(T* value) + { + set(value); + } + + + LLThreadLocalPointer(const LLThreadLocalPointer<T>& other) + : LLThreadLocalPointerBase(other) + { + set(other.get()); + } + + LL_FORCE_INLINE T* get() const + { + return (T*)LLThreadLocalPointerBase::get(); + } + + T* operator -> () const + { + return (T*)get(); + } + + T& operator*() const + { + return *(T*)get(); + } + + LLThreadLocalPointer<T>& operator = (T* value) + { + set((void*)value); + return *this; + } + + bool operator ==(const T* other) const + { + if (!sInitialized) return false; + return get() == other; + } + + bool isNull() const { return !sInitialized || get() == NULL; } + + bool notNull() const { return sInitialized && get() != NULL; } +}; + +template<typename DERIVED_TYPE> +class LLThreadLocalSingletonPointer +{ +public: + LL_FORCE_INLINE static DERIVED_TYPE* getInstance() + { +#if LL_DARWIN + createTLSKey(); + return (DERIVED_TYPE*)pthread_getspecific(sInstanceKey); +#else + return sInstance; +#endif + } + + static void setInstance(DERIVED_TYPE* instance) + { +#if LL_DARWIN + createTLSKey(); + pthread_setspecific(sInstanceKey, (void*)instance); +#else + sInstance = instance; +#endif + } + +private: + +#if LL_WINDOWS + static __declspec(thread) DERIVED_TYPE* sInstance; +#elif LL_LINUX + static __thread DERIVED_TYPE* sInstance; +#elif LL_DARWIN + static void TLSError() + { + LL_ERRS() << "Could not create thread local storage" << LL_ENDL; + } + static void createTLSKey() + { + static S32 key_created = pthread_key_create(&sInstanceKey, NULL); + if (key_created != 0) + { + LL_ERRS() << "Could not create thread local storage" << LL_ENDL; + } + } + static pthread_key_t sInstanceKey; +#endif +}; + +#if LL_WINDOWS +template<typename DERIVED_TYPE> +__declspec(thread) DERIVED_TYPE* LLThreadLocalSingletonPointer<DERIVED_TYPE>::sInstance = NULL; +#elif LL_LINUX +template<typename DERIVED_TYPE> +__thread DERIVED_TYPE* LLThreadLocalSingletonPointer<DERIVED_TYPE>::sInstance = NULL; +#elif LL_DARWIN +template<typename DERIVED_TYPE> +pthread_key_t LLThreadLocalSingletonPointer<DERIVED_TYPE>::sInstanceKey; +#endif + +#endif // LL_LLTHREADLOCALSTORAGE_H diff --git a/indra/llcommon/llthreadsafequeue.cpp b/indra/llcommon/llthreadsafequeue.cpp index 8a73e632a9..185f0d63fb 100755 --- a/indra/llcommon/llthreadsafequeue.cpp +++ b/indra/llcommon/llthreadsafequeue.cpp @@ -54,7 +54,7 @@ LLThreadSafeQueueImplementation::LLThreadSafeQueueImplementation(apr_pool_t * po LLThreadSafeQueueImplementation::~LLThreadSafeQueueImplementation() { if(mQueue != 0) { - if(apr_queue_size(mQueue) != 0) llwarns << + if(apr_queue_size(mQueue) != 0) LL_WARNS() << "terminating queue which still contains " << apr_queue_size(mQueue) << " elements;" << "memory will be leaked" << LL_ENDL; apr_queue_term(mQueue); diff --git a/indra/llcommon/lltimer.cpp b/indra/llcommon/lltimer.cpp index 9ebc6de7f4..ab105a82e6 100755 --- a/indra/llcommon/lltimer.cpp +++ b/indra/llcommon/lltimer.cpp @@ -31,11 +31,9 @@ #include "u64.h" #if LL_WINDOWS -# define WIN32_LEAN_AND_MEAN -# include <winsock2.h> -# include <windows.h> +# include "llwin32headerslean.h" #elif LL_LINUX || LL_SOLARIS || LL_DARWIN -# include <errno.h> +# include <errno.h> # include <sys/time.h> #else # error "architecture not supported" @@ -45,7 +43,6 @@ // // Locally used constants // -const U32 SEC_PER_DAY = 86400; const F64 SEC_TO_MICROSEC = 1000000.f; const U64 SEC_TO_MICROSEC_U64 = 1000000; const F64 USEC_TO_SEC_F64 = 0.000001; @@ -58,11 +55,6 @@ const F64 USEC_TO_SEC_F64 = 0.000001; S32 gUTCOffset = 0; // viewer's offset from server UTC, in seconds LLTimer* LLTimer::sTimer = NULL; -F64 gClockFrequency = 0.0; -F64 gClockFrequencyInv = 0.0; -F64 gClocksToMicroseconds = 0.0; -U64 gTotalTimeClockCount = 0; -U64 gLastTotalTimeClockCount = 0; // // Forward declarations @@ -190,7 +182,7 @@ U64 get_clock_count() return clock_count.QuadPart - offset; } -F64 calc_clock_frequency(U32 uiMeasureMSecs) +F64 calc_clock_frequency() { __int64 freq; QueryPerformanceFrequency((LARGE_INTEGER *) &freq); @@ -201,7 +193,7 @@ F64 calc_clock_frequency(U32 uiMeasureMSecs) #if LL_LINUX || LL_DARWIN || LL_SOLARIS // Both Linux and Mac use gettimeofday for accurate time -F64 calc_clock_frequency(unsigned int uiMeasureMSecs) +F64 calc_clock_frequency() { return 1000000.0; // microseconds, so 1 MHz. } @@ -216,56 +208,68 @@ U64 get_clock_count() #endif -void update_clock_frequencies() +TimerInfo::TimerInfo() +: mClockFrequency(0.0), + mTotalTimeClockCount(0), + mLastTotalTimeClockCount(0) +{} + +void TimerInfo::update() { - gClockFrequency = calc_clock_frequency(50U); - gClockFrequencyInv = 1.0/gClockFrequency; - gClocksToMicroseconds = gClockFrequencyInv * SEC_TO_MICROSEC; + mClockFrequency = calc_clock_frequency(); + mClockFrequencyInv = 1.0/mClockFrequency; + mClocksToMicroseconds = mClockFrequencyInv; } +TimerInfo& get_timer_info() +{ + static TimerInfo sTimerInfo; + return sTimerInfo; +} /////////////////////////////////////////////////////////////////////////////// // returns a U64 number that represents the number of -// microseconds since the unix epoch - Jan 1, 1970 -U64 totalTime() +// microseconds since the Unix epoch - Jan 1, 1970 +U64MicrosecondsImplicit totalTime() { U64 current_clock_count = get_clock_count(); - if (!gTotalTimeClockCount) + if (!get_timer_info().mTotalTimeClockCount || get_timer_info().mClocksToMicroseconds.value() == 0) { - update_clock_frequencies(); - gTotalTimeClockCount = current_clock_count; + get_timer_info().update(); + get_timer_info().mTotalTimeClockCount = current_clock_count; #if LL_WINDOWS - // Synch us up with local time (even though we PROBABLY don't need to, this is how it was implemented) + // Sync us up with local time (even though we PROBABLY don't need to, this is how it was implemented) // Unix platforms use gettimeofday so they are synced, although this probably isn't a good assumption to // make in the future. - gTotalTimeClockCount = (U64)(time(NULL) * gClockFrequency); + get_timer_info().mTotalTimeClockCount = (U64)(time(NULL) * get_timer_info().mClockFrequency); #endif // Update the last clock count - gLastTotalTimeClockCount = current_clock_count; + get_timer_info().mLastTotalTimeClockCount = current_clock_count; } else { - if (current_clock_count >= gLastTotalTimeClockCount) + if (current_clock_count >= get_timer_info().mLastTotalTimeClockCount) { // No wrapping, we're all okay. - gTotalTimeClockCount += current_clock_count - gLastTotalTimeClockCount; + get_timer_info().mTotalTimeClockCount += current_clock_count - get_timer_info().mLastTotalTimeClockCount; } else { // We've wrapped. Compensate correctly - gTotalTimeClockCount += (0xFFFFFFFFFFFFFFFFULL - gLastTotalTimeClockCount) + current_clock_count; + get_timer_info().mTotalTimeClockCount += (0xFFFFFFFFFFFFFFFFULL - get_timer_info().mLastTotalTimeClockCount) + current_clock_count; } // Update the last clock count - gLastTotalTimeClockCount = current_clock_count; + get_timer_info().mLastTotalTimeClockCount = current_clock_count; } // Return the total clock tick count in microseconds. - return (U64)(gTotalTimeClockCount*gClocksToMicroseconds); + U64Microseconds time(get_timer_info().mTotalTimeClockCount*get_timer_info().mClocksToMicroseconds); + return time; } @@ -273,9 +277,9 @@ U64 totalTime() LLTimer::LLTimer() { - if (!gClockFrequency) + if (!get_timer_info().mClockFrequency) { - update_clock_frequencies(); + get_timer_info().update(); } mStarted = TRUE; @@ -283,20 +287,32 @@ LLTimer::LLTimer() } LLTimer::~LLTimer() +{} + +// static +void LLTimer::initClass() +{ + if (!sTimer) sTimer = new LLTimer; +} + +// static +void LLTimer::cleanupClass() { + delete sTimer; sTimer = NULL; } // static -U64 LLTimer::getTotalTime() +U64MicrosecondsImplicit LLTimer::getTotalTime() { // simply call into the implementation function. - return totalTime(); + U64MicrosecondsImplicit total_time = totalTime(); + return total_time; } // static -F64 LLTimer::getTotalSeconds() +F64SecondsImplicit LLTimer::getTotalSeconds() { - return U64_to_F64(getTotalTime()) * USEC_TO_SEC_F64; + return F64Microseconds(U64_to_F64(getTotalTime())); } void LLTimer::reset() @@ -343,43 +359,43 @@ U64 getElapsedTimeAndUpdate(U64& lastClockCount) } -F64 LLTimer::getElapsedTimeF64() const +F64SecondsImplicit LLTimer::getElapsedTimeF64() const { U64 last = mLastClockCount; - return (F64)getElapsedTimeAndUpdate(last) * gClockFrequencyInv; + return (F64)getElapsedTimeAndUpdate(last) * get_timer_info().mClockFrequencyInv; } -F32 LLTimer::getElapsedTimeF32() const +F32SecondsImplicit LLTimer::getElapsedTimeF32() const { return (F32)getElapsedTimeF64(); } -F64 LLTimer::getElapsedTimeAndResetF64() +F64SecondsImplicit LLTimer::getElapsedTimeAndResetF64() { - return (F64)getElapsedTimeAndUpdate(mLastClockCount) * gClockFrequencyInv; + return (F64)getElapsedTimeAndUpdate(mLastClockCount) * get_timer_info().mClockFrequencyInv; } -F32 LLTimer::getElapsedTimeAndResetF32() +F32SecondsImplicit LLTimer::getElapsedTimeAndResetF32() { return (F32)getElapsedTimeAndResetF64(); } /////////////////////////////////////////////////////////////////////////////// -void LLTimer::setTimerExpirySec(F32 expiration) +void LLTimer::setTimerExpirySec(F32SecondsImplicit expiration) { mExpirationTicks = get_clock_count() - + (U64)((F32)(expiration * gClockFrequency)); + + (U64)((F32)(expiration * get_timer_info().mClockFrequency.value())); } -F32 LLTimer::getRemainingTimeF32() const +F32SecondsImplicit LLTimer::getRemainingTimeF32() const { U64 cur_ticks = get_clock_count(); if (cur_ticks > mExpirationTicks) { return 0.0f; } - return F32((mExpirationTicks - cur_ticks) * gClockFrequencyInv); + return F32((mExpirationTicks - cur_ticks) * get_timer_info().mClockFrequencyInv); } @@ -392,7 +408,7 @@ BOOL LLTimer::checkExpirationAndReset(F32 expiration) } mExpirationTicks = cur_ticks - + (U64)((F32)(expiration * gClockFrequency)); + + (U64)((F32)(expiration * get_timer_info().mClockFrequency)); return TRUE; } @@ -448,7 +464,7 @@ BOOL LLTimer::knownBadTimer() { if (!wcscmp(pci_id, bad_pci_list[check])) { -// llwarns << "unreliable PCI chipset found!! " << pci_id << endl; +// LL_WARNS() << "unreliable PCI chipset found!! " << pci_id << endl; failed = TRUE; break; } @@ -491,20 +507,20 @@ BOOL is_daylight_savings() struct tm* utc_to_pacific_time(time_t utc_time, BOOL pacific_daylight_time) { - S32 pacific_offset_hours; + S32Hours pacific_offset_hours; if (pacific_daylight_time) { - pacific_offset_hours = 7; + pacific_offset_hours = S32Hours(7); } else { - pacific_offset_hours = 8; + pacific_offset_hours = S32Hours(8); } // We subtract off the PST/PDT offset _before_ getting // "UTC" time, because this will handle wrapping around // for 5 AM UTC -> 10 PM PDT of the previous day. - utc_time -= pacific_offset_hours * MIN_PER_HOUR * SEC_PER_MIN; + utc_time -= S32SecondsImplicit(pacific_offset_hours); // Internal buffer to PST/PDT (see above) struct tm* internal_time = gmtime(&utc_time); @@ -521,7 +537,7 @@ struct tm* utc_to_pacific_time(time_t utc_time, BOOL pacific_daylight_time) } -void microsecondsToTimecodeString(U64 current_time, std::string& tcstring) +void microsecondsToTimecodeString(U64MicrosecondsImplicit current_time, std::string& tcstring) { U64 hours; U64 minutes; @@ -543,9 +559,9 @@ void microsecondsToTimecodeString(U64 current_time, std::string& tcstring) } -void secondsToTimecodeString(F32 current_time, std::string& tcstring) +void secondsToTimecodeString(F32SecondsImplicit current_time, std::string& tcstring) { - microsecondsToTimecodeString((U64)((F64)(SEC_TO_MICROSEC*current_time)), tcstring); + microsecondsToTimecodeString(current_time, tcstring); } diff --git a/indra/llcommon/lltimer.h b/indra/llcommon/lltimer.h index e73741217c..ec70213447 100755 --- a/indra/llcommon/lltimer.h +++ b/indra/llcommon/lltimer.h @@ -37,6 +37,7 @@ #include <string> #include <list> // units conversions +#include "llunits.h" #ifndef USEC_PER_SEC const U32 USEC_PER_SEC = 1000000; #endif @@ -55,27 +56,34 @@ public: protected: U64 mLastClockCount; U64 mExpirationTicks; - BOOL mStarted; + bool mStarted; public: LLTimer(); ~LLTimer(); - static void initClass() { if (!sTimer) sTimer = new LLTimer; } - static void cleanupClass() { delete sTimer; sTimer = NULL; } + static void initClass(); + static void cleanupClass(); // Return a high precision number of seconds since the start of // this application instance. - static F64 getElapsedSeconds() + static F64SecondsImplicit getElapsedSeconds() + { + if (sTimer) { return sTimer->getElapsedTimeF64(); } + else + { + return 0; + } + } // Return a high precision usec since epoch - static U64 getTotalTime(); + static U64MicrosecondsImplicit getTotalTime(); // Return a high precision seconds since epoch - static F64 getTotalSeconds(); + static F64SecondsImplicit getTotalSeconds(); // MANIPULATORS @@ -83,21 +91,21 @@ public: void stop() { mStarted = FALSE; } void reset(); // Resets the timer void setLastClockCount(U64 current_count); // Sets the timer so that the next elapsed call will be relative to this time - void setTimerExpirySec(F32 expiration); + void setTimerExpirySec(F32SecondsImplicit expiration); BOOL checkExpirationAndReset(F32 expiration); BOOL hasExpired() const; - F32 getElapsedTimeAndResetF32(); // Returns elapsed time in seconds with reset - F64 getElapsedTimeAndResetF64(); + F32SecondsImplicit getElapsedTimeAndResetF32(); // Returns elapsed time in seconds with reset + F64SecondsImplicit getElapsedTimeAndResetF64(); - F32 getRemainingTimeF32() const; + F32SecondsImplicit getRemainingTimeF32() const; static BOOL knownBadTimer(); // ACCESSORS - F32 getElapsedTimeF32() const; // Returns elapsed time in seconds - F64 getElapsedTimeF64() const; // Returns elapsed time in seconds + F32SecondsImplicit getElapsedTimeF32() const; // Returns elapsed time in seconds + F64SecondsImplicit getElapsedTimeF64() const; // Returns elapsed time in seconds - BOOL getStarted() const { return mStarted; } + bool getStarted() const { return mStarted; } static U64 getCurrentClockCount(); // Returns the raw clockticks @@ -106,9 +114,21 @@ public: // // Various functions for initializing/accessing clock and timing stuff. Don't use these without REALLY knowing how they work. // +struct TimerInfo +{ + TimerInfo(); + void update(); + + F64HertzImplicit mClockFrequency; + F64SecondsImplicit mClockFrequencyInv; + F64MicrosecondsImplicit mClocksToMicroseconds; + U64 mTotalTimeClockCount; + U64 mLastTotalTimeClockCount; +}; + +TimerInfo& get_timer_info(); + LL_COMMON_API U64 get_clock_count(); -LL_COMMON_API F64 calc_clock_frequency(U32 msecs); -LL_COMMON_API void update_clock_frequencies(); // Sleep for milliseconds LL_COMMON_API void ms_sleep(U32 ms); @@ -146,13 +166,6 @@ static inline time_t time_max() } } -// These are really statics but they've been global for awhile -// and they're material to other timing classes. If you are -// not implementing a timer class, do not use these directly. -extern LL_COMMON_API F64 gClockFrequency; -extern LL_COMMON_API F64 gClockFrequencyInv; -extern LL_COMMON_API F64 gClocksToMicroseconds; - // Correction factor used by time_corrected() above. extern LL_COMMON_API S32 gUTCOffset; @@ -167,9 +180,9 @@ LL_COMMON_API BOOL is_daylight_savings(); // struct tm* internal_time = utc_to_pacific_time(utc_time, gDaylight); LL_COMMON_API struct tm* utc_to_pacific_time(time_t utc_time, BOOL pacific_daylight_time); -LL_COMMON_API void microsecondsToTimecodeString(U64 current_time, std::string& tcstring); -LL_COMMON_API void secondsToTimecodeString(F32 current_time, std::string& tcstring); +LL_COMMON_API void microsecondsToTimecodeString(U64MicrosecondsImplicit current_time, std::string& tcstring); +LL_COMMON_API void secondsToTimecodeString(F32SecondsImplicit current_time, std::string& tcstring); -U64 LL_COMMON_API totalTime(); // Returns current system time in microseconds +U64MicrosecondsImplicit LL_COMMON_API totalTime(); // Returns current system time in microseconds #endif diff --git a/indra/llcommon/lltrace.cpp b/indra/llcommon/lltrace.cpp new file mode 100644 index 0000000000..54079a4689 --- /dev/null +++ b/indra/llcommon/lltrace.cpp @@ -0,0 +1,86 @@ +/** + * @file lltrace.cpp + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2012, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "lltrace.h" +#include "lltracerecording.h" +#include "lltracethreadrecorder.h" +#include "llfasttimer.h" + +namespace LLTrace +{ + +MemStatHandle gTraceMemStat("LLTrace"); + +StatBase::StatBase( const char* name, const char* description ) +: mName(name), + mDescription(description ? description : "") +{ +#ifndef LL_RELEASE_FOR_DOWNLOAD + if (LLTrace::get_thread_recorder().notNull()) + { + LL_ERRS() << "Attempting to declare trace object after program initialization. Trace objects should be statically initialized." << LL_ENDL; + } +#endif +} + +const char* StatBase::getUnitLabel() const +{ + return ""; +} + +TimeBlockTreeNode::TimeBlockTreeNode() +: mBlock(NULL), + mParent(NULL), + mNeedsSorting(false), + mCollapsed(true) +{} + +void TimeBlockTreeNode::setParent( BlockTimerStatHandle* parent ) +{ + llassert_always(parent != mBlock); + llassert_always(parent != NULL); + + TimeBlockTreeNode* parent_tree_node = get_thread_recorder()->getTimeBlockTreeNode(parent->getIndex()); + if (!parent_tree_node) return; + + if (mParent) + { + std::vector<BlockTimerStatHandle*>& children = mParent->getChildren(); + std::vector<BlockTimerStatHandle*>::iterator found_it = std::find(children.begin(), children.end(), mBlock); + if (found_it != children.end()) + { + children.erase(found_it); + } + } + + mParent = parent; + mBlock->getCurrentAccumulator().mParent = parent; + parent_tree_node->mChildren.push_back(mBlock); + parent_tree_node->mNeedsSorting = true; +} + +} diff --git a/indra/llcommon/lltrace.h b/indra/llcommon/lltrace.h new file mode 100644 index 0000000000..5f1289dad8 --- /dev/null +++ b/indra/llcommon/lltrace.h @@ -0,0 +1,492 @@ +/** + * @file lltrace.h + * @brief Runtime statistics accumulation. + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2012, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLTRACE_H +#define LL_LLTRACE_H + +#include "stdtypes.h" +#include "llpreprocessor.h" + +#include "llmemory.h" +#include "llrefcount.h" +#include "lltraceaccumulators.h" +#include "llthreadlocalstorage.h" +#include "lltimer.h" +#include "llpointer.h" +#include "llunits.h" + +#define LL_TRACE_ENABLED 1 + +namespace LLTrace +{ +class Recording; + +template<typename T> +T storage_value(T val) { return val; } + +template<typename UNIT_TYPE, typename STORAGE_TYPE> +STORAGE_TYPE storage_value(LLUnit<STORAGE_TYPE, UNIT_TYPE> val) { return val.value(); } + +template<typename UNIT_TYPE, typename STORAGE_TYPE> +STORAGE_TYPE storage_value(LLUnitImplicit<STORAGE_TYPE, UNIT_TYPE> val) { return val.value(); } + +class StatBase +{ +public: + StatBase(const char* name, const char* description); + virtual ~StatBase() {}; + virtual const char* getUnitLabel() const; + + const std::string& getName() const { return mName; } + const std::string& getDescription() const { return mDescription; } + +protected: + std::string mName; + std::string mDescription; +}; + +template<typename ACCUMULATOR> +class StatType +: public StatBase, + public LLInstanceTracker<StatType<ACCUMULATOR>, std::string> +{ +public: + typedef LLInstanceTracker<StatType<ACCUMULATOR>, std::string> instance_tracker_t; + StatType(const char* name, const char* description) + : instance_tracker_t(name), + StatBase(name, description), + mAccumulatorIndex(AccumulatorBuffer<ACCUMULATOR>::getDefaultBuffer()->reserveSlot()) + {} + + LL_FORCE_INLINE ACCUMULATOR& getCurrentAccumulator() const + { + ACCUMULATOR* accumulator_storage = LLThreadLocalSingletonPointer<ACCUMULATOR>::getInstance(); + return accumulator_storage ? accumulator_storage[mAccumulatorIndex] : (*AccumulatorBuffer<ACCUMULATOR>::getDefaultBuffer())[mAccumulatorIndex]; + } + + size_t getIndex() const { return mAccumulatorIndex; } + static size_t getNumIndices() { return AccumulatorBuffer<ACCUMULATOR>::getNumIndices(); } + +protected: + const size_t mAccumulatorIndex; +}; + + +template<> +class StatType<TimeBlockAccumulator::CallCountFacet> +: public StatType<TimeBlockAccumulator> +{ +public: + + StatType(const char* name, const char* description = "") + : StatType<TimeBlockAccumulator>(name, description) + {} +}; + +template<> +class StatType<TimeBlockAccumulator::SelfTimeFacet> + : public StatType<TimeBlockAccumulator> +{ +public: + + StatType(const char* name, const char* description = "") + : StatType<TimeBlockAccumulator>(name, description) + {} +}; + +template <typename T = F64> +class EventStatHandle +: public StatType<EventAccumulator> +{ +public: + typedef F64 storage_t; + typedef StatType<EventAccumulator> stat_t; + typedef EventStatHandle<T> self_t; + + EventStatHandle(const char* name, const char* description = NULL) + : stat_t(name, description) + {} + + /*virtual*/ const char* getUnitLabel() const { return LLGetUnitLabel<T>::getUnitLabel(); } + +}; + +template<typename T, typename VALUE_T> +void record(EventStatHandle<T>& measurement, VALUE_T value) +{ +#if LL_TRACE_ENABLED + T converted_value(value); + measurement.getCurrentAccumulator().record(storage_value(converted_value)); +#endif +} + +template <typename T = F64> +class SampleStatHandle +: public StatType<SampleAccumulator> +{ +public: + typedef F64 storage_t; + typedef StatType<SampleAccumulator> stat_t; + typedef SampleStatHandle<T> self_t; + + SampleStatHandle(const char* name, const char* description = NULL) + : stat_t(name, description) + {} + + /*virtual*/ const char* getUnitLabel() const { return LLGetUnitLabel<T>::getUnitLabel(); } +}; + +template<typename T, typename VALUE_T> +void sample(SampleStatHandle<T>& measurement, VALUE_T value) +{ +#if LL_TRACE_ENABLED + T converted_value(value); + measurement.getCurrentAccumulator().sample(storage_value(converted_value)); +#endif +} + +template <typename T = F64> +class CountStatHandle +: public StatType<CountAccumulator> +{ +public: + typedef F64 storage_t; + typedef StatType<CountAccumulator> stat_t; + typedef CountStatHandle<T> self_t; + + CountStatHandle(const char* name, const char* description = NULL) + : stat_t(name, description) + {} + + /*virtual*/ const char* getUnitLabel() const { return LLGetUnitLabel<T>::getUnitLabel(); } +}; + +template<typename T, typename VALUE_T> +void add(CountStatHandle<T>& count, VALUE_T value) +{ +#if LL_TRACE_ENABLED + T converted_value(value); + count.getCurrentAccumulator().add(storage_value(converted_value)); +#endif +} + +template<> +class StatType<MemAccumulator::AllocationFacet> +: public StatType<MemAccumulator> +{ +public: + + StatType(const char* name, const char* description = "") + : StatType<MemAccumulator>(name, description) + {} +}; + +template<> +class StatType<MemAccumulator::DeallocationFacet> +: public StatType<MemAccumulator> +{ +public: + + StatType(const char* name, const char* description = "") + : StatType<MemAccumulator>(name, description) + {} +}; + +class MemStatHandle : public StatType<MemAccumulator> +{ +public: + typedef StatType<MemAccumulator> stat_t; + MemStatHandle(const char* name, const char* description = "") + : stat_t(name, description) + { + mName = name; + } + + void setName(const char* name) + { + mName = name; + setKey(name); + } + + /*virtual*/ const char* getUnitLabel() const { return "KB"; } + + StatType<MemAccumulator::AllocationFacet>& allocations() + { + return static_cast<StatType<MemAccumulator::AllocationFacet>&>(*(StatType<MemAccumulator>*)this); + } + + StatType<MemAccumulator::DeallocationFacet>& deallocations() + { + return static_cast<StatType<MemAccumulator::DeallocationFacet>&>(*(StatType<MemAccumulator>*)this); + } +}; + + +// measures effective memory footprint of specified type +// specialize to cover different types +template<typename T, typename IS_MEM_TRACKABLE = void, typename IS_UNITS = void> +struct MeasureMem +{ + static size_t measureFootprint(const T& value) + { + return sizeof(T); + } +}; + +template<typename T, typename IS_BYTES> +struct MeasureMem<T, typename T::mem_trackable_tag_t, IS_BYTES> +{ + static size_t measureFootprint(const T& value) + { + return sizeof(T) + value.getMemFootprint(); + } +}; + +template<typename T, typename IS_MEM_TRACKABLE> +struct MeasureMem<T, IS_MEM_TRACKABLE, typename T::is_unit_t> +{ + static size_t measureFootprint(const T& value) + { + return U32Bytes(value).value(); + } +}; + +template<typename T, typename IS_MEM_TRACKABLE, typename IS_BYTES> +struct MeasureMem<T*, IS_MEM_TRACKABLE, IS_BYTES> +{ + static size_t measureFootprint(const T* value) + { + if (!value) + { + return 0; + } + return MeasureMem<T>::measureFootprint(*value); + } +}; + +template<typename T, typename IS_MEM_TRACKABLE, typename IS_BYTES> +struct MeasureMem<LLPointer<T>, IS_MEM_TRACKABLE, IS_BYTES> +{ + static size_t measureFootprint(const LLPointer<T> value) + { + if (value.isNull()) + { + return 0; + } + return MeasureMem<T>::measureFootprint(*value); + } +}; + +template<typename IS_MEM_TRACKABLE, typename IS_BYTES> +struct MeasureMem<S32, IS_MEM_TRACKABLE, IS_BYTES> +{ + static size_t measureFootprint(S32 value) + { + return value; + } +}; + +template<typename IS_MEM_TRACKABLE, typename IS_BYTES> +struct MeasureMem<U32, IS_MEM_TRACKABLE, IS_BYTES> +{ + static size_t measureFootprint(U32 value) + { + return value; + } +}; + +template<typename T, typename IS_MEM_TRACKABLE, typename IS_BYTES> +struct MeasureMem<std::basic_string<T>, IS_MEM_TRACKABLE, IS_BYTES> +{ + static size_t measureFootprint(const std::basic_string<T>& value) + { + return value.capacity() * sizeof(T); + } +}; + + +template<typename T> +inline void claim_alloc(MemStatHandle& measurement, const T& value) +{ +#if LL_TRACE_ENABLED + S32 size = MeasureMem<T>::measureFootprint(value); + if(size == 0) return; + MemAccumulator& accumulator = measurement.getCurrentAccumulator(); + accumulator.mSize.sample(accumulator.mSize.hasValue() ? accumulator.mSize.getLastValue() + (F64)size : (F64)size); + accumulator.mAllocations.record(size); +#endif +} + +template<typename T> +inline void disclaim_alloc(MemStatHandle& measurement, const T& value) +{ +#if LL_TRACE_ENABLED + S32 size = MeasureMem<T>::measureFootprint(value); + if(size == 0) return; + MemAccumulator& accumulator = measurement.getCurrentAccumulator(); + accumulator.mSize.sample(accumulator.mSize.hasValue() ? accumulator.mSize.getLastValue() - (F64)size : -(F64)size); + accumulator.mDeallocations.add(size); +#endif +} + +template<typename DERIVED, size_t ALIGNMENT = LL_DEFAULT_HEAP_ALIGN> +class MemTrackableNonVirtual +{ +public: + typedef void mem_trackable_tag_t; + + MemTrackableNonVirtual(const char* name) +#if LL_TRACE_ENABLED + : mMemFootprint(0) +#endif + { +#if LL_TRACE_ENABLED + static bool name_initialized = false; + if (!name_initialized) + { + name_initialized = true; + sMemStat.setName(name); + } +#endif + } + +#if LL_TRACE_ENABLED + ~MemTrackableNonVirtual() + { + disclaimMem(mMemFootprint); + } + + static MemStatHandle& getMemStatHandle() + { + return sMemStat; + } + + S32 getMemFootprint() const { return mMemFootprint; } +#endif + + void* operator new(size_t size) + { +#if LL_TRACE_ENABLED + claim_alloc(sMemStat, size); +#endif + return ll_aligned_malloc<ALIGNMENT>(size); + } + + template<int CUSTOM_ALIGNMENT> + static void* aligned_new(size_t size) + { +#if LL_TRACE_ENABLED + claim_alloc(sMemStat, size); +#endif + return ll_aligned_malloc<CUSTOM_ALIGNMENT>(size); + } + + void operator delete(void* ptr, size_t size) + { +#if LL_TRACE_ENABLED + disclaim_alloc(sMemStat, size); +#endif + ll_aligned_free<ALIGNMENT>(ptr); + } + + template<int CUSTOM_ALIGNMENT> + static void aligned_delete(void* ptr, size_t size) + { +#if LL_TRACE_ENABLED + disclaim_alloc(sMemStat, size); +#endif + ll_aligned_free<CUSTOM_ALIGNMENT>(ptr); + } + + void* operator new [](size_t size) + { +#if LL_TRACE_ENABLED + claim_alloc(sMemStat, size); +#endif + return ll_aligned_malloc<ALIGNMENT>(size); + } + + void operator delete[](void* ptr, size_t size) + { +#if LL_TRACE_ENABLED + disclaim_alloc(sMemStat, size); +#endif + ll_aligned_free<ALIGNMENT>(ptr); + } + + // claim memory associated with other objects/data as our own, adding to our calculated footprint + template<typename CLAIM_T> + void claimMem(const CLAIM_T& value) const + { +#if LL_TRACE_ENABLED + S32 size = MeasureMem<CLAIM_T>::measureFootprint(value); + claim_alloc(sMemStat, size); + mMemFootprint += size; +#endif + } + + // remove memory we had claimed from our calculated footprint + template<typename CLAIM_T> + void disclaimMem(const CLAIM_T& value) const + { +#if LL_TRACE_ENABLED + S32 size = MeasureMem<CLAIM_T>::measureFootprint(value); + disclaim_alloc(sMemStat, size); + mMemFootprint -= size; +#endif + } + +private: +#if LL_TRACE_ENABLED + // use signed values so that we can temporarily go negative + // and reconcile in destructor + // NB: this assumes that no single class is responsible for > 2GB of allocations + mutable S32 mMemFootprint; + + static MemStatHandle sMemStat; +#endif + +}; + +#if LL_TRACE_ENABLED +template<typename DERIVED, size_t ALIGNMENT> +MemStatHandle MemTrackableNonVirtual<DERIVED, ALIGNMENT>::sMemStat(typeid(MemTrackableNonVirtual<DERIVED, ALIGNMENT>).name()); +#endif + +template<typename DERIVED, size_t ALIGNMENT = LL_DEFAULT_HEAP_ALIGN> +class MemTrackable : public MemTrackableNonVirtual<DERIVED, ALIGNMENT> +{ +public: + MemTrackable(const char* name) + : MemTrackableNonVirtual<DERIVED, ALIGNMENT>(name) + {} + + virtual ~MemTrackable() + {} +}; +} + +#endif // LL_LLTRACE_H diff --git a/indra/llcommon/lltraceaccumulators.cpp b/indra/llcommon/lltraceaccumulators.cpp new file mode 100644 index 0000000000..385d31edd7 --- /dev/null +++ b/indra/llcommon/lltraceaccumulators.cpp @@ -0,0 +1,302 @@ +/** + * @file lltracesampler.cpp + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2012, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "lltraceaccumulators.h" +#include "lltrace.h" +#include "lltracethreadrecorder.h" + +namespace LLTrace +{ + +extern MemStatHandle gTraceMemStat; + + +/////////////////////////////////////////////////////////////////////// +// AccumulatorBufferGroup +/////////////////////////////////////////////////////////////////////// + +AccumulatorBufferGroup::AccumulatorBufferGroup() +{ + claim_alloc(gTraceMemStat, mCounts.capacity() * sizeof(CountAccumulator)); + claim_alloc(gTraceMemStat, mSamples.capacity() * sizeof(SampleAccumulator)); + claim_alloc(gTraceMemStat, mEvents.capacity() * sizeof(EventAccumulator)); + claim_alloc(gTraceMemStat, mStackTimers.capacity() * sizeof(TimeBlockAccumulator)); + claim_alloc(gTraceMemStat, mMemStats.capacity() * sizeof(MemAccumulator)); +} + +AccumulatorBufferGroup::AccumulatorBufferGroup(const AccumulatorBufferGroup& other) +: mCounts(other.mCounts), + mSamples(other.mSamples), + mEvents(other.mEvents), + mStackTimers(other.mStackTimers), + mMemStats(other.mMemStats) +{ + claim_alloc(gTraceMemStat, mCounts.capacity() * sizeof(CountAccumulator)); + claim_alloc(gTraceMemStat, mSamples.capacity() * sizeof(SampleAccumulator)); + claim_alloc(gTraceMemStat, mEvents.capacity() * sizeof(EventAccumulator)); + claim_alloc(gTraceMemStat, mStackTimers.capacity() * sizeof(TimeBlockAccumulator)); + claim_alloc(gTraceMemStat, mMemStats.capacity() * sizeof(MemAccumulator)); +} + +AccumulatorBufferGroup::~AccumulatorBufferGroup() +{ + disclaim_alloc(gTraceMemStat, mCounts.capacity() * sizeof(CountAccumulator)); + disclaim_alloc(gTraceMemStat, mSamples.capacity() * sizeof(SampleAccumulator)); + disclaim_alloc(gTraceMemStat, mEvents.capacity() * sizeof(EventAccumulator)); + disclaim_alloc(gTraceMemStat, mStackTimers.capacity() * sizeof(TimeBlockAccumulator)); + disclaim_alloc(gTraceMemStat, mMemStats.capacity() * sizeof(MemAccumulator)); +} + +void AccumulatorBufferGroup::handOffTo(AccumulatorBufferGroup& other) +{ + other.mCounts.reset(&mCounts); + other.mSamples.reset(&mSamples); + other.mEvents.reset(&mEvents); + other.mStackTimers.reset(&mStackTimers); + other.mMemStats.reset(&mMemStats); +} + +void AccumulatorBufferGroup::makeCurrent() +{ + mCounts.makeCurrent(); + mSamples.makeCurrent(); + mEvents.makeCurrent(); + mStackTimers.makeCurrent(); + mMemStats.makeCurrent(); + + ThreadRecorder* thread_recorder = get_thread_recorder().get(); + AccumulatorBuffer<TimeBlockAccumulator>& timer_accumulator_buffer = mStackTimers; + // update stacktimer parent pointers + for (S32 i = 0, end_i = mStackTimers.size(); i < end_i; i++) + { + TimeBlockTreeNode* tree_node = thread_recorder->getTimeBlockTreeNode(i); + if (tree_node) + { + timer_accumulator_buffer[i].mParent = tree_node->mParent; + } + } +} + +//static +void AccumulatorBufferGroup::clearCurrent() +{ + AccumulatorBuffer<CountAccumulator>::clearCurrent(); + AccumulatorBuffer<SampleAccumulator>::clearCurrent(); + AccumulatorBuffer<EventAccumulator>::clearCurrent(); + AccumulatorBuffer<TimeBlockAccumulator>::clearCurrent(); + AccumulatorBuffer<MemAccumulator>::clearCurrent(); +} + +bool AccumulatorBufferGroup::isCurrent() const +{ + return mCounts.isCurrent(); +} + +void AccumulatorBufferGroup::append( const AccumulatorBufferGroup& other ) +{ + mCounts.addSamples(other.mCounts, SEQUENTIAL); + mSamples.addSamples(other.mSamples, SEQUENTIAL); + mEvents.addSamples(other.mEvents, SEQUENTIAL); + mMemStats.addSamples(other.mMemStats, SEQUENTIAL); + mStackTimers.addSamples(other.mStackTimers, SEQUENTIAL); +} + +void AccumulatorBufferGroup::merge( const AccumulatorBufferGroup& other) +{ + mCounts.addSamples(other.mCounts, NON_SEQUENTIAL); + mSamples.addSamples(other.mSamples, NON_SEQUENTIAL); + mEvents.addSamples(other.mEvents, NON_SEQUENTIAL); + mMemStats.addSamples(other.mMemStats, NON_SEQUENTIAL); + // for now, hold out timers from merge, need to be displayed per thread + //mStackTimers.addSamples(other.mStackTimers, NON_SEQUENTIAL); +} + +void AccumulatorBufferGroup::reset(AccumulatorBufferGroup* other) +{ + mCounts.reset(other ? &other->mCounts : NULL); + mSamples.reset(other ? &other->mSamples : NULL); + mEvents.reset(other ? &other->mEvents : NULL); + mStackTimers.reset(other ? &other->mStackTimers : NULL); + mMemStats.reset(other ? &other->mMemStats : NULL); +} + +void AccumulatorBufferGroup::sync() +{ + if (isCurrent()) + { + F64SecondsImplicit time_stamp = LLTimer::getTotalSeconds(); + + mSamples.sync(time_stamp); + mMemStats.sync(time_stamp); + } +} + +F64 SampleAccumulator::mergeSumsOfSquares(const SampleAccumulator& a, const SampleAccumulator& b) +{ + const F64 epsilon = 0.0000001; + + if (a.getSamplingTime() > epsilon && b.getSamplingTime() > epsilon) + { + // combine variance (and hence standard deviation) of 2 different sized sample groups using + // the following formula: http://www.mrc-bsu.cam.ac.uk/cochrane/handbook/chapter_7/7_7_3_8_combining_groups.htm + F64 n_1 = a.getSamplingTime(), + n_2 = b.getSamplingTime(); + F64 m_1 = a.getMean(), + m_2 = b.getMean(); + F64 v_1 = a.getSumOfSquares() / a.getSamplingTime(), + v_2 = b.getSumOfSquares() / b.getSamplingTime(); + if (n_1 < epsilon) + { + return b.getSumOfSquares(); + } + else + { + return a.getSamplingTime() + * ((((n_1 - epsilon) * v_1) + + ((n_2 - epsilon) * v_2) + + (((n_1 * n_2) / (n_1 + n_2)) + * ((m_1 * m_1) + (m_2 * m_2) - (2.f * m_1 * m_2)))) + / (n_1 + n_2 - epsilon)); + } + } + + return a.getSumOfSquares(); +} + + +void SampleAccumulator::addSamples( const SampleAccumulator& other, EBufferAppendType append_type ) +{ + if (append_type == NON_SEQUENTIAL) + { + return; + } + + if (!mHasValue) + { + *this = other; + + if (append_type == NON_SEQUENTIAL) + { + // restore own last value state + mLastValue = NaN; + mHasValue = false; + } + } + else if (other.mHasValue) + { + mSum += other.mSum; + + if (other.mMin < mMin) { mMin = other.mMin; } + if (other.mMax > mMax) { mMax = other.mMax; } + + mSumOfSquares = mergeSumsOfSquares(*this, other); + + if (append_type == SEQUENTIAL) + { + mLastValue = other.mLastValue; + mLastSampleTimeStamp = other.mLastSampleTimeStamp; + } + } +} + +void SampleAccumulator::reset( const SampleAccumulator* other ) +{ + mLastValue = other ? other->mLastValue : NaN; + mHasValue = other ? other->mHasValue : false; + mNumSamples = 0; + mSum = 0; + mMin = mLastValue; + mMax = mLastValue; + mMean = mLastValue; + llassert(!mHasValue || mMean < 0 || mMean >= 0); + mSumOfSquares = 0; + mLastSampleTimeStamp = LLTimer::getTotalSeconds(); + mTotalSamplingTime = 0; +} + +F64 EventAccumulator::mergeSumsOfSquares(const EventAccumulator& a, const EventAccumulator& b) +{ + if (a.mNumSamples && b.mNumSamples) + { + // combine variance (and hence standard deviation) of 2 different sized sample groups using + // the following formula: http://www.mrc-bsu.cam.ac.uk/cochrane/handbook/chapter_7/7_7_3_8_combining_groups.htm + F64 n_1 = a.mNumSamples, + n_2 = b.mNumSamples; + F64 m_1 = a.mMean, + m_2 = b.mMean; + F64 v_1 = a.mSumOfSquares / a.mNumSamples, + v_2 = b.mSumOfSquares / b.mNumSamples; + return (F64)a.mNumSamples + * ((((n_1 - 1.f) * v_1) + + ((n_2 - 1.f) * v_2) + + (((n_1 * n_2) / (n_1 + n_2)) + * ((m_1 * m_1) + (m_2 * m_2) - (2.f * m_1 * m_2)))) + / (n_1 + n_2 - 1.f)); + } + + return a.mSumOfSquares; +} + +void EventAccumulator::addSamples( const EventAccumulator& other, EBufferAppendType append_type ) +{ + if (other.mNumSamples) + { + if (!mNumSamples) + { + *this = other; + } + else + { + mSum += other.mSum; + + // NOTE: both conditions will hold first time through + if (other.mMin < mMin) { mMin = other.mMin; } + if (other.mMax > mMax) { mMax = other.mMax; } + + mSumOfSquares = mergeSumsOfSquares(*this, other); + + F64 weight = (F64)mNumSamples / (F64)(mNumSamples + other.mNumSamples); + mNumSamples += other.mNumSamples; + mMean = mMean * weight + other.mMean * (1.f - weight); + if (append_type == SEQUENTIAL) mLastValue = other.mLastValue; + } + } +} + +void EventAccumulator::reset( const EventAccumulator* other ) +{ + mNumSamples = 0; + mSum = 0; + mMin = NaN; + mMax = NaN; + mMean = NaN; + mSumOfSquares = 0; + mLastValue = other ? other->mLastValue : NaN; +} + + +} diff --git a/indra/llcommon/lltraceaccumulators.h b/indra/llcommon/lltraceaccumulators.h new file mode 100644 index 0000000000..42fad8a793 --- /dev/null +++ b/indra/llcommon/lltraceaccumulators.h @@ -0,0 +1,590 @@ + +/** + * @file lltraceaccumulators.h + * @brief Storage for accumulating statistics + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2012, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLTRACEACCUMULATORS_H +#define LL_LLTRACEACCUMULATORS_H + + +#include "stdtypes.h" +#include "llpreprocessor.h" +#include "llunits.h" +#include "lltimer.h" +#include "llrefcount.h" +#include "llthreadlocalstorage.h" +#include "llmemory.h" +#include <limits> + +namespace LLTrace +{ + const F64 NaN = std::numeric_limits<double>::quiet_NaN(); + + enum EBufferAppendType + { + SEQUENTIAL, + NON_SEQUENTIAL + }; + + template<typename ACCUMULATOR> + class AccumulatorBuffer : public LLRefCount + { + typedef AccumulatorBuffer<ACCUMULATOR> self_t; + static const S32 DEFAULT_ACCUMULATOR_BUFFER_SIZE = 32; + private: + struct StaticAllocationMarker { }; + + AccumulatorBuffer(StaticAllocationMarker m) + : mStorageSize(0), + mStorage(NULL) + {} + + public: + + AccumulatorBuffer(const AccumulatorBuffer& other = *getDefaultBuffer()) + : mStorageSize(0), + mStorage(NULL) + { + resize(sNextStorageSlot); + for (S32 i = 0; i < sNextStorageSlot; i++) + { + mStorage[i] = other.mStorage[i]; + } + } + + ~AccumulatorBuffer() + { + if (isCurrent()) + { + LLThreadLocalSingletonPointer<ACCUMULATOR>::setInstance(NULL); + } + delete[] mStorage; + } + + LL_FORCE_INLINE ACCUMULATOR& operator[](size_t index) + { + return mStorage[index]; + } + + LL_FORCE_INLINE const ACCUMULATOR& operator[](size_t index) const + { + return mStorage[index]; + } + + void addSamples(const AccumulatorBuffer<ACCUMULATOR>& other, EBufferAppendType append_type) + { + llassert(mStorageSize >= sNextStorageSlot && other.mStorageSize >= sNextStorageSlot); + for (size_t i = 0; i < sNextStorageSlot; i++) + { + mStorage[i].addSamples(other.mStorage[i], append_type); + } + } + + void copyFrom(const AccumulatorBuffer<ACCUMULATOR>& other) + { + llassert(mStorageSize >= sNextStorageSlot && other.mStorageSize >= sNextStorageSlot); + for (size_t i = 0; i < sNextStorageSlot; i++) + { + mStorage[i] = other.mStorage[i]; + } + } + + void reset(const AccumulatorBuffer<ACCUMULATOR>* other = NULL) + { + llassert(mStorageSize >= sNextStorageSlot); + for (size_t i = 0; i < sNextStorageSlot; i++) + { + mStorage[i].reset(other ? &other->mStorage[i] : NULL); + } + } + + void sync(F64SecondsImplicit time_stamp) + { + llassert(mStorageSize >= sNextStorageSlot); + for (size_t i = 0; i < sNextStorageSlot; i++) + { + mStorage[i].sync(time_stamp); + } + } + + void makeCurrent() + { + LLThreadLocalSingletonPointer<ACCUMULATOR>::setInstance(mStorage); + } + + bool isCurrent() const + { + return LLThreadLocalSingletonPointer<ACCUMULATOR>::getInstance() == mStorage; + } + + static void clearCurrent() + { + LLThreadLocalSingletonPointer<ACCUMULATOR>::setInstance(NULL); + } + + // NOTE: this is not thread-safe. We assume that slots are reserved in the main thread before any child threads are spawned + size_t reserveSlot() + { + size_t next_slot = sNextStorageSlot++; + if (next_slot >= mStorageSize) + { + // don't perform doubling, as this should only happen during startup + // want to keep a tight bounds as we will have a lot of these buffers + resize(mStorageSize + mStorageSize / 2); + } + llassert(mStorage && next_slot < mStorageSize); + return next_slot; + } + + void resize(size_t new_size) + { + if (new_size <= mStorageSize) return; + + ACCUMULATOR* old_storage = mStorage; + mStorage = new ACCUMULATOR[new_size]; + if (old_storage) + { + for (S32 i = 0; i < mStorageSize; i++) + { + mStorage[i] = old_storage[i]; + } + } + mStorageSize = new_size; + delete[] old_storage; + + self_t* default_buffer = getDefaultBuffer(); + if (this != default_buffer + && new_size > default_buffer->size()) + { + //NB: this is not thread safe, but we assume that all resizing occurs during static initialization + default_buffer->resize(new_size); + } + } + + size_t size() const + { + return getNumIndices(); + } + + size_t capacity() const + { + return mStorageSize; + } + + static size_t getNumIndices() + { + return sNextStorageSlot; + } + + static self_t* getDefaultBuffer() + { + static bool sInitialized = false; + if (!sInitialized) + { + // this buffer is allowed to leak so that trace calls from global destructors have somewhere to put their data + // so as not to trigger an access violation + sDefaultBuffer = new AccumulatorBuffer(StaticAllocationMarker()); + sInitialized = true; + sDefaultBuffer->resize(DEFAULT_ACCUMULATOR_BUFFER_SIZE); + } + return sDefaultBuffer; + } + + private: + ACCUMULATOR* mStorage; + size_t mStorageSize; + static size_t sNextStorageSlot; + static self_t* sDefaultBuffer; + }; + + template<typename ACCUMULATOR> size_t AccumulatorBuffer<ACCUMULATOR>::sNextStorageSlot = 0; + template<typename ACCUMULATOR> AccumulatorBuffer<ACCUMULATOR>* AccumulatorBuffer<ACCUMULATOR>::sDefaultBuffer = NULL; + + class EventAccumulator + { + public: + typedef F64 value_t; + static F64 getDefaultValue() { return NaN; } + + EventAccumulator() + : mSum(0), + mMin(NaN), + mMax(NaN), + mMean(NaN), + mSumOfSquares(0), + mNumSamples(0), + mLastValue(NaN) + {} + + void record(F64 value) + { + if (mNumSamples == 0) + { + mSum = value; + mMean = value; + mMin = value; + mMax = value; + } + else + { + mSum += value; + F64 old_mean = mMean; + mMean += (value - old_mean) / (F64)mNumSamples; + mSumOfSquares += (value - old_mean) * (value - mMean); + + if (value < mMin) { mMin = value; } + else if (value > mMax) { mMax = value; } + } + + mNumSamples++; + mLastValue = value; + } + + void addSamples(const EventAccumulator& other, EBufferAppendType append_type); + void reset(const EventAccumulator* other); + void sync(F64SecondsImplicit) {} + + F64 getSum() const { return mSum; } + F32 getMin() const { return mMin; } + F32 getMax() const { return mMax; } + F64 getLastValue() const { return mLastValue; } + F64 getMean() const { return mMean; } + F64 getStandardDeviation() const { return sqrtf(mSumOfSquares / mNumSamples); } + F64 getSumOfSquares() const { return mSumOfSquares; } + S32 getSampleCount() const { return mNumSamples; } + bool hasValue() const { return mNumSamples > 0; } + + // helper utility to calculate combined sumofsquares total + static F64 mergeSumsOfSquares(const EventAccumulator& a, const EventAccumulator& b); + + private: + F64 mSum, + mLastValue; + + F64 mMean, + mSumOfSquares; + + F32 mMin, + mMax; + + S32 mNumSamples; + }; + + + class SampleAccumulator + { + public: + typedef F64 value_t; + static F64 getDefaultValue() { return NaN; } + + SampleAccumulator() + : mSum(0), + mMin(NaN), + mMax(NaN), + mMean(NaN), + mSumOfSquares(0), + mLastSampleTimeStamp(0), + mTotalSamplingTime(0), + mNumSamples(0), + mLastValue(NaN), + mHasValue(false) + {} + + void sample(F64 value) + { + F64SecondsImplicit time_stamp = LLTimer::getTotalSeconds(); + + // store effect of last value + sync(time_stamp); + + if (!mHasValue) + { + mHasValue = true; + + mMin = value; + mMax = value; + mMean = value; + mLastSampleTimeStamp = time_stamp; + } + else + { + if (value < mMin) { mMin = value; } + else if (value > mMax) { mMax = value; } + } + + mLastValue = value; + mNumSamples++; + } + + void addSamples(const SampleAccumulator& other, EBufferAppendType append_type); + void reset(const SampleAccumulator* other); + + void sync(F64SecondsImplicit time_stamp) + { + if (mHasValue && time_stamp != mLastSampleTimeStamp) + { + F64SecondsImplicit delta_time = time_stamp - mLastSampleTimeStamp; + mSum += mLastValue * delta_time; + mTotalSamplingTime += delta_time; + F64 old_mean = mMean; + mMean += (delta_time / mTotalSamplingTime) * (mLastValue - old_mean); + mSumOfSquares += delta_time * (mLastValue - old_mean) * (mLastValue - mMean); + } + mLastSampleTimeStamp = time_stamp; + } + + F64 getSum() const { return mSum; } + F32 getMin() const { return mMin; } + F32 getMax() const { return mMax; } + F64 getLastValue() const { return mLastValue; } + F64 getMean() const { return mMean; } + F64 getStandardDeviation() const { return sqrtf(mSumOfSquares / mTotalSamplingTime); } + F64 getSumOfSquares() const { return mSumOfSquares; } + F64SecondsImplicit getSamplingTime() const { return mTotalSamplingTime; } + S32 getSampleCount() const { return mNumSamples; } + bool hasValue() const { return mHasValue; } + + // helper utility to calculate combined sumofsquares total + static F64 mergeSumsOfSquares(const SampleAccumulator& a, const SampleAccumulator& b); + + private: + F64 mSum, + mLastValue; + + F64 mMean, + mSumOfSquares; + + F64SecondsImplicit + mLastSampleTimeStamp, + mTotalSamplingTime; + + F32 mMin, + mMax; + + S32 mNumSamples; + // distinct from mNumSamples, since we might have inherited a last value from + // a previous sampling period + bool mHasValue; + }; + + class CountAccumulator + { + public: + typedef F64 value_t; + static F64 getDefaultValue() { return 0; } + + CountAccumulator() + : mSum(0), + mNumSamples(0) + {} + + void add(F64 value) + { + mNumSamples++; + mSum += value; + } + + void addSamples(const CountAccumulator& other, EBufferAppendType /*type*/) + { + mSum += other.mSum; + mNumSamples += other.mNumSamples; + } + + void reset(const CountAccumulator* other) + { + mNumSamples = 0; + mSum = 0; + } + + void sync(F64SecondsImplicit) {} + + F64 getSum() const { return mSum; } + + S32 getSampleCount() const { return mNumSamples; } + + bool hasValue() const { return true; } + + private: + F64 mSum; + + S32 mNumSamples; + }; + + class TimeBlockAccumulator + { + public: + typedef F64Seconds value_t; + static F64Seconds getDefaultValue() { return F64Seconds(0); } + + typedef TimeBlockAccumulator self_t; + + // fake classes that allows us to view different facets of underlying statistic + struct CallCountFacet + { + typedef S32 value_t; + }; + + struct SelfTimeFacet + { + typedef F64Seconds value_t; + }; + + // arrays are allocated with 32 byte alignment + void *operator new [](size_t size) + { + return ll_aligned_malloc<32>(size); + } + + void operator delete[](void* ptr, size_t size) + { + ll_aligned_free<32>(ptr); + } + + TimeBlockAccumulator(); + void addSamples(const self_t& other, EBufferAppendType append_type); + void reset(const self_t* other); + void sync(F64SecondsImplicit) {} + bool hasValue() const { return true; } + + // + // members + // + U64 mTotalTimeCounter, + mSelfTimeCounter; + S32 mCalls; + class BlockTimerStatHandle* mParent; // last acknowledged parent of this time block + class BlockTimerStatHandle* mLastCaller; // used to bootstrap tree construction + 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 + + }; + + class BlockTimerStatHandle; + + class TimeBlockTreeNode + { + public: + TimeBlockTreeNode(); + + void setParent(BlockTimerStatHandle* parent); + BlockTimerStatHandle* getParent() { return mParent; } + + BlockTimerStatHandle* mBlock; + BlockTimerStatHandle* mParent; + std::vector<BlockTimerStatHandle*> mChildren; + bool mCollapsed; + bool mNeedsSorting; + }; + + struct BlockTimerStackRecord + { + class BlockTimer* mActiveTimer; + class BlockTimerStatHandle* mTimeBlock; + U64 mChildTime; + }; + + struct MemAccumulator + { + typedef F64Bytes value_t; + static F64Bytes getDefaultValue() { return F64Bytes(0); } + + typedef MemAccumulator self_t; + + // fake classes that allows us to view different facets of underlying statistic + struct AllocationFacet + { + typedef F64Bytes value_t; + static F64Bytes getDefaultValue() { return F64Bytes(0); } + }; + + struct DeallocationFacet + { + typedef F64Bytes value_t; + static F64Bytes getDefaultValue() { return F64Bytes(0); } + }; + + void addSamples(const MemAccumulator& other, EBufferAppendType append_type) + { + mAllocations.addSamples(other.mAllocations, append_type); + mDeallocations.addSamples(other.mDeallocations, append_type); + + if (append_type == SEQUENTIAL) + { + mSize.addSamples(other.mSize, SEQUENTIAL); + } + else + { + F64 allocation_delta(other.mAllocations.getSum() - other.mDeallocations.getSum()); + mSize.sample(mSize.hasValue() + ? mSize.getLastValue() + allocation_delta + : allocation_delta); + } + } + + void reset(const MemAccumulator* other) + { + mSize.reset(other ? &other->mSize : NULL); + mAllocations.reset(other ? &other->mAllocations : NULL); + mDeallocations.reset(other ? &other->mDeallocations : NULL); + } + + void sync(F64SecondsImplicit time_stamp) + { + mSize.sync(time_stamp); + } + + bool hasValue() const { return mSize.hasValue(); } + + SampleAccumulator mSize; + EventAccumulator mAllocations; + CountAccumulator mDeallocations; + }; + + struct AccumulatorBufferGroup : public LLRefCount + { + AccumulatorBufferGroup(); + AccumulatorBufferGroup(const AccumulatorBufferGroup&); + ~AccumulatorBufferGroup(); + + void handOffTo(AccumulatorBufferGroup& other); + void makeCurrent(); + bool isCurrent() const; + static void clearCurrent(); + + void append(const AccumulatorBufferGroup& other); + void merge(const AccumulatorBufferGroup& other); + void reset(AccumulatorBufferGroup* other = NULL); + void sync(); + + AccumulatorBuffer<CountAccumulator> mCounts; + AccumulatorBuffer<SampleAccumulator> mSamples; + AccumulatorBuffer<EventAccumulator> mEvents; + AccumulatorBuffer<TimeBlockAccumulator> mStackTimers; + AccumulatorBuffer<MemAccumulator> mMemStats; + }; +} + +#endif // LL_LLTRACEACCUMULATORS_H + diff --git a/indra/llcommon/lltracerecording.cpp b/indra/llcommon/lltracerecording.cpp new file mode 100644 index 0000000000..0b10438b9f --- /dev/null +++ b/indra/llcommon/lltracerecording.cpp @@ -0,0 +1,1251 @@ +/** + * @file lltracesampler.cpp + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2012, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "lltracerecording.h" + +#include "lltrace.h" +#include "llfasttimer.h" +#include "lltracethreadrecorder.h" +#include "llthread.h" + +inline F64 lerp(F64 a, F64 b, F64 u) +{ + return a + ((b - a) * u); +} + +namespace LLTrace +{ + +extern MemStatHandle gTraceMemStat; + +/////////////////////////////////////////////////////////////////////// +// Recording +/////////////////////////////////////////////////////////////////////// + +Recording::Recording(EPlayState state) +: mElapsedSeconds(0), + mActiveBuffers(NULL) +{ + claim_alloc(gTraceMemStat, this); + mBuffers = new AccumulatorBufferGroup(); + claim_alloc(gTraceMemStat, mBuffers); + setPlayState(state); +} + +Recording::Recording( const Recording& other ) +: mActiveBuffers(NULL) +{ + claim_alloc(gTraceMemStat, this); + *this = other; +} + +Recording& Recording::operator = (const Recording& other) +{ + // this will allow us to seamlessly start without affecting any data we've acquired from other + setPlayState(PAUSED); + + const_cast<Recording&>(other).update(); + EPlayState other_play_state = other.getPlayState(); + + mBuffers = other.mBuffers; + + // above call will clear mElapsedSeconds as a side effect, so copy it here + mElapsedSeconds = other.mElapsedSeconds; + mSamplingTimer = other.mSamplingTimer; + + setPlayState(other_play_state); + + return *this; +} + + +Recording::~Recording() +{ + disclaim_alloc(gTraceMemStat, this); + disclaim_alloc(gTraceMemStat, mBuffers); + + // allow recording destruction without thread recorder running, + // otherwise thread shutdown could crash if a recording outlives the thread recorder + // besides, recording construction and destruction is fine without a recorder...just don't attempt to start one + if (isStarted() && LLTrace::get_thread_recorder().notNull()) + { + LLTrace::get_thread_recorder()->deactivate(mBuffers.write()); + } +} + +// brings recording to front of recorder stack, with up to date info +void Recording::update() +{ +#if LL_TRACE_ENABLED + if (isStarted()) + { + mElapsedSeconds += mSamplingTimer.getElapsedTimeF64(); + + // must have + llassert(mActiveBuffers != NULL + && LLTrace::get_thread_recorder().notNull()); + + if(!mActiveBuffers->isCurrent()) + { + AccumulatorBufferGroup* buffers = mBuffers.write(); + LLTrace::get_thread_recorder()->deactivate(buffers); + mActiveBuffers = LLTrace::get_thread_recorder()->activate(buffers); + } + + mSamplingTimer.reset(); + } +#endif +} + +void Recording::handleReset() +{ +#if LL_TRACE_ENABLED + mBuffers.write()->reset(); + + mElapsedSeconds = F64Seconds(0.0); + mSamplingTimer.reset(); +#endif +} + +void Recording::handleStart() +{ +#if LL_TRACE_ENABLED + mSamplingTimer.reset(); + mBuffers.setStayUnique(true); + // must have thread recorder running on this thread + llassert(LLTrace::get_thread_recorder().notNull()); + mActiveBuffers = LLTrace::get_thread_recorder()->activate(mBuffers.write()); +#endif +} + +void Recording::handleStop() +{ +#if LL_TRACE_ENABLED + mElapsedSeconds += mSamplingTimer.getElapsedTimeF64(); + // must have thread recorder running on this thread + llassert(LLTrace::get_thread_recorder().notNull()); + LLTrace::get_thread_recorder()->deactivate(mBuffers.write()); + mActiveBuffers = NULL; + mBuffers.setStayUnique(false); +#endif +} + +void Recording::handleSplitTo(Recording& other) +{ +#if LL_TRACE_ENABLED + mBuffers.write()->handOffTo(*other.mBuffers.write()); +#endif +} + +void Recording::appendRecording( Recording& other ) +{ +#if LL_TRACE_ENABLED + update(); + other.update(); + mBuffers.write()->append(*other.mBuffers); + mElapsedSeconds += other.mElapsedSeconds; +#endif +} + +bool Recording::hasValue(const StatType<TimeBlockAccumulator>& stat) +{ + update(); + const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()]; + const TimeBlockAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mStackTimers[stat.getIndex()] : NULL; + return accumulator.hasValue() || (active_accumulator && active_accumulator->hasValue()); +} + +F64Seconds Recording::getSum(const StatType<TimeBlockAccumulator>& stat) +{ + update(); + const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()]; + const TimeBlockAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mStackTimers[stat.getIndex()] : NULL; + return F64Seconds((F64)(accumulator.mTotalTimeCounter) + (F64)(active_accumulator ? active_accumulator->mTotalTimeCounter : 0)) + / (F64)LLTrace::BlockTimer::countsPerSecond(); +} + +F64Seconds Recording::getSum(const StatType<TimeBlockAccumulator::SelfTimeFacet>& stat) +{ + update(); + const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()]; + const TimeBlockAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mStackTimers[stat.getIndex()] : NULL; + return F64Seconds(((F64)(accumulator.mSelfTimeCounter) + (F64)(active_accumulator ? active_accumulator->mSelfTimeCounter : 0)) / (F64)LLTrace::BlockTimer::countsPerSecond()); +} + + +S32 Recording::getSum(const StatType<TimeBlockAccumulator::CallCountFacet>& stat) +{ + update(); + const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()]; + const TimeBlockAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mStackTimers[stat.getIndex()] : NULL; + return accumulator.mCalls + (active_accumulator ? active_accumulator->mCalls : 0); +} + +F64Seconds Recording::getPerSec(const StatType<TimeBlockAccumulator>& stat) +{ + update(); + const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()]; + const TimeBlockAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mStackTimers[stat.getIndex()] : NULL; + + return F64Seconds((F64)(accumulator.mTotalTimeCounter + (active_accumulator ? active_accumulator->mTotalTimeCounter : 0)) + / ((F64)LLTrace::BlockTimer::countsPerSecond() * mElapsedSeconds.value())); +} + +F64Seconds Recording::getPerSec(const StatType<TimeBlockAccumulator::SelfTimeFacet>& stat) +{ + update(); + const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()]; + const TimeBlockAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mStackTimers[stat.getIndex()] : NULL; + + return F64Seconds((F64)(accumulator.mSelfTimeCounter + (active_accumulator ? active_accumulator->mSelfTimeCounter : 0)) + / ((F64)LLTrace::BlockTimer::countsPerSecond() * mElapsedSeconds.value())); +} + +F32 Recording::getPerSec(const StatType<TimeBlockAccumulator::CallCountFacet>& stat) +{ + update(); + const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()]; + const TimeBlockAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mStackTimers[stat.getIndex()] : NULL; + return (F32)(accumulator.mCalls + (active_accumulator ? active_accumulator->mCalls : 0)) / mElapsedSeconds.value(); +} + +bool Recording::hasValue(const StatType<MemAccumulator>& stat) +{ + update(); + const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()]; + const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL; + return accumulator.mSize.hasValue() || (active_accumulator && active_accumulator->mSize.hasValue() ? active_accumulator->mSize.hasValue() : false); +} + +F64Kilobytes Recording::getMin(const StatType<MemAccumulator>& stat) +{ + update(); + const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()]; + const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL; + return F64Bytes(llmin(accumulator.mSize.getMin(), (active_accumulator && active_accumulator->mSize.hasValue() ? active_accumulator->mSize.getMin() : F32_MAX))); +} + +F64Kilobytes Recording::getMean(const StatType<MemAccumulator>& stat) +{ + update(); + const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()]; + const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL; + + if (active_accumulator && active_accumulator->mSize.hasValue()) + { + return F64Bytes(lerp(accumulator.mSize.getMean(), active_accumulator->mSize.getMean(), active_accumulator->mSize.getSampleCount() / (accumulator.mSize.getSampleCount() + active_accumulator->mSize.getSampleCount()))); + } + else + { + return F64Bytes(accumulator.mSize.getMean()); + } +} + +F64Kilobytes Recording::getMax(const StatType<MemAccumulator>& stat) +{ + update(); + const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()]; + const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL; + return F64Bytes(llmax(accumulator.mSize.getMax(), active_accumulator && active_accumulator->mSize.hasValue() ? active_accumulator->mSize.getMax() : F32_MIN)); +} + +F64Kilobytes Recording::getStandardDeviation(const StatType<MemAccumulator>& stat) +{ + update(); + const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()]; + const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL; + if (active_accumulator && active_accumulator->hasValue()) + { + F64 sum_of_squares = SampleAccumulator::mergeSumsOfSquares(accumulator.mSize, active_accumulator->mSize); + return F64Bytes(sqrtf(sum_of_squares / (accumulator.mSize.getSamplingTime().value() + active_accumulator->mSize.getSamplingTime().value()))); + } + else + { + return F64Bytes(accumulator.mSize.getStandardDeviation()); + } +} + +F64Kilobytes Recording::getLastValue(const StatType<MemAccumulator>& stat) +{ + update(); + const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()]; + const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL; + return F64Bytes(active_accumulator ? active_accumulator->mSize.getLastValue() : accumulator.mSize.getLastValue()); +} + +bool Recording::hasValue(const StatType<MemAccumulator::AllocationFacet>& stat) +{ + update(); + const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()]; + const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL; + return accumulator.mAllocations.hasValue() || (active_accumulator ? active_accumulator->mAllocations.hasValue() : false); +} + +F64Kilobytes Recording::getSum(const StatType<MemAccumulator::AllocationFacet>& stat) +{ + update(); + const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()]; + const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL; + return F64Bytes(accumulator.mAllocations.getSum() + (active_accumulator ? active_accumulator->mAllocations.getSum() : 0)); +} + +F64Kilobytes Recording::getPerSec(const StatType<MemAccumulator::AllocationFacet>& stat) +{ + update(); + const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()]; + const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL; + return F64Bytes((accumulator.mAllocations.getSum() + (active_accumulator ? active_accumulator->mAllocations.getSum() : 0)) / mElapsedSeconds.value()); +} + +S32 Recording::getSampleCount(const StatType<MemAccumulator::AllocationFacet>& stat) +{ + update(); + const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()]; + const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL; + return accumulator.mAllocations.getSampleCount() + (active_accumulator ? active_accumulator->mAllocations.getSampleCount() : 0); +} + +bool Recording::hasValue(const StatType<MemAccumulator::DeallocationFacet>& stat) +{ + update(); + const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()]; + const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL; + return accumulator.mDeallocations.hasValue() || (active_accumulator ? active_accumulator->mDeallocations.hasValue() : false); +} + + +F64Kilobytes Recording::getSum(const StatType<MemAccumulator::DeallocationFacet>& stat) +{ + update(); + const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()]; + const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL; + return F64Bytes(accumulator.mDeallocations.getSum() + (active_accumulator ? active_accumulator->mDeallocations.getSum() : 0)); +} + +F64Kilobytes Recording::getPerSec(const StatType<MemAccumulator::DeallocationFacet>& stat) +{ + update(); + const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()]; + const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL; + return F64Bytes((accumulator.mDeallocations.getSum() + (active_accumulator ? active_accumulator->mDeallocations.getSum() : 0)) / mElapsedSeconds.value()); +} + +S32 Recording::getSampleCount(const StatType<MemAccumulator::DeallocationFacet>& stat) +{ + update(); + const MemAccumulator& accumulator = mBuffers->mMemStats[stat.getIndex()]; + const MemAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mMemStats[stat.getIndex()] : NULL; + return accumulator.mDeallocations.getSampleCount() + (active_accumulator ? active_accumulator->mDeallocations.getSampleCount() : 0); +} + +bool Recording::hasValue(const StatType<CountAccumulator>& stat) +{ + update(); + const CountAccumulator& accumulator = mBuffers->mCounts[stat.getIndex()]; + const CountAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mCounts[stat.getIndex()] : NULL; + return accumulator.hasValue() || (active_accumulator ? active_accumulator->hasValue() : false); +} + +F64 Recording::getSum(const StatType<CountAccumulator>& stat) +{ + update(); + const CountAccumulator& accumulator = mBuffers->mCounts[stat.getIndex()]; + const CountAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mCounts[stat.getIndex()] : NULL; + return accumulator.getSum() + (active_accumulator ? active_accumulator->getSum() : 0); +} + +F64 Recording::getPerSec( const StatType<CountAccumulator>& stat ) +{ + update(); + const CountAccumulator& accumulator = mBuffers->mCounts[stat.getIndex()]; + const CountAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mCounts[stat.getIndex()] : NULL; + F64 sum = accumulator.getSum() + (active_accumulator ? active_accumulator->getSum() : 0); + return sum / mElapsedSeconds.value(); +} + +S32 Recording::getSampleCount( const StatType<CountAccumulator>& stat ) +{ + update(); + const CountAccumulator& accumulator = mBuffers->mCounts[stat.getIndex()]; + const CountAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mCounts[stat.getIndex()] : NULL; + return accumulator.getSampleCount() + (active_accumulator ? active_accumulator->getSampleCount() : 0); +} + +bool Recording::hasValue(const StatType<SampleAccumulator>& stat) +{ + update(); + const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()]; + const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL; + return accumulator.hasValue() || (active_accumulator && active_accumulator->hasValue()); +} + +F64 Recording::getMin( const StatType<SampleAccumulator>& stat ) +{ + update(); + const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()]; + const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL; + return llmin(accumulator.getMin(), active_accumulator && active_accumulator->hasValue() ? active_accumulator->getMin() : F32_MAX); +} + +F64 Recording::getMax( const StatType<SampleAccumulator>& stat ) +{ + update(); + const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()]; + const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL; + return llmax(accumulator.getMax(), active_accumulator && active_accumulator->hasValue() ? active_accumulator->getMax() : F32_MIN); +} + +F64 Recording::getMean( const StatType<SampleAccumulator>& stat ) +{ + update(); + const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()]; + const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL; + if (active_accumulator && active_accumulator->hasValue()) + { + return lerp(accumulator.getMean(), active_accumulator->getMean(), active_accumulator->getSampleCount() / (accumulator.getSampleCount() + active_accumulator->getSampleCount())); + } + else + { + return accumulator.getMean(); + } +} + +F64 Recording::getStandardDeviation( const StatType<SampleAccumulator>& stat ) +{ + update(); + const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()]; + const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL; + + if (active_accumulator && active_accumulator->hasValue()) + { + F64 sum_of_squares = SampleAccumulator::mergeSumsOfSquares(accumulator, *active_accumulator); + return sqrtf(sum_of_squares / (accumulator.getSamplingTime() + active_accumulator->getSamplingTime())); + } + else + { + return accumulator.getStandardDeviation(); + } +} + +F64 Recording::getLastValue( const StatType<SampleAccumulator>& stat ) +{ + update(); + const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()]; + const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL; + return (active_accumulator && active_accumulator->hasValue() ? active_accumulator->getLastValue() : accumulator.getLastValue()); +} + +S32 Recording::getSampleCount( const StatType<SampleAccumulator>& stat ) +{ + update(); + const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()]; + const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL; + return accumulator.getSampleCount() + (active_accumulator && active_accumulator->hasValue() ? active_accumulator->getSampleCount() : 0); +} + +bool Recording::hasValue(const StatType<EventAccumulator>& stat) +{ + update(); + const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()]; + const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL; + return accumulator.hasValue() || (active_accumulator && active_accumulator->hasValue()); +} + +F64 Recording::getSum( const StatType<EventAccumulator>& stat) +{ + update(); + const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()]; + const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL; + return (F64)(accumulator.getSum() + (active_accumulator && active_accumulator->hasValue() ? active_accumulator->getSum() : 0)); +} + +F64 Recording::getMin( const StatType<EventAccumulator>& stat ) +{ + update(); + const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()]; + const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL; + return llmin(accumulator.getMin(), active_accumulator && active_accumulator->hasValue() ? active_accumulator->getMin() : F32_MAX); +} + +F64 Recording::getMax( const StatType<EventAccumulator>& stat ) +{ + update(); + const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()]; + const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL; + return llmax(accumulator.getMax(), active_accumulator && active_accumulator->hasValue() ? active_accumulator->getMax() : F32_MIN); +} + +F64 Recording::getMean( const StatType<EventAccumulator>& stat ) +{ + update(); + const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()]; + const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL; + if (active_accumulator && active_accumulator->hasValue()) + { + return lerp(accumulator.getMean(), active_accumulator->getMean(), active_accumulator->getSampleCount() / (accumulator.getSampleCount() + active_accumulator->getSampleCount())); + } + else + { + return accumulator.getMean(); + } +} + +F64 Recording::getStandardDeviation( const StatType<EventAccumulator>& stat ) +{ + update(); + const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()]; + const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL; + + if (active_accumulator && active_accumulator->hasValue()) + { + F64 sum_of_squares = EventAccumulator::mergeSumsOfSquares(accumulator, *active_accumulator); + return sqrtf(sum_of_squares / (accumulator.getSampleCount() + active_accumulator->getSampleCount())); + } + else + { + return accumulator.getStandardDeviation(); + } +} + +F64 Recording::getLastValue( const StatType<EventAccumulator>& stat ) +{ + update(); + const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()]; + const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL; + return active_accumulator ? active_accumulator->getLastValue() : accumulator.getLastValue(); +} + +S32 Recording::getSampleCount( const StatType<EventAccumulator>& stat ) +{ + update(); + const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()]; + const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL; + return accumulator.getSampleCount() + (active_accumulator ? active_accumulator->getSampleCount() : 0); +} + +/////////////////////////////////////////////////////////////////////// +// PeriodicRecording +/////////////////////////////////////////////////////////////////////// + +PeriodicRecording::PeriodicRecording( S32 num_periods, EPlayState state) +: mAutoResize(num_periods == 0), + mCurPeriod(0), + mNumRecordedPeriods(0), + mRecordingPeriods(num_periods ? num_periods : 1) +{ + setPlayState(state); + claim_alloc(gTraceMemStat, this); +} + +PeriodicRecording::~PeriodicRecording() +{ + disclaim_alloc(gTraceMemStat, this); +} + +void PeriodicRecording::nextPeriod() +{ + if (mAutoResize) + { + mRecordingPeriods.push_back(Recording()); + } + + Recording& old_recording = getCurRecording(); + mCurPeriod = (mCurPeriod + 1) % mRecordingPeriods.size(); + old_recording.splitTo(getCurRecording()); + + mNumRecordedPeriods = llmin((S32)mRecordingPeriods.size() - 1, mNumRecordedPeriods + 1); +} + +void PeriodicRecording::appendRecording(Recording& recording) +{ + getCurRecording().appendRecording(recording); + nextPeriod(); +} + + +void PeriodicRecording::appendPeriodicRecording( PeriodicRecording& other ) +{ + if (other.mRecordingPeriods.empty()) return; + + getCurRecording().update(); + other.getCurRecording().update(); + + const S32 other_recording_slots = other.mRecordingPeriods.size(); + const S32 other_num_recordings = other.getNumRecordedPeriods(); + const S32 other_current_recording_index = other.mCurPeriod; + const S32 other_oldest_recording_index = (other_current_recording_index + other_recording_slots - other_num_recordings) % other_recording_slots; + + // append first recording into our current slot + getCurRecording().appendRecording(other.mRecordingPeriods[other_oldest_recording_index]); + + // from now on, add new recordings for everything after the first + S32 other_index = (other_oldest_recording_index + 1) % other_recording_slots; + + if (mAutoResize) + { + // push back recordings for everything in the middle + S32 other_index = (other_oldest_recording_index + 1) % other_recording_slots; + while (other_index != other_current_recording_index) + { + mRecordingPeriods.push_back(other.mRecordingPeriods[other_index]); + other_index = (other_index + 1) % other_recording_slots; + } + + // add final recording, if it wasn't already added as the first + if (other_num_recordings > 1) + { + mRecordingPeriods.push_back(other.mRecordingPeriods[other_current_recording_index]); + } + + mCurPeriod = mRecordingPeriods.size() - 1; + mNumRecordedPeriods = mRecordingPeriods.size() - 1; + } + else + { + S32 num_to_copy = llmin((S32)mRecordingPeriods.size(), (S32)other_num_recordings); + + std::vector<Recording>::iterator src_it = other.mRecordingPeriods.begin() + other_index ; + std::vector<Recording>::iterator dest_it = mRecordingPeriods.begin() + mCurPeriod; + + // already consumed the first recording from other, so start counting at 1 + for(S32 i = 1; i < num_to_copy; i++) + { + *dest_it = *src_it; + + if (++src_it == other.mRecordingPeriods.end()) + { + src_it = other.mRecordingPeriods.begin(); + } + + if (++dest_it == mRecordingPeriods.end()) + { + dest_it = mRecordingPeriods.begin(); + } + } + + // want argument to % to be positive, otherwise result could be negative and thus out of bounds + llassert(num_to_copy >= 1); + // advance to last recording period copied, and make that our current period + mCurPeriod = (mCurPeriod + num_to_copy - 1) % mRecordingPeriods.size(); + mNumRecordedPeriods = llmin((S32)mRecordingPeriods.size() - 1, mNumRecordedPeriods + num_to_copy - 1); + } + + // end with fresh period, otherwise next appendPeriodicRecording() will merge the first + // recording period with the last one appended here + nextPeriod(); + getCurRecording().setPlayState(getPlayState()); +} + +F64Seconds PeriodicRecording::getDuration() const +{ + F64Seconds duration; + S32 num_periods = mRecordingPeriods.size(); + for (S32 i = 1; i <= num_periods; i++) + { + S32 index = (mCurPeriod + num_periods - i) % num_periods; + duration += mRecordingPeriods[index].getDuration(); + } + return duration; +} + + +LLTrace::Recording PeriodicRecording::snapshotCurRecording() const +{ + Recording recording_copy(getCurRecording()); + recording_copy.stop(); + return recording_copy; +} + + +Recording& PeriodicRecording::getLastRecording() +{ + return getPrevRecording(1); +} + +const Recording& PeriodicRecording::getLastRecording() const +{ + return getPrevRecording(1); +} + +Recording& PeriodicRecording::getCurRecording() +{ + return mRecordingPeriods[mCurPeriod]; +} + +const Recording& PeriodicRecording::getCurRecording() const +{ + return mRecordingPeriods[mCurPeriod]; +} + +Recording& PeriodicRecording::getPrevRecording( S32 offset ) +{ + S32 num_periods = mRecordingPeriods.size(); + offset = llclamp(offset, 0, num_periods - 1); + return mRecordingPeriods[(mCurPeriod + num_periods - offset) % num_periods]; +} + +const Recording& PeriodicRecording::getPrevRecording( S32 offset ) const +{ + S32 num_periods = mRecordingPeriods.size(); + offset = llclamp(offset, 0, num_periods - 1); + return mRecordingPeriods[(mCurPeriod + num_periods - offset) % num_periods]; +} + +void PeriodicRecording::handleStart() +{ + getCurRecording().start(); +} + +void PeriodicRecording::handleStop() +{ + getCurRecording().pause(); +} + +void PeriodicRecording::handleReset() +{ + getCurRecording().stop(); + + if (mAutoResize) + { + mRecordingPeriods.clear(); + mRecordingPeriods.push_back(Recording()); + } + else + { + for (std::vector<Recording>::iterator it = mRecordingPeriods.begin(), end_it = mRecordingPeriods.end(); + it != end_it; + ++it) + { + it->reset(); + } + } + mCurPeriod = 0; + mNumRecordedPeriods = 0; + getCurRecording().setPlayState(getPlayState()); +} + +void PeriodicRecording::handleSplitTo(PeriodicRecording& other) +{ + getCurRecording().splitTo(other.getCurRecording()); +} + +F64 PeriodicRecording::getPeriodMin( const StatType<EventAccumulator>& stat, S32 num_periods /*= S32_MAX*/ ) +{ + num_periods = llmin(num_periods, getNumRecordedPeriods()); + + bool has_value = false; + F64 min_val = std::numeric_limits<F64>::max(); + for (S32 i = 1; i <= num_periods; i++) + { + Recording& recording = getPrevRecording(i); + if (recording.hasValue(stat)) + { + min_val = llmin(min_val, recording.getMin(stat)); + has_value = true; + } + } + + return has_value + ? min_val + : NaN; +} + +F64 PeriodicRecording::getPeriodMax( const StatType<EventAccumulator>& stat, S32 num_periods /*= S32_MAX*/ ) +{ + num_periods = llmin(num_periods, getNumRecordedPeriods()); + + bool has_value = false; + F64 max_val = std::numeric_limits<F64>::min(); + for (S32 i = 1; i <= num_periods; i++) + { + Recording& recording = getPrevRecording(i); + if (recording.hasValue(stat)) + { + max_val = llmax(max_val, recording.getMax(stat)); + has_value = true; + } + } + + return has_value + ? max_val + : NaN; +} + +// calculates means using aggregates per period +F64 PeriodicRecording::getPeriodMean( const StatType<EventAccumulator>& stat, S32 num_periods /*= S32_MAX*/ ) +{ + num_periods = llmin(num_periods, getNumRecordedPeriods()); + + F64 mean = 0; + S32 valid_period_count = 0; + + for (S32 i = 1; i <= num_periods; i++) + { + Recording& recording = getPrevRecording(i); + if (recording.hasValue(stat)) + { + mean += recording.getMean(stat); + valid_period_count++; + } + } + + return valid_period_count + ? mean / (F64)valid_period_count + : NaN; +} + + +F64 PeriodicRecording::getPeriodStandardDeviation( const StatType<EventAccumulator>& stat, S32 num_periods /*= S32_MAX*/ ) +{ + num_periods = llmin(num_periods, getNumRecordedPeriods()); + + F64 period_mean = getPeriodMean(stat, num_periods); + F64 sum_of_squares = 0; + S32 valid_period_count = 0; + + for (S32 i = 1; i <= num_periods; i++) + { + Recording& recording = getPrevRecording(i); + if (recording.hasValue(stat)) + { + F64 delta = recording.getMean(stat) - period_mean; + sum_of_squares += delta * delta; + valid_period_count++; + } + } + + return valid_period_count + ? sqrt((F64)sum_of_squares / (F64)valid_period_count) + : NaN; +} + +F64 PeriodicRecording::getPeriodMin( const StatType<SampleAccumulator>& stat, S32 num_periods /*= S32_MAX*/ ) +{ + num_periods = llmin(num_periods, getNumRecordedPeriods()); + + bool has_value = false; + F64 min_val = std::numeric_limits<F64>::max(); + for (S32 i = 1; i <= num_periods; i++) + { + Recording& recording = getPrevRecording(i); + if (recording.hasValue(stat)) + { + min_val = llmin(min_val, recording.getMin(stat)); + has_value = true; + } + } + + return has_value + ? min_val + : NaN; +} + +F64 PeriodicRecording::getPeriodMax(const StatType<SampleAccumulator>& stat, S32 num_periods /*= S32_MAX*/) +{ + num_periods = llmin(num_periods, getNumRecordedPeriods()); + + bool has_value = false; + F64 max_val = std::numeric_limits<F64>::min(); + for (S32 i = 1; i <= num_periods; i++) + { + Recording& recording = getPrevRecording(i); + if (recording.hasValue(stat)) + { + max_val = llmax(max_val, recording.getMax(stat)); + has_value = true; + } + } + + return has_value + ? max_val + : NaN; +} + + +F64 PeriodicRecording::getPeriodMean( const StatType<SampleAccumulator>& stat, S32 num_periods /*= S32_MAX*/ ) +{ + num_periods = llmin(num_periods, getNumRecordedPeriods()); + + S32 valid_period_count = 0; + F64 mean = 0; + + for (S32 i = 1; i <= num_periods; i++) + { + Recording& recording = getPrevRecording(i); + if (recording.hasValue(stat)) + { + mean += recording.getMean(stat); + valid_period_count++; + } + } + + return valid_period_count + ? mean / F64(valid_period_count) + : NaN; +} + +F64 PeriodicRecording::getPeriodStandardDeviation( const StatType<SampleAccumulator>& stat, S32 num_periods /*= S32_MAX*/ ) +{ + num_periods = llmin(num_periods, getNumRecordedPeriods()); + + F64 period_mean = getPeriodMean(stat, num_periods); + S32 valid_period_count = 0; + F64 sum_of_squares = 0; + + for (S32 i = 1; i <= num_periods; i++) + { + Recording& recording = getPrevRecording(i); + if (recording.hasValue(stat)) + { + F64 delta = recording.getMean(stat) - period_mean; + sum_of_squares += delta * delta; + valid_period_count++; + } + } + + return valid_period_count + ? sqrt(sum_of_squares / (F64)valid_period_count) + : NaN; +} + + +F64Kilobytes PeriodicRecording::getPeriodMin( const StatType<MemAccumulator>& stat, S32 num_periods /*= S32_MAX*/ ) +{ + num_periods = llmin(num_periods, getNumRecordedPeriods()); + + F64Kilobytes min_val(std::numeric_limits<F64>::max()); + for (S32 i = 1; i <= num_periods; i++) + { + Recording& recording = getPrevRecording(i); + min_val = llmin(min_val, recording.getMin(stat)); + } + + return min_val; +} + +F64Kilobytes PeriodicRecording::getPeriodMin(const MemStatHandle& stat, S32 num_periods) +{ + return getPeriodMin(static_cast<const StatType<MemAccumulator>&>(stat), num_periods); +} + +F64Kilobytes PeriodicRecording::getPeriodMax(const StatType<MemAccumulator>& stat, S32 num_periods /*= S32_MAX*/) +{ + num_periods = llmin(num_periods, getNumRecordedPeriods()); + + F64Kilobytes max_val(0.0); + for (S32 i = 1; i <= num_periods; i++) + { + Recording& recording = getPrevRecording(i); + max_val = llmax(max_val, recording.getMax(stat)); + } + + return max_val; +} + +F64Kilobytes PeriodicRecording::getPeriodMax(const MemStatHandle& stat, S32 num_periods) +{ + return getPeriodMax(static_cast<const StatType<MemAccumulator>&>(stat), num_periods); +} + +F64Kilobytes PeriodicRecording::getPeriodMean( const StatType<MemAccumulator>& stat, S32 num_periods /*= S32_MAX*/ ) +{ + num_periods = llmin(num_periods, getNumRecordedPeriods()); + + F64Kilobytes mean(0); + + for (S32 i = 1; i <= num_periods; i++) + { + Recording& recording = getPrevRecording(i); + mean += recording.getMean(stat); + } + + return mean / F64(num_periods); +} + +F64Kilobytes PeriodicRecording::getPeriodMean(const MemStatHandle& stat, S32 num_periods) +{ + return getPeriodMean(static_cast<const StatType<MemAccumulator>&>(stat), num_periods); +} + +F64Kilobytes PeriodicRecording::getPeriodStandardDeviation( const StatType<MemAccumulator>& stat, S32 num_periods /*= S32_MAX*/ ) +{ + num_periods = llmin(num_periods, getNumRecordedPeriods()); + + F64Kilobytes period_mean = getPeriodMean(stat, num_periods); + S32 valid_period_count = 0; + F64 sum_of_squares = 0; + + for (S32 i = 1; i <= num_periods; i++) + { + Recording& recording = getPrevRecording(i); + if (recording.hasValue(stat)) + { + F64Kilobytes delta = recording.getMean(stat) - period_mean; + sum_of_squares += delta.value() * delta.value(); + valid_period_count++; + } + } + + return F64Kilobytes(valid_period_count + ? sqrt(sum_of_squares / (F64)valid_period_count) + : NaN); +} + +F64Kilobytes PeriodicRecording::getPeriodStandardDeviation(const MemStatHandle& stat, S32 num_periods) +{ + return getPeriodStandardDeviation(static_cast<const StatType<MemAccumulator>&>(stat), num_periods); +} + +/////////////////////////////////////////////////////////////////////// +// ExtendableRecording +/////////////////////////////////////////////////////////////////////// + +void ExtendableRecording::extend() +{ + // push the data back to accepted recording + mAcceptedRecording.appendRecording(mPotentialRecording); + // flush data, so we can start from scratch + mPotentialRecording.reset(); +} + +void ExtendableRecording::handleStart() +{ + mPotentialRecording.start(); +} + +void ExtendableRecording::handleStop() +{ + mPotentialRecording.pause(); +} + +void ExtendableRecording::handleReset() +{ + mAcceptedRecording.reset(); + mPotentialRecording.reset(); +} + +void ExtendableRecording::handleSplitTo(ExtendableRecording& other) +{ + mPotentialRecording.splitTo(other.mPotentialRecording); +} + + +/////////////////////////////////////////////////////////////////////// +// ExtendablePeriodicRecording +/////////////////////////////////////////////////////////////////////// + + +ExtendablePeriodicRecording::ExtendablePeriodicRecording() +: mAcceptedRecording(0), + mPotentialRecording(0) +{} + +void ExtendablePeriodicRecording::extend() +{ + // push the data back to accepted recording + mAcceptedRecording.appendPeriodicRecording(mPotentialRecording); + // flush data, so we can start from scratch + mPotentialRecording.reset(); +} + + +void ExtendablePeriodicRecording::handleStart() +{ + mPotentialRecording.start(); +} + +void ExtendablePeriodicRecording::handleStop() +{ + mPotentialRecording.pause(); +} + +void ExtendablePeriodicRecording::handleReset() +{ + mAcceptedRecording.reset(); + mPotentialRecording.reset(); +} + +void ExtendablePeriodicRecording::handleSplitTo(ExtendablePeriodicRecording& other) +{ + mPotentialRecording.splitTo(other.mPotentialRecording); +} + + +PeriodicRecording& get_frame_recording() +{ + static LLThreadLocalPointer<PeriodicRecording> sRecording(new PeriodicRecording(200, PeriodicRecording::STARTED)); + return *sRecording; +} + +} + +void LLStopWatchControlsMixinCommon::start() +{ + switch (mPlayState) + { + case STOPPED: + handleReset(); + handleStart(); + mPlayState = STARTED; + break; + case PAUSED: + handleStart(); + mPlayState = STARTED; + break; + case STARTED: + break; + default: + llassert(false); + break; + } +} + +void LLStopWatchControlsMixinCommon::stop() +{ + switch (mPlayState) + { + case STOPPED: + break; + case PAUSED: + mPlayState = STOPPED; + break; + case STARTED: + handleStop(); + mPlayState = STOPPED; + break; + default: + llassert(false); + break; + } +} + +void LLStopWatchControlsMixinCommon::pause() +{ + switch (mPlayState) + { + case STOPPED: + // stay stopped, don't go to pause + break; + case PAUSED: + break; + case STARTED: + handleStop(); + mPlayState = PAUSED; + break; + default: + llassert(false); + break; + } +} + +void LLStopWatchControlsMixinCommon::unpause() +{ + switch (mPlayState) + { + case STOPPED: + // stay stopped, don't start + break; + case PAUSED: + handleStart(); + mPlayState = STARTED; + break; + case STARTED: + break; + default: + llassert(false); + break; + } +} + +void LLStopWatchControlsMixinCommon::resume() +{ + switch (mPlayState) + { + case STOPPED: + handleStart(); + mPlayState = STARTED; + break; + case PAUSED: + handleStart(); + mPlayState = STARTED; + break; + case STARTED: + break; + default: + llassert(false); + break; + } +} + +void LLStopWatchControlsMixinCommon::restart() +{ + switch (mPlayState) + { + case STOPPED: + handleReset(); + handleStart(); + mPlayState = STARTED; + break; + case PAUSED: + handleReset(); + handleStart(); + mPlayState = STARTED; + break; + case STARTED: + handleReset(); + break; + default: + llassert(false); + break; + } +} + +void LLStopWatchControlsMixinCommon::reset() +{ + handleReset(); +} + +void LLStopWatchControlsMixinCommon::setPlayState( EPlayState state ) +{ + switch(state) + { + case STOPPED: + stop(); + break; + case PAUSED: + pause(); + break; + case STARTED: + start(); + break; + default: + llassert(false); + break; + } + + mPlayState = state; +} diff --git a/indra/llcommon/lltracerecording.h b/indra/llcommon/lltracerecording.h new file mode 100644 index 0000000000..d0b4a842a6 --- /dev/null +++ b/indra/llcommon/lltracerecording.h @@ -0,0 +1,670 @@ +/** + * @file lltracerecording.h + * @brief Sampling object for collecting runtime statistics originating from lltrace. + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2012, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLTRACERECORDING_H +#define LL_LLTRACERECORDING_H + +#include "stdtypes.h" +#include "llpreprocessor.h" + +#include "lltimer.h" +#include "lltraceaccumulators.h" +#include "llpointer.h" + +class LLStopWatchControlsMixinCommon +{ +public: + virtual ~LLStopWatchControlsMixinCommon() {} + + enum EPlayState + { + STOPPED, + PAUSED, + STARTED + }; + + void start(); // moves to started state, resetting if stopped + void stop(); // moves to stopped state + void pause(); // moves to paused state, unless stopped + void unpause(); // moves to started state if paused + void resume(); // moves to started state, without resetting + void restart(); // moves to started state, always resetting + void reset(); // resets + + bool isStarted() const { return mPlayState == STARTED; } + bool isPaused() const { return mPlayState == PAUSED; } + bool isStopped() const { return mPlayState == STOPPED; } + + EPlayState getPlayState() const { return mPlayState; } + // force play state to specific value by calling appropriate handle* methods + void setPlayState(EPlayState state); + +protected: + LLStopWatchControlsMixinCommon() + : mPlayState(STOPPED) + {} + +private: + // override these methods to provide started/stopped semantics + + // activate behavior (without reset) + virtual void handleStart() = 0; + // deactivate behavior + virtual void handleStop() = 0; + // clear accumulated state, may be called while started + virtual void handleReset() = 0; + + EPlayState mPlayState; +}; + +template<typename DERIVED> +class LLStopWatchControlsMixin +: public LLStopWatchControlsMixinCommon +{ +public: + + typedef LLStopWatchControlsMixin<DERIVED> self_t; + virtual void splitTo(DERIVED& other) + { + EPlayState play_state = getPlayState(); + stop(); + other.reset(); + + handleSplitTo(other); + + other.setPlayState(play_state); + } + + virtual void splitFrom(DERIVED& other) + { + static_cast<self_t&>(other).handleSplitTo(*static_cast<DERIVED*>(this)); + } +private: + self_t& operator = (const self_t& other) + { + // don't do anything, derived class must implement logic + } + + // atomically stop this object while starting the other + // no data can be missed in between stop and start + virtual void handleSplitTo(DERIVED& other) {}; + +}; + +namespace LLTrace +{ + template<typename T> + class StatType; + + template<typename T> + class CountStatHandle; + + template<typename T> + class SampleStatHandle; + + template<typename T> + class EventStatHandle; + + class MemStatHandle; + + template<typename T> + struct RelatedTypes + { + typedef F64 fractional_t; + typedef T sum_t; + }; + + template<typename T, typename UNIT_T> + struct RelatedTypes<LLUnit<T, UNIT_T> > + { + typedef LLUnit<typename RelatedTypes<T>::fractional_t, UNIT_T> fractional_t; + typedef LLUnit<typename RelatedTypes<T>::sum_t, UNIT_T> sum_t; + }; + + template<> + struct RelatedTypes<bool> + { + typedef F64 fractional_t; + typedef S32 sum_t; + }; + + class Recording + : public LLStopWatchControlsMixin<Recording> + { + public: + Recording(EPlayState state = LLStopWatchControlsMixinCommon::STOPPED); + + Recording(const Recording& other); + ~Recording(); + + Recording& operator = (const Recording& other); + + // accumulate data from subsequent, non-overlapping recording + void appendRecording(Recording& other); + + // grab latest recorded data + void update(); + + // ensure that buffers are exclusively owned by this recording + void makeUnique() { mBuffers.makeUnique(); } + + // Timer accessors + bool hasValue(const StatType<TimeBlockAccumulator>& stat); + F64Seconds getSum(const StatType<TimeBlockAccumulator>& stat); + F64Seconds getSum(const StatType<TimeBlockAccumulator::SelfTimeFacet>& stat); + S32 getSum(const StatType<TimeBlockAccumulator::CallCountFacet>& stat); + + F64Seconds getPerSec(const StatType<TimeBlockAccumulator>& stat); + F64Seconds getPerSec(const StatType<TimeBlockAccumulator::SelfTimeFacet>& stat); + F32 getPerSec(const StatType<TimeBlockAccumulator::CallCountFacet>& stat); + + // Memory accessors + bool hasValue(const StatType<MemAccumulator>& stat); + F64Kilobytes getMin(const StatType<MemAccumulator>& stat); + F64Kilobytes getMean(const StatType<MemAccumulator>& stat); + F64Kilobytes getMax(const StatType<MemAccumulator>& stat); + F64Kilobytes getStandardDeviation(const StatType<MemAccumulator>& stat); + F64Kilobytes getLastValue(const StatType<MemAccumulator>& stat); + + bool hasValue(const StatType<MemAccumulator::AllocationFacet>& stat); + F64Kilobytes getSum(const StatType<MemAccumulator::AllocationFacet>& stat); + F64Kilobytes getPerSec(const StatType<MemAccumulator::AllocationFacet>& stat); + S32 getSampleCount(const StatType<MemAccumulator::AllocationFacet>& stat); + + bool hasValue(const StatType<MemAccumulator::DeallocationFacet>& stat); + F64Kilobytes getSum(const StatType<MemAccumulator::DeallocationFacet>& stat); + F64Kilobytes getPerSec(const StatType<MemAccumulator::DeallocationFacet>& stat); + S32 getSampleCount(const StatType<MemAccumulator::DeallocationFacet>& stat); + + // CountStatHandle accessors + bool hasValue(const StatType<CountAccumulator>& stat); + F64 getSum(const StatType<CountAccumulator>& stat); + template <typename T> + typename RelatedTypes<T>::sum_t getSum(const CountStatHandle<T>& stat) + { + return (typename RelatedTypes<T>::sum_t)getSum(static_cast<const StatType<CountAccumulator>&> (stat)); + } + + F64 getPerSec(const StatType<CountAccumulator>& stat); + template <typename T> + typename RelatedTypes<T>::fractional_t getPerSec(const CountStatHandle<T>& stat) + { + return (typename RelatedTypes<T>::fractional_t)getPerSec(static_cast<const StatType<CountAccumulator>&> (stat)); + } + + S32 getSampleCount(const StatType<CountAccumulator>& stat); + + + // SampleStatHandle accessors + bool hasValue(const StatType<SampleAccumulator>& stat); + + F64 getMin(const StatType<SampleAccumulator>& stat); + template <typename T> + T getMin(const SampleStatHandle<T>& stat) + { + return (T)getMin(static_cast<const StatType<SampleAccumulator>&> (stat)); + } + + F64 getMax(const StatType<SampleAccumulator>& stat); + template <typename T> + T getMax(const SampleStatHandle<T>& stat) + { + return (T)getMax(static_cast<const StatType<SampleAccumulator>&> (stat)); + } + + F64 getMean(const StatType<SampleAccumulator>& stat); + template <typename T> + typename RelatedTypes<T>::fractional_t getMean(SampleStatHandle<T>& stat) + { + return (typename RelatedTypes<T>::fractional_t)getMean(static_cast<const StatType<SampleAccumulator>&> (stat)); + } + + F64 getStandardDeviation(const StatType<SampleAccumulator>& stat); + template <typename T> + typename RelatedTypes<T>::fractional_t getStandardDeviation(const SampleStatHandle<T>& stat) + { + return (typename RelatedTypes<T>::fractional_t)getStandardDeviation(static_cast<const StatType<SampleAccumulator>&> (stat)); + } + + F64 getLastValue(const StatType<SampleAccumulator>& stat); + template <typename T> + T getLastValue(const SampleStatHandle<T>& stat) + { + return (T)getLastValue(static_cast<const StatType<SampleAccumulator>&> (stat)); + } + + S32 getSampleCount(const StatType<SampleAccumulator>& stat); + + // EventStatHandle accessors + bool hasValue(const StatType<EventAccumulator>& stat); + + F64 getSum(const StatType<EventAccumulator>& stat); + template <typename T> + typename RelatedTypes<T>::sum_t getSum(const EventStatHandle<T>& stat) + { + return (typename RelatedTypes<T>::sum_t)getSum(static_cast<const StatType<EventAccumulator>&> (stat)); + } + + F64 getMin(const StatType<EventAccumulator>& stat); + template <typename T> + T getMin(const EventStatHandle<T>& stat) + { + return (T)getMin(static_cast<const StatType<EventAccumulator>&> (stat)); + } + + F64 getMax(const StatType<EventAccumulator>& stat); + template <typename T> + T getMax(const EventStatHandle<T>& stat) + { + return (T)getMax(static_cast<const StatType<EventAccumulator>&> (stat)); + } + + F64 getMean(const StatType<EventAccumulator>& stat); + template <typename T> + typename RelatedTypes<T>::fractional_t getMean(EventStatHandle<T>& stat) + { + return (typename RelatedTypes<T>::fractional_t)getMean(static_cast<const StatType<EventAccumulator>&> (stat)); + } + + F64 getStandardDeviation(const StatType<EventAccumulator>& stat); + template <typename T> + typename RelatedTypes<T>::fractional_t getStandardDeviation(const EventStatHandle<T>& stat) + { + return (typename RelatedTypes<T>::fractional_t)getStandardDeviation(static_cast<const StatType<EventAccumulator>&> (stat)); + } + + F64 getLastValue(const StatType<EventAccumulator>& stat); + template <typename T> + T getLastValue(const EventStatHandle<T>& stat) + { + return (T)getLastValue(static_cast<const StatType<EventAccumulator>&> (stat)); + } + + S32 getSampleCount(const StatType<EventAccumulator>& stat); + + F64Seconds getDuration() const { return mElapsedSeconds; } + + protected: + friend class ThreadRecorder; + + // implementation for LLStopWatchControlsMixin + /*virtual*/ void handleStart(); + /*virtual*/ void handleStop(); + /*virtual*/ void handleReset(); + /*virtual*/ void handleSplitTo(Recording& other); + + // returns data for current thread + class ThreadRecorder* getThreadRecorder(); + + LLTimer mSamplingTimer; + F64Seconds mElapsedSeconds; + LLCopyOnWritePointer<AccumulatorBufferGroup> mBuffers; + AccumulatorBufferGroup* mActiveBuffers; + + }; + + class LL_COMMON_API PeriodicRecording + : public LLStopWatchControlsMixin<PeriodicRecording> + { + public: + PeriodicRecording(S32 num_periods, EPlayState state = STOPPED); + ~PeriodicRecording(); + + void nextPeriod(); + S32 getNumRecordedPeriods() + { + // current period counts if not active + return mNumRecordedPeriods + (isStarted() ? 0 : 1); + } + + F64Seconds getDuration() const; + + void appendPeriodicRecording(PeriodicRecording& other); + void appendRecording(Recording& recording); + Recording& getLastRecording(); + const Recording& getLastRecording() const; + Recording& getCurRecording(); + const Recording& getCurRecording() const; + Recording& getPrevRecording(S32 offset); + const Recording& getPrevRecording(S32 offset) const; + Recording snapshotCurRecording() const; + + template <typename T> + S32 getSampleCount(const StatType<T>& stat, S32 num_periods = S32_MAX) + { + num_periods = llmin(num_periods, getNumRecordedPeriods()); + + S32 num_samples = 0; + for (S32 i = 1; i <= num_periods; i++) + { + Recording& recording = getPrevRecording(i); + num_samples += recording.getSampleCount(stat); + } + return num_samples; + } + + // + // PERIODIC MIN + // + + // catch all for stats that have a defined sum + template <typename T> + typename T::value_t getPeriodMin(const StatType<T>& stat, S32 num_periods = S32_MAX) + { + num_periods = llmin(num_periods, getNumRecordedPeriods()); + + bool has_value = false; + typename T::value_t min_val(std::numeric_limits<typename T::value_t>::max()); + for (S32 i = 1; i <= num_periods; i++) + { + Recording& recording = getPrevRecording(i); + if (recording.hasValue(stat)) + { + min_val = llmin(min_val, recording.getSum(stat)); + has_value = true; + } + } + + return has_value + ? min_val + : T::getDefaultValue(); + } + + template<typename T> + T getPeriodMin(const CountStatHandle<T>& stat, S32 num_periods = S32_MAX) + { + return T(getPeriodMin(static_cast<const StatType<CountAccumulator>&>(stat), num_periods)); + } + + F64 getPeriodMin(const StatType<SampleAccumulator>& stat, S32 num_periods = S32_MAX); + template<typename T> + T getPeriodMin(const SampleStatHandle<T>& stat, S32 num_periods = S32_MAX) + { + return T(getPeriodMin(static_cast<const StatType<SampleAccumulator>&>(stat), num_periods)); + } + + F64 getPeriodMin(const StatType<EventAccumulator>& stat, S32 num_periods = S32_MAX); + template<typename T> + T getPeriodMin(const EventStatHandle<T>& stat, S32 num_periods = S32_MAX) + { + return T(getPeriodMin(static_cast<const StatType<EventAccumulator>&>(stat), num_periods)); + } + + F64Kilobytes getPeriodMin(const StatType<MemAccumulator>& stat, S32 num_periods = S32_MAX); + F64Kilobytes getPeriodMin(const MemStatHandle& stat, S32 num_periods = S32_MAX); + + template <typename T> + typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMinPerSec(const StatType<T>& stat, S32 num_periods = S32_MAX) + { + num_periods = llmin(num_periods, getNumRecordedPeriods()); + + typename RelatedTypes<typename T::value_t>::fractional_t min_val(std::numeric_limits<F64>::max()); + for (S32 i = 1; i <= num_periods; i++) + { + Recording& recording = getPrevRecording(i); + min_val = llmin(min_val, recording.getPerSec(stat)); + } + return (typename RelatedTypes<typename T::value_t>::fractional_t) min_val; + } + + template<typename T> + typename RelatedTypes<T>::fractional_t getPeriodMinPerSec(const CountStatHandle<T>& stat, S32 num_periods = S32_MAX) + { + return typename RelatedTypes<T>::fractional_t(getPeriodMinPerSec(static_cast<const StatType<CountAccumulator>&>(stat), num_periods)); + } + + // + // PERIODIC MAX + // + + // catch all for stats that have a defined sum + template <typename T> + typename T::value_t getPeriodMax(const StatType<T>& stat, S32 num_periods = S32_MAX) + { + num_periods = llmin(num_periods, getNumRecordedPeriods()); + + bool has_value = false; + typename T::value_t max_val(std::numeric_limits<typename T::value_t>::min()); + for (S32 i = 1; i <= num_periods; i++) + { + Recording& recording = getPrevRecording(i); + if (recording.hasValue(stat)) + { + max_val = llmax(max_val, recording.getSum(stat)); + has_value = true; + } + } + + return has_value + ? max_val + : T::getDefaultValue(); + } + + template<typename T> + T getPeriodMax(const CountStatHandle<T>& stat, S32 num_periods = S32_MAX) + { + return T(getPeriodMax(static_cast<const StatType<CountAccumulator>&>(stat), num_periods)); + } + + F64 getPeriodMax(const StatType<SampleAccumulator>& stat, S32 num_periods = S32_MAX); + template<typename T> + T getPeriodMax(const SampleStatHandle<T>& stat, S32 num_periods = S32_MAX) + { + return T(getPeriodMax(static_cast<const StatType<SampleAccumulator>&>(stat), num_periods)); + } + + F64 getPeriodMax(const StatType<EventAccumulator>& stat, S32 num_periods = S32_MAX); + template<typename T> + T getPeriodMax(const EventStatHandle<T>& stat, S32 num_periods = S32_MAX) + { + return T(getPeriodMax(static_cast<const StatType<EventAccumulator>&>(stat), num_periods)); + } + + F64Kilobytes getPeriodMax(const StatType<MemAccumulator>& stat, S32 num_periods = S32_MAX); + F64Kilobytes getPeriodMax(const MemStatHandle& stat, S32 num_periods = S32_MAX); + + template <typename T> + typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMaxPerSec(const StatType<T>& stat, S32 num_periods = S32_MAX) + { + num_periods = llmin(num_periods, getNumRecordedPeriods()); + + F64 max_val = std::numeric_limits<F64>::min(); + for (S32 i = 1; i <= num_periods; i++) + { + Recording& recording = getPrevRecording(i); + max_val = llmax(max_val, recording.getPerSec(stat)); + } + return (typename RelatedTypes<typename T::value_t>::fractional_t)max_val; + } + + template<typename T> + typename RelatedTypes<T>::fractional_t getPeriodMaxPerSec(const CountStatHandle<T>& stat, S32 num_periods = S32_MAX) + { + return typename RelatedTypes<T>::fractional_t(getPeriodMaxPerSec(static_cast<const StatType<CountAccumulator>&>(stat), num_periods)); + } + + // + // PERIODIC MEAN + // + + // catch all for stats that have a defined sum + template <typename T> + typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMean(const StatType<T >& stat, S32 num_periods = S32_MAX) + { + num_periods = llmin(num_periods, getNumRecordedPeriods()); + + typename RelatedTypes<typename T::value_t>::fractional_t mean(0); + + for (S32 i = 1; i <= num_periods; i++) + { + Recording& recording = getPrevRecording(i); + if (recording.getDuration() > (F32Seconds)0.f) + { + mean += recording.getSum(stat); + } + } + return (num_periods + ? typename RelatedTypes<typename T::value_t>::fractional_t(mean / num_periods) + : typename RelatedTypes<typename T::value_t>::fractional_t(NaN)); + } + + template<typename T> + typename RelatedTypes<T>::fractional_t getPeriodMean(const CountStatHandle<T>& stat, S32 num_periods = S32_MAX) + { + return typename RelatedTypes<T>::fractional_t(getPeriodMean(static_cast<const StatType<CountAccumulator>&>(stat), num_periods)); + } + F64 getPeriodMean(const StatType<SampleAccumulator>& stat, S32 num_periods = S32_MAX); + template<typename T> + typename RelatedTypes<T>::fractional_t getPeriodMean(const SampleStatHandle<T>& stat, S32 num_periods = S32_MAX) + { + return typename RelatedTypes<T>::fractional_t(getPeriodMean(static_cast<const StatType<SampleAccumulator>&>(stat), num_periods)); + } + + F64 getPeriodMean(const StatType<EventAccumulator>& stat, S32 num_periods = S32_MAX); + template<typename T> + typename RelatedTypes<T>::fractional_t getPeriodMean(const EventStatHandle<T>& stat, S32 num_periods = S32_MAX) + { + return typename RelatedTypes<T>::fractional_t(getPeriodMean(static_cast<const StatType<EventAccumulator>&>(stat), num_periods)); + } + + F64Kilobytes getPeriodMean(const StatType<MemAccumulator>& stat, S32 num_periods = S32_MAX); + F64Kilobytes getPeriodMean(const MemStatHandle& stat, S32 num_periods = S32_MAX); + + template <typename T> + typename RelatedTypes<typename T::value_t>::fractional_t getPeriodMeanPerSec(const StatType<T>& stat, S32 num_periods = S32_MAX) + { + num_periods = llmin(num_periods, getNumRecordedPeriods()); + + typename RelatedTypes<typename T::value_t>::fractional_t mean = 0; + + for (S32 i = 1; i <= num_periods; i++) + { + Recording& recording = getPrevRecording(i); + if (recording.getDuration() > (F32Seconds)0.f) + { + mean += recording.getPerSec(stat); + } + } + + return (num_periods + ? typename RelatedTypes<typename T::value_t>::fractional_t(mean / num_periods) + : typename RelatedTypes<typename T::value_t>::fractional_t(NaN)); + } + + template<typename T> + typename RelatedTypes<T>::fractional_t getPeriodMeanPerSec(const CountStatHandle<T>& stat, S32 num_periods = S32_MAX) + { + return typename RelatedTypes<T>::fractional_t(getPeriodMeanPerSec(static_cast<const StatType<CountAccumulator>&>(stat), num_periods)); + } + + // + // PERIODIC STANDARD DEVIATION + // + + F64 getPeriodStandardDeviation(const StatType<SampleAccumulator>& stat, S32 num_periods = S32_MAX); + + template<typename T> + typename RelatedTypes<T>::fractional_t getPeriodStandardDeviation(const SampleStatHandle<T>& stat, S32 num_periods = S32_MAX) + { + return typename RelatedTypes<T>::fractional_t(getPeriodStandardDeviation(static_cast<const StatType<SampleAccumulator>&>(stat), num_periods)); + } + + F64 getPeriodStandardDeviation(const StatType<EventAccumulator>& stat, S32 num_periods = S32_MAX); + template<typename T> + typename RelatedTypes<T>::fractional_t getPeriodStandardDeviation(const EventStatHandle<T>& stat, S32 num_periods = S32_MAX) + { + return typename RelatedTypes<T>::fractional_t(getPeriodStandardDeviation(static_cast<const StatType<EventAccumulator>&>(stat), num_periods)); + } + + F64Kilobytes getPeriodStandardDeviation(const StatType<MemAccumulator>& stat, S32 num_periods = S32_MAX); + F64Kilobytes getPeriodStandardDeviation(const MemStatHandle& stat, S32 num_periods = S32_MAX); + + private: + // implementation for LLStopWatchControlsMixin + /*virtual*/ void handleStart(); + /*virtual*/ void handleStop(); + /*virtual*/ void handleReset(); + /*virtual*/ void handleSplitTo(PeriodicRecording& other); + + private: + std::vector<Recording> mRecordingPeriods; + const bool mAutoResize; + S32 mCurPeriod; + S32 mNumRecordedPeriods; + }; + + PeriodicRecording& get_frame_recording(); + + class ExtendableRecording + : public LLStopWatchControlsMixin<ExtendableRecording> + { + public: + void extend(); + + Recording& getAcceptedRecording() { return mAcceptedRecording; } + const Recording& getAcceptedRecording() const {return mAcceptedRecording;} + + Recording& getPotentialRecording() { return mPotentialRecording; } + const Recording& getPotentialRecording() const { return mPotentialRecording;} + + private: + // implementation for LLStopWatchControlsMixin + /*virtual*/ void handleStart(); + /*virtual*/ void handleStop(); + /*virtual*/ void handleReset(); + /*virtual*/ void handleSplitTo(ExtendableRecording& other); + + private: + Recording mAcceptedRecording; + Recording mPotentialRecording; + }; + + class ExtendablePeriodicRecording + : public LLStopWatchControlsMixin<ExtendablePeriodicRecording> + { + public: + ExtendablePeriodicRecording(); + void extend(); + + PeriodicRecording& getResults() { return mAcceptedRecording; } + const PeriodicRecording& getResults() const {return mAcceptedRecording;} + + void nextPeriod() { mPotentialRecording.nextPeriod(); } + + private: + // implementation for LLStopWatchControlsMixin + /*virtual*/ void handleStart(); + /*virtual*/ void handleStop(); + /*virtual*/ void handleReset(); + /*virtual*/ void handleSplitTo(ExtendablePeriodicRecording& other); + + private: + PeriodicRecording mAcceptedRecording; + PeriodicRecording mPotentialRecording; + }; +} + +#endif // LL_LLTRACERECORDING_H diff --git a/indra/llcommon/lltracethreadrecorder.cpp b/indra/llcommon/lltracethreadrecorder.cpp new file mode 100644 index 0000000000..181fc2f058 --- /dev/null +++ b/indra/llcommon/lltracethreadrecorder.cpp @@ -0,0 +1,329 @@ +/** + * @file lltracethreadrecorder.cpp + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2012, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "lltracethreadrecorder.h" +#include "llfasttimer.h" +#include "lltrace.h" + +namespace LLTrace +{ +extern MemStatHandle gTraceMemStat; + +static ThreadRecorder* sMasterThreadRecorder = NULL; + +/////////////////////////////////////////////////////////////////////// +// ThreadRecorder +/////////////////////////////////////////////////////////////////////// + +ThreadRecorder::ThreadRecorder() +: mParentRecorder(NULL) +{ + init(); +} + +void ThreadRecorder::init() +{ +#if LL_TRACE_ENABLED + LLThreadLocalSingletonPointer<BlockTimerStackRecord>::setInstance(&mBlockTimerStackRecord); + //NB: the ordering of initialization in this function is very fragile due to a large number of implicit dependencies + set_thread_recorder(this); + BlockTimerStatHandle& root_time_block = BlockTimer::getRootTimeBlock(); + + BlockTimerStackRecord* timer_stack = LLThreadLocalSingletonPointer<BlockTimerStackRecord>::getInstance(); + timer_stack->mTimeBlock = &root_time_block; + timer_stack->mActiveTimer = NULL; + + mNumTimeBlockTreeNodes = AccumulatorBuffer<TimeBlockAccumulator>::getDefaultBuffer()->size(); + + mTimeBlockTreeNodes = new TimeBlockTreeNode[mNumTimeBlockTreeNodes]; + + activate(&mThreadRecordingBuffers); + + // initialize time block parent pointers + for (BlockTimerStatHandle::instance_tracker_t::instance_iter it = BlockTimerStatHandle::instance_tracker_t::beginInstances(), end_it = BlockTimerStatHandle::instance_tracker_t::endInstances(); + it != end_it; + ++it) + { + BlockTimerStatHandle& time_block = static_cast<BlockTimerStatHandle&>(*it); + TimeBlockTreeNode& tree_node = mTimeBlockTreeNodes[it->getIndex()]; + tree_node.mBlock = &time_block; + tree_node.mParent = &root_time_block; + + it->getCurrentAccumulator().mParent = &root_time_block; + } + + mRootTimer = new BlockTimer(root_time_block); + timer_stack->mActiveTimer = mRootTimer; + + BlockTimer::getRootTimeBlock().getCurrentAccumulator().mActiveCount = 1; + + claim_alloc(gTraceMemStat, this); + claim_alloc(gTraceMemStat, mRootTimer); + claim_alloc(gTraceMemStat, sizeof(TimeBlockTreeNode) * mNumTimeBlockTreeNodes); +#endif +} + + +ThreadRecorder::ThreadRecorder( ThreadRecorder& parent ) +: mParentRecorder(&parent) +{ + init(); + mParentRecorder->addChildRecorder(this); +} + + +ThreadRecorder::~ThreadRecorder() +{ +#if LL_TRACE_ENABLED + LLThreadLocalSingletonPointer<BlockTimerStackRecord>::setInstance(NULL); + + disclaim_alloc(gTraceMemStat, this); + disclaim_alloc(gTraceMemStat, sizeof(BlockTimer)); + disclaim_alloc(gTraceMemStat, sizeof(TimeBlockTreeNode) * mNumTimeBlockTreeNodes); + + deactivate(&mThreadRecordingBuffers); + + delete mRootTimer; + + if (!mActiveRecordings.empty()) + { + std::for_each(mActiveRecordings.begin(), mActiveRecordings.end(), DeletePointer()); + mActiveRecordings.clear(); + } + + set_thread_recorder(NULL); + delete[] mTimeBlockTreeNodes; + + if (mParentRecorder) + { + mParentRecorder->removeChildRecorder(this); + } +#endif +} + +TimeBlockTreeNode* ThreadRecorder::getTimeBlockTreeNode( S32 index ) +{ +#if LL_TRACE_ENABLED + if (0 <= index && index < mNumTimeBlockTreeNodes) + { + return &mTimeBlockTreeNodes[index]; + } +#endif + return NULL; +} + +AccumulatorBufferGroup* ThreadRecorder::activate( AccumulatorBufferGroup* recording) +{ +#if LL_TRACE_ENABLED + ActiveRecording* active_recording = new ActiveRecording(recording); + if (!mActiveRecordings.empty()) + { + AccumulatorBufferGroup& prev_active_recording = mActiveRecordings.back()->mPartialRecording; + prev_active_recording.sync(); + BlockTimer::updateTimes(); + prev_active_recording.handOffTo(active_recording->mPartialRecording); + } + mActiveRecordings.push_back(active_recording); + + mActiveRecordings.back()->mPartialRecording.makeCurrent(); + return &active_recording->mPartialRecording; +#else + return NULL; +#endif +} + +ThreadRecorder::active_recording_list_t::iterator ThreadRecorder::bringUpToDate( AccumulatorBufferGroup* recording ) +{ +#if LL_TRACE_ENABLED + if (mActiveRecordings.empty()) return mActiveRecordings.end(); + + mActiveRecordings.back()->mPartialRecording.sync(); + BlockTimer::updateTimes(); + + active_recording_list_t::reverse_iterator it, end_it; + for (it = mActiveRecordings.rbegin(), end_it = mActiveRecordings.rend(); + it != end_it; + ++it) + { + ActiveRecording* cur_recording = *it; + + active_recording_list_t::reverse_iterator next_it = it; + ++next_it; + + // if we have another recording further down in the stack... + if (next_it != mActiveRecordings.rend()) + { + // ...push our gathered data down to it + (*next_it)->mPartialRecording.append(cur_recording->mPartialRecording); + } + + // copy accumulated measurements into result buffer and clear accumulator (mPartialRecording) + cur_recording->movePartialToTarget(); + + if (cur_recording->mTargetRecording == recording) + { + // found the recording, so return it + break; + } + } + + if (it == end_it) + { + LL_WARNS() << "Recording not active on this thread" << LL_ENDL; + } + + return (++it).base(); +#else + return ThreadRecorder::active_recording_list_t::iterator(); +#endif +} + +void ThreadRecorder::deactivate( AccumulatorBufferGroup* recording ) +{ +#if LL_TRACE_ENABLED + active_recording_list_t::iterator recording_it = bringUpToDate(recording); + // this method should only be called on a thread where the recorder is active + llassert_always(recording_it != mActiveRecordings.end()); + + ActiveRecording* recording_to_remove = *recording_it; + bool was_current = recording_to_remove->mPartialRecording.isCurrent(); + llassert(recording_to_remove->mTargetRecording == recording); + mActiveRecordings.erase(recording_it); + if (was_current) + { + if (mActiveRecordings.empty()) + { + AccumulatorBufferGroup::clearCurrent(); + } + else + { + mActiveRecordings.back()->mPartialRecording.makeCurrent(); + } + } + delete recording_to_remove; +#endif +} + +ThreadRecorder::ActiveRecording::ActiveRecording( AccumulatorBufferGroup* target ) +: mTargetRecording(target) +{} + +void ThreadRecorder::ActiveRecording::movePartialToTarget() +{ +#if LL_TRACE_ENABLED + mTargetRecording->append(mPartialRecording); + // reset based on self to keep history + mPartialRecording.reset(&mPartialRecording); +#endif +} + + +// called by child thread +void ThreadRecorder::addChildRecorder( class ThreadRecorder* child ) +{ +#if LL_TRACE_ENABLED + { LLMutexLock lock(&mChildListMutex); + mChildThreadRecorders.push_back(child); + } +#endif +} + +// called by child thread +void ThreadRecorder::removeChildRecorder( class ThreadRecorder* child ) +{ +#if LL_TRACE_ENABLED + { LLMutexLock lock(&mChildListMutex); + mChildThreadRecorders.remove(child); + } +#endif +} + +void ThreadRecorder::pushToParent() +{ +#if LL_TRACE_ENABLED + { LLMutexLock lock(&mSharedRecordingMutex); + LLTrace::get_thread_recorder()->bringUpToDate(&mThreadRecordingBuffers); + mSharedRecordingBuffers.append(mThreadRecordingBuffers); + mThreadRecordingBuffers.reset(); + } +#endif +} + + +static LLTrace::BlockTimerStatHandle FTM_PULL_TRACE_DATA_FROM_CHILDREN("Pull child thread trace data"); + +void ThreadRecorder::pullFromChildren() +{ +#if LL_TRACE_ENABLED + LL_RECORD_BLOCK_TIME(FTM_PULL_TRACE_DATA_FROM_CHILDREN); + if (mActiveRecordings.empty()) return; + + { LLMutexLock lock(&mChildListMutex); + + AccumulatorBufferGroup& target_recording_buffers = mActiveRecordings.back()->mPartialRecording; + target_recording_buffers.sync(); + for (child_thread_recorder_list_t::iterator it = mChildThreadRecorders.begin(), end_it = mChildThreadRecorders.end(); + it != end_it; + ++it) + { LLMutexLock lock(&(*it)->mSharedRecordingMutex); + + target_recording_buffers.merge((*it)->mSharedRecordingBuffers); + (*it)->mSharedRecordingBuffers.reset(); + } + } +#endif +} + + +void set_master_thread_recorder( ThreadRecorder* recorder ) +{ + sMasterThreadRecorder = recorder; +} + + +ThreadRecorder* get_master_thread_recorder() +{ + return sMasterThreadRecorder; +} + +LLThreadLocalPointer<ThreadRecorder>& get_thread_recorder_ptr() +{ + static LLThreadLocalPointer<ThreadRecorder> s_thread_recorder; + return s_thread_recorder; +} + +const LLThreadLocalPointer<ThreadRecorder>& get_thread_recorder() +{ + return get_thread_recorder_ptr(); +} + +void set_thread_recorder( ThreadRecorder* recorder ) +{ + get_thread_recorder_ptr() = recorder; +} + +} diff --git a/indra/llcommon/lltracethreadrecorder.h b/indra/llcommon/lltracethreadrecorder.h new file mode 100644 index 0000000000..a797c6687e --- /dev/null +++ b/indra/llcommon/lltracethreadrecorder.h @@ -0,0 +1,102 @@ +/** + * @file lltrace.h + * @brief Runtime statistics accumulation. + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2012, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLTRACETHREADRECORDER_H +#define LL_LLTRACETHREADRECORDER_H + +#include "stdtypes.h" +#include "llpreprocessor.h" + +#include "llmutex.h" +#include "lltraceaccumulators.h" +#include "llthreadlocalstorage.h" + +namespace LLTrace +{ + class LL_COMMON_API ThreadRecorder + { + protected: + struct ActiveRecording; + typedef std::vector<ActiveRecording*> active_recording_list_t; + public: + ThreadRecorder(); + explicit ThreadRecorder(ThreadRecorder& parent); + + ~ThreadRecorder(); + + AccumulatorBufferGroup* activate(AccumulatorBufferGroup* recording); + void deactivate(AccumulatorBufferGroup* recording); + active_recording_list_t::iterator bringUpToDate(AccumulatorBufferGroup* recording); + + void addChildRecorder(class ThreadRecorder* child); + void removeChildRecorder(class ThreadRecorder* child); + + // call this periodically to gather stats data from child threads + void pullFromChildren(); + void pushToParent(); + + TimeBlockTreeNode* getTimeBlockTreeNode(S32 index); + + protected: + void init(); + + protected: + struct ActiveRecording + { + ActiveRecording(AccumulatorBufferGroup* target); + + AccumulatorBufferGroup* mTargetRecording; + AccumulatorBufferGroup mPartialRecording; + + void movePartialToTarget(); + }; + + AccumulatorBufferGroup mThreadRecordingBuffers; + + BlockTimerStackRecord mBlockTimerStackRecord; + active_recording_list_t mActiveRecordings; + + class BlockTimer* mRootTimer; + TimeBlockTreeNode* mTimeBlockTreeNodes; + size_t mNumTimeBlockTreeNodes; + typedef std::list<class ThreadRecorder*> child_thread_recorder_list_t; + + child_thread_recorder_list_t mChildThreadRecorders; // list of child thread recorders associated with this master + LLMutex mChildListMutex; // protects access to child list + LLMutex mSharedRecordingMutex; + AccumulatorBufferGroup mSharedRecordingBuffers; + ThreadRecorder* mParentRecorder; + + }; + + const LLThreadLocalPointer<ThreadRecorder>& get_thread_recorder(); + void set_thread_recorder(ThreadRecorder*); + + void set_master_thread_recorder(ThreadRecorder*); + ThreadRecorder* get_master_thread_recorder(); +} + +#endif // LL_LLTRACETHREADRECORDER_H diff --git a/indra/llcommon/lltypeinfolookup.h b/indra/llcommon/lltypeinfolookup.h deleted file mode 100755 index 0b6862444e..0000000000 --- a/indra/llcommon/lltypeinfolookup.h +++ /dev/null @@ -1,117 +0,0 @@ -/** - * @file lltypeinfolookup.h - * @author Nat Goodspeed - * @date 2012-04-08 - * @brief Template data structure like std::map<std::type_info*, T> - * - * $LicenseInfo:firstyear=2012&license=viewerlgpl$ - * Copyright (c) 2012, Linden Research, Inc. - * $/LicenseInfo$ - */ - -#if ! defined(LL_LLTYPEINFOLOOKUP_H) -#define LL_LLTYPEINFOLOOKUP_H - -#include <boost/unordered_map.hpp> -#include <boost/functional/hash.hpp> -#include <boost/optional.hpp> -#include <functional> // std::binary_function -#include <typeinfo> - -/** - * The following helper classes are based on the Boost.Unordered documentation: - * http://www.boost.org/doc/libs/1_45_0/doc/html/unordered/hash_equality.html - */ - -/** - * Compute hash for a string passed as const char* - */ -struct const_char_star_hash: public std::unary_function<const char*, std::size_t> -{ - std::size_t operator()(const char* str) const - { - std::size_t seed = 0; - for ( ; *str; ++str) - { - boost::hash_combine(seed, *str); - } - return seed; - } -}; - -/** - * Compute equality for strings passed as const char* - * - * I (nat) suspect that this is where the default behavior breaks for the - * const char* values returned from std::type_info::name(). If you compare the - * two const char* pointer values, as a naive, unspecialized implementation - * will surely do, they'll compare unequal. - */ -struct const_char_star_equal: public std::binary_function<const char*, const char*, bool> -{ - bool operator()(const char* lhs, const char* rhs) const - { - return strcmp(lhs, rhs) == 0; - } -}; - -/** - * LLTypeInfoLookup is specifically designed for use cases for which you might - * consider std::map<std::type_info*, VALUE>. We have several such data - * structures in the viewer. The trouble with them is that at least on Linux, - * you can't rely on always getting the same std::type_info* for a given type: - * different load modules will produce different std::type_info*. - * LLTypeInfoLookup contains a workaround to address this issue. - * - * The API deliberately diverges from std::map in several respects: - * * It avoids iterators, not only begin()/end() but also as return values - * from insert() and find(). This bypasses transform_iterator overhead. - * * Since we literally use compile-time types as keys, the essential insert() - * and find() methods accept the key type as a @em template parameter, - * accepting and returning value_type as a normal runtime value. This is to - * permit future optimization (e.g. compile-time type hashing) without - * changing the API. - */ -template <typename VALUE> -class LLTypeInfoLookup -{ - // Use this for our underlying implementation: lookup by - // std::type_info::name() string. This is one of the rare cases in which I - // dare use const char* directly, rather than std::string, because I'm - // sure that every value returned by std::type_info::name() is static. - // HOWEVER, specify our own hash + equality functors: naively comparing - // distinct const char* values won't work. - typedef boost::unordered_map<const char*, VALUE, - const_char_star_hash, const_char_star_equal> impl_map_type; - -public: - typedef VALUE value_type; - - LLTypeInfoLookup() {} - - bool empty() const { return mMap.empty(); } - std::size_t size() const { return mMap.size(); } - - template <typename KEY> - bool insert(const value_type& value) - { - // Obtain and store the std::type_info::name() string as the key. - // Return just the bool from std::map::insert()'s return pair. - return mMap.insert(typename impl_map_type::value_type(typeid(KEY).name(), value)).second; - } - - template <typename KEY> - boost::optional<value_type> find() const - { - // Use the std::type_info::name() string as the key. - typename impl_map_type::const_iterator found = mMap.find(typeid(KEY).name()); - if (found == mMap.end()) - return boost::optional<value_type>(); - return found->second; - } - -private: - impl_map_type mMap; -}; - -#endif /* ! defined(LL_LLTYPEINFOLOOKUP_H) */ diff --git a/indra/llcommon/llunits.h b/indra/llcommon/llunits.h new file mode 100644 index 0000000000..0fcb8281a0 --- /dev/null +++ b/indra/llcommon/llunits.h @@ -0,0 +1,129 @@ +/** + * @file llunits.h + * @brief Unit definitions + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2012, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_LLUNITTYPE_H +#define LL_LLUNITTYPE_H + +#include "stdtypes.h" +#include "llunittype.h" + +// +// Unit declarations +// + +namespace LLUnits +{ +LL_DECLARE_BASE_UNIT(Bytes, "B"); +// technically, these are kibibytes, mibibytes, etc. but we should stick with commonly accepted terminology +LL_DECLARE_DERIVED_UNIT(Kilobytes, "KB", Bytes, / 1024); +LL_DECLARE_DERIVED_UNIT(Megabytes, "MB", Kilobytes, / 1024); +LL_DECLARE_DERIVED_UNIT(Gigabytes, "GB", Megabytes, / 1024); +} + +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Bytes); +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Kilobytes); +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Megabytes); +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Gigabytes); + +namespace LLUnits +{ +// technically, these are kibibits, mibibits, etc. but we should stick with commonly accepted terminology +LL_DECLARE_DERIVED_UNIT(Bits, "b", Bytes, * 8 ); +LL_DECLARE_DERIVED_UNIT(Kilobits, "Kb", Bits, / 1024); +LL_DECLARE_DERIVED_UNIT(Megabits, "Mb", Kilobits, / 1024); +LL_DECLARE_DERIVED_UNIT(Gigabits, "Gb", Megabits, / 1024); +} + +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Bits); +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Kilobits); +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Megabits); +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Gigabits); + +namespace LLUnits +{ +LL_DECLARE_BASE_UNIT(Seconds, "s"); +LL_DECLARE_DERIVED_UNIT(Minutes, "min", Seconds, / 60); +LL_DECLARE_DERIVED_UNIT(Hours, "h", Minutes, / 60); +LL_DECLARE_DERIVED_UNIT(Days, "d", Hours, / 24); +LL_DECLARE_DERIVED_UNIT(Milliseconds, "ms", Seconds, * 1000); +LL_DECLARE_DERIVED_UNIT(Microseconds, "\x09\x3cs", Milliseconds, * 1000); +LL_DECLARE_DERIVED_UNIT(Nanoseconds, "ns", Microseconds, * 1000); +} + +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Seconds); +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Minutes); +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Hours); +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Days); +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Milliseconds); +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Microseconds); +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Nanoseconds); + +namespace LLUnits +{ +LL_DECLARE_BASE_UNIT(Meters, "m"); +LL_DECLARE_DERIVED_UNIT(Kilometers, "km", Meters, / 1000); +LL_DECLARE_DERIVED_UNIT(Centimeters, "cm", Meters, * 100); +LL_DECLARE_DERIVED_UNIT(Millimeters, "mm", Meters, * 1000); +} + +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Meters); +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Kilometers); +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Centimeters); +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Millimeters); + +namespace LLUnits +{ +// rare units +LL_DECLARE_BASE_UNIT(Hertz, "Hz"); +LL_DECLARE_DERIVED_UNIT(Kilohertz, "KHz", Hertz, / 1000); +LL_DECLARE_DERIVED_UNIT(Megahertz, "MHz", Kilohertz, / 1000); +LL_DECLARE_DERIVED_UNIT(Gigahertz, "GHz", Megahertz, / 1000); + +LL_DECLARE_BASE_UNIT(Radians, "rad"); +LL_DECLARE_DERIVED_UNIT(Degrees, "deg", Radians, * 57.29578f); + +LL_DECLARE_BASE_UNIT(Percent, "%"); +LL_DECLARE_DERIVED_UNIT(Ratio, "x", Percent, / 100); + +LL_DECLARE_BASE_UNIT(Triangles, "tris"); +LL_DECLARE_DERIVED_UNIT(Kilotriangles, "ktris", Triangles, / 1000); + +} // namespace LLUnits + +// rare units +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Hertz); +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Kilohertz); +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Megahertz); +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Gigahertz); +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Radians); +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Degrees); +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Percent); +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Ratio); +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Triangles); +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Kilotriangles); + + +#endif // LL_LLUNITTYPE_H diff --git a/indra/llcommon/llunittype.h b/indra/llcommon/llunittype.h new file mode 100644 index 0000000000..0e05ecd683 --- /dev/null +++ b/indra/llcommon/llunittype.h @@ -0,0 +1,836 @@ +/** + * @file llunit.h + * @brief Unit conversion classes + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2012, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_UNITTYPE_H +#define LL_UNITTYPE_H + +#include "stdtypes.h" +#include "llpreprocessor.h" +#include "llerror.h" + +//lightweight replacement of type traits for simple type equality check +template<typename S, typename T> +struct LLIsSameType +{ + static const bool value = false; +}; + +template<typename T> +struct LLIsSameType<T, T> +{ + static const bool value = true; +}; + +// workaround for decltype() not existing and typeof() not working inline in gcc 4.2 +template<typename S, typename T> +struct LLResultTypeAdd +{ + typedef LL_TYPEOF(S() + T()) type_t; +}; + +template<typename S, typename T> +struct LLResultTypeSubtract +{ + typedef LL_TYPEOF(S() - T()) type_t; +}; + +template<typename S, typename T> +struct LLResultTypeMultiply +{ + typedef LL_TYPEOF(S() * T()) type_t; +}; + +template<typename S, typename T> +struct LLResultTypeDivide +{ + typedef LL_TYPEOF(S() / T(1)) type_t; +}; + +template<typename S, typename T> +struct LLResultTypePromote +{ + typedef LL_TYPEOF((true) ? S() : T()) type_t; +}; + +template<typename STORAGE_TYPE, typename UNITS> +struct LLUnit +{ + typedef LLUnit<STORAGE_TYPE, UNITS> self_t; + typedef STORAGE_TYPE storage_t; + typedef void is_unit_t; + + // value initialization + LL_FORCE_INLINE explicit LLUnit(storage_t value = storage_t()) + : mValue(value) + {} + + // unit initialization and conversion + template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> + LL_FORCE_INLINE LLUnit(LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) + : mValue(convert(other).mValue) + {} + + LL_FORCE_INLINE storage_t value() const + { + return mValue; + } + + LL_FORCE_INLINE void value(storage_t value) + { + mValue = value; + } + + template<typename NEW_UNITS> + storage_t valueInUnits() + { + return LLUnit<storage_t, NEW_UNITS>(*this).value(); + } + + template<typename NEW_UNITS> + void valueInUnits(storage_t value) + { + *this = LLUnit<storage_t, NEW_UNITS>(value); + } + + LL_FORCE_INLINE void operator += (self_t other) + { + mValue += convert(other).mValue; + } + + LL_FORCE_INLINE void operator -= (self_t other) + { + mValue -= convert(other).mValue; + } + + LL_FORCE_INLINE void operator *= (storage_t multiplicand) + { + mValue *= multiplicand; + } + + LL_FORCE_INLINE void operator *= (self_t multiplicand) + { + // spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template + LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE, "Multiplication of unit types not supported."); + } + + LL_FORCE_INLINE void operator /= (storage_t divisor) + { + mValue /= divisor; + } + + void operator /= (self_t divisor) + { + // spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template + LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE, "Illegal in-place division of unit types."); + } + + template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> + LL_FORCE_INLINE bool operator == (LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) const + { + return mValue == convert(other).value(); + } + + template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> + LL_FORCE_INLINE bool operator != (LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) const + { + return mValue != convert(other).value(); + } + + template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> + LL_FORCE_INLINE bool operator < (LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) const + { + return mValue < convert(other).value(); + } + + template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> + LL_FORCE_INLINE bool operator <= (LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) const + { + return mValue <= convert(other).value(); + } + + template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> + LL_FORCE_INLINE bool operator > (LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) const + { + return mValue > convert(other).value(); + } + + template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> + LL_FORCE_INLINE bool operator >= (LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) const + { + return mValue >= convert(other).value(); + } + + LL_FORCE_INLINE static self_t convert(self_t v) + { + return v; + } + + template<typename FROM_STORAGE_TYPE> + LL_FORCE_INLINE static self_t convert(LLUnit<FROM_STORAGE_TYPE, UNITS> v) + { + self_t result; + result.mValue = (STORAGE_TYPE)v.value(); + return result; + } + + template<typename FROM_UNITS> + LL_FORCE_INLINE static self_t convert(LLUnit<STORAGE_TYPE, FROM_UNITS> v) + { + self_t result; + STORAGE_TYPE divisor = ll_convert_units(v, result); + result.mValue /= divisor; + return result; + } + + template<typename FROM_STORAGE_TYPE, typename FROM_UNITS> + LL_FORCE_INLINE static self_t convert(LLUnit<FROM_STORAGE_TYPE, FROM_UNITS> v) + { + typedef typename LLResultTypePromote<FROM_STORAGE_TYPE, STORAGE_TYPE>::type_t result_storage_t; + LLUnit<result_storage_t, UNITS> result; + result_storage_t divisor = ll_convert_units(v, result); + result.value(result.value() / divisor); + return self_t(result.value()); + } + +protected: + storage_t mValue; +}; + +template<typename STORAGE_TYPE, typename UNITS> +std::ostream& operator <<(std::ostream& s, const LLUnit<STORAGE_TYPE, UNITS>& unit) +{ + s << unit.value() << UNITS::getUnitLabel(); + return s; +} + +template<typename STORAGE_TYPE, typename UNITS> +std::istream& operator >>(std::istream& s, LLUnit<STORAGE_TYPE, UNITS>& unit) +{ + STORAGE_TYPE val; + s >> val; + unit.value(val); + return s; +} + +template<typename STORAGE_TYPE, typename UNITS> +struct LLUnitImplicit : public LLUnit<STORAGE_TYPE, UNITS> +{ + typedef LLUnitImplicit<STORAGE_TYPE, UNITS> self_t; + typedef typename LLUnit<STORAGE_TYPE, UNITS>::storage_t storage_t; + typedef LLUnit<STORAGE_TYPE, UNITS> base_t; + + LL_FORCE_INLINE LLUnitImplicit(storage_t value = storage_t()) + : base_t(value) + {} + + template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> + LL_FORCE_INLINE LLUnitImplicit(LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) + : base_t(other) + {} + + // unlike LLUnit, LLUnitImplicit is *implicitly* convertable to a POD value (F32, S32, etc) + // this allows for interoperability with legacy code + LL_FORCE_INLINE operator storage_t() const + { + return base_t::value(); + } + + using base_t::operator +=; + LL_FORCE_INLINE void operator += (storage_t value) + { + base_t::mValue += value; + } + + // this overload exists to explicitly catch use of another implicit unit + // without ambiguity between conversion to storage_t vs conversion to base_t + template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> + LL_FORCE_INLINE void operator += (LLUnitImplicit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) + { + base_t::mValue += convert(other).value(); + } + + using base_t::operator -=; + LL_FORCE_INLINE void operator -= (storage_t value) + { + base_t::mValue -= value; + } + + // this overload exists to explicitly catch use of another implicit unit + // without ambiguity between conversion to storage_t vs conversion to base_t + template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> + LL_FORCE_INLINE void operator -= (LLUnitImplicit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) + { + base_t::mValue -= convert(other).value(); + } + + template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> + LL_FORCE_INLINE bool operator == (LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) const + { + return base_t::mValue == convert(other).value(); + } + + template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> + LL_FORCE_INLINE bool operator == (LLUnitImplicit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) const + { + return base_t::mValue == convert(other).value(); + } + + template<typename STORAGE_T> + LL_FORCE_INLINE bool operator == (STORAGE_T other) const + { + return base_t::mValue == other; + } + + template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> + LL_FORCE_INLINE bool operator != (LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) const + { + return base_t::mValue != convert(other).value(); + } + + template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> + LL_FORCE_INLINE bool operator != (LLUnitImplicit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) const + { + return base_t::mValue != convert(other).value(); + } + + template<typename STORAGE_T> + LL_FORCE_INLINE bool operator != (STORAGE_T other) const + { + return base_t::mValue != other; + } + + template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> + LL_FORCE_INLINE bool operator < (LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) const + { + return base_t::mValue < convert(other).value(); + } + + template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> + LL_FORCE_INLINE bool operator < (LLUnitImplicit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) const + { + return base_t::mValue < convert(other).value(); + } + + template<typename STORAGE_T> + LL_FORCE_INLINE bool operator < (STORAGE_T other) const + { + return base_t::mValue < other; + } + + template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> + LL_FORCE_INLINE bool operator <= (LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) const + { + return base_t::mValue <= convert(other).value(); + } + + template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> + LL_FORCE_INLINE bool operator <= (LLUnitImplicit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) const + { + return base_t::mValue <= convert(other).value(); + } + + template<typename STORAGE_T> + LL_FORCE_INLINE bool operator <= (STORAGE_T other) const + { + return base_t::mValue <= other; + } + + template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> + LL_FORCE_INLINE bool operator > (LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) const + { + return base_t::mValue > convert(other).value(); + } + + template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> + LL_FORCE_INLINE bool operator > (LLUnitImplicit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) const + { + return base_t::mValue > convert(other).value(); + } + + template<typename STORAGE_T> + LL_FORCE_INLINE bool operator > (STORAGE_T other) const + { + return base_t::mValue > other; + } + + template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> + LL_FORCE_INLINE bool operator >= (LLUnit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) const + { + return base_t::mValue >= convert(other).value(); + } + + template<typename OTHER_STORAGE_TYPE, typename OTHER_UNITS> + LL_FORCE_INLINE bool operator >= (LLUnitImplicit<OTHER_STORAGE_TYPE, OTHER_UNITS> other) const + { + return base_t::mValue >= convert(other).value(); + } + + template<typename STORAGE_T> + LL_FORCE_INLINE bool operator >= (STORAGE_T other) const + { + return base_t::mValue >= other; + } +}; + +template<typename STORAGE_TYPE, typename UNITS> +std::ostream& operator <<(std::ostream& s, const LLUnitImplicit<STORAGE_TYPE, UNITS>& unit) +{ + s << unit.value() << UNITS::getUnitLabel(); + return s; +} + +template<typename STORAGE_TYPE, typename UNITS> +std::istream& operator >>(std::istream& s, LLUnitImplicit<STORAGE_TYPE, UNITS>& unit) +{ + STORAGE_TYPE val; + s >> val; + unit = val; + return s; +} + +template<typename S1, typename T1, typename S2, typename T2> +LL_FORCE_INLINE S2 ll_convert_units(LLUnit<S1, T1> in, LLUnit<S2, T2>& out) +{ + S2 divisor(1); + + LL_STATIC_ASSERT((LLIsSameType<T1, T2>::value + || !LLIsSameType<T1, typename T1::base_unit_t>::value + || !LLIsSameType<T2, typename T2::base_unit_t>::value), + "conversion requires compatible units"); + + if (LLIsSameType<T1, T2>::value) + { + // T1 and T2 same type, just assign + out.value((S2)in.value()); + } + else if (T1::sLevel > T2::sLevel) + { + // reduce T1 + LLUnit<S2, typename T1::base_unit_t> new_in; + divisor *= (S2)ll_convert_units(in, new_in); + divisor *= (S2)ll_convert_units(new_in, out); + } + else + { + // reduce T2 + LLUnit<S2, typename T2::base_unit_t> new_out; + divisor *= (S2)ll_convert_units(in, new_out); + divisor *= (S2)ll_convert_units(new_out, out); + } + return divisor; +} + +template<typename T> +struct LLStorageType +{ + typedef T type_t; +}; + +template<typename STORAGE_TYPE, typename UNITS> +struct LLStorageType<LLUnit<STORAGE_TYPE, UNITS> > +{ + typedef STORAGE_TYPE type_t; +}; + +// all of these operators need to perform type promotion on the storage type of the units, so they +// cannot be expressed as operations on identical types with implicit unit conversion +// e.g. typeof(S32Bytes(x) + F32Megabytes(y)) <==> F32Bytes + +// +// operator + +// +template<typename STORAGE_TYPE1, typename UNITS1, typename STORAGE_TYPE2, typename UNITS2> +LL_FORCE_INLINE LLUnit<typename LLResultTypeAdd<STORAGE_TYPE1, STORAGE_TYPE2>::type_t, UNITS1> operator + (LLUnit<STORAGE_TYPE1, UNITS1> first, LLUnit<STORAGE_TYPE2, UNITS2> second) +{ + LLUnit<typename LLResultTypeAdd<STORAGE_TYPE1, STORAGE_TYPE2>::type_t, UNITS1> result(first); + result += second; + return result; +} + +template<typename STORAGE_TYPE, typename UNITS, typename UNITLESS> +LLUnit<STORAGE_TYPE, UNITS> operator + (LLUnit<STORAGE_TYPE, UNITS> first, UNITLESS second) +{ + LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE, "operator + requires compatible unit types"); + return LLUnit<STORAGE_TYPE, UNITS>(0); +} + +template<typename STORAGE_TYPE, typename UNITS, typename UNITLESS> +LLUnit<STORAGE_TYPE, UNITS> operator + (UNITLESS first, LLUnit<STORAGE_TYPE, UNITS> second) +{ + LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE, "operator + requires compatible unit types"); + return LLUnit<STORAGE_TYPE, UNITS>(0); +} + +template<typename STORAGE_TYPE1, typename UNITS1, typename STORAGE_TYPE2, typename UNITS2> +LL_FORCE_INLINE LLUnitImplicit<typename LLResultTypeAdd<STORAGE_TYPE1, STORAGE_TYPE2>::type_t, UNITS1> operator + (LLUnitImplicit<STORAGE_TYPE1, UNITS1> first, LLUnitImplicit<STORAGE_TYPE2, UNITS2> second) +{ + LLUnitImplicit<typename LLResultTypeAdd<STORAGE_TYPE1, STORAGE_TYPE2>::type_t, UNITS1> result(first); + result += second; + return result; +} + +template<typename STORAGE_TYPE1, typename UNITS1, typename STORAGE_TYPE2, typename UNITS2> +LL_FORCE_INLINE LLUnitImplicit<typename LLResultTypeAdd<STORAGE_TYPE1, STORAGE_TYPE2>::type_t, UNITS1> operator + (LLUnit<STORAGE_TYPE1, UNITS1> first, LLUnitImplicit<STORAGE_TYPE2, UNITS2> second) +{ + LLUnitImplicit<typename LLResultTypeAdd<STORAGE_TYPE1, STORAGE_TYPE2>::type_t, UNITS1> result(first); + result += second; + return result; +} + +template<typename STORAGE_TYPE1, typename UNITS1, typename STORAGE_TYPE2, typename UNITS2> +LL_FORCE_INLINE LLUnitImplicit<typename LLResultTypeAdd<STORAGE_TYPE1, STORAGE_TYPE2>::type_t, UNITS1> operator + (LLUnitImplicit<STORAGE_TYPE1, UNITS1> first, LLUnit<STORAGE_TYPE2, UNITS2> second) +{ + LLUnitImplicit<typename LLResultTypeAdd<STORAGE_TYPE1, STORAGE_TYPE2>::type_t, UNITS1> result(first); + result += LLUnitImplicit<STORAGE_TYPE1, UNITS1>(second); + return result; +} + +template<typename STORAGE_TYPE, typename UNITS, typename UNITLESS_TYPE> +LL_FORCE_INLINE LLUnitImplicit<typename LLResultTypeAdd<STORAGE_TYPE, typename LLStorageType<UNITLESS_TYPE>::type_t>::type_t, UNITS> operator + (LLUnitImplicit<STORAGE_TYPE, UNITS> first, UNITLESS_TYPE second) +{ + LLUnitImplicit<typename LLResultTypeAdd<STORAGE_TYPE, typename LLStorageType<UNITLESS_TYPE>::type_t>::type_t, UNITS> result(first); + result += second; + return result; +} + +template<typename STORAGE_TYPE, typename UNITS, typename UNITLESS_TYPE> +LL_FORCE_INLINE LLUnitImplicit<typename LLResultTypeAdd<typename LLStorageType<UNITLESS_TYPE>::type_t, STORAGE_TYPE>:: + type_t, UNITS> operator + (UNITLESS_TYPE first, LLUnitImplicit<STORAGE_TYPE, UNITS> second) +{ + LLUnitImplicit<typename LLResultTypeAdd<typename LLStorageType<UNITLESS_TYPE>::type_t, STORAGE_TYPE>::type_t, UNITS> result(first); + result += second; + return result; +} + +// +// operator - +// +template<typename STORAGE_TYPE1, typename UNITS1, typename STORAGE_TYPE2, typename UNITS2> +LL_FORCE_INLINE LLUnit<typename LLResultTypeSubtract<STORAGE_TYPE1, STORAGE_TYPE2>::type_t, UNITS1> operator - (LLUnit<STORAGE_TYPE1, UNITS1> first, LLUnit<STORAGE_TYPE2, UNITS2> second) +{ + LLUnit<typename LLResultTypeSubtract<STORAGE_TYPE1, STORAGE_TYPE2>::type_t, UNITS1> result(first); + result -= second; + return result; +} + +template<typename STORAGE_TYPE, typename UNITS, typename UNITLESS> +LLUnit<STORAGE_TYPE, UNITS> operator - (LLUnit<STORAGE_TYPE, UNITS> first, UNITLESS second) +{ + LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE, "operator - requires compatible unit types"); + return LLUnit<STORAGE_TYPE, UNITS>(0); +} + +template<typename STORAGE_TYPE, typename UNITS, typename UNITLESS> +LLUnit<STORAGE_TYPE, UNITS> operator - (UNITLESS first, LLUnit<STORAGE_TYPE, UNITS> second) +{ + LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE, "operator - requires compatible unit types"); + return LLUnit<STORAGE_TYPE, UNITS>(0); +} + +template<typename STORAGE_TYPE1, typename UNITS1, typename STORAGE_TYPE2, typename UNITS2> +LL_FORCE_INLINE LLUnitImplicit<typename LLResultTypeSubtract<STORAGE_TYPE1, STORAGE_TYPE2>::type_t, UNITS1> operator - (LLUnitImplicit<STORAGE_TYPE1, UNITS1> first, LLUnitImplicit<STORAGE_TYPE2, UNITS2> second) +{ + LLUnitImplicit<typename LLResultTypeSubtract<STORAGE_TYPE1, STORAGE_TYPE2>::type_t, UNITS1> result(first); + result -= second; + return result; +} + +template<typename STORAGE_TYPE1, typename UNITS1, typename STORAGE_TYPE2, typename UNITS2> +LL_FORCE_INLINE LLUnitImplicit<typename LLResultTypeSubtract<STORAGE_TYPE1, STORAGE_TYPE2>::type_t, UNITS1> operator - (LLUnit<STORAGE_TYPE1, UNITS1> first, LLUnitImplicit<STORAGE_TYPE2, UNITS2> second) +{ + LLUnitImplicit<typename LLResultTypeSubtract<STORAGE_TYPE1, STORAGE_TYPE2>::type_t, UNITS1> result(first); + result -= second; + return result; +} + +template<typename STORAGE_TYPE1, typename UNITS1, typename STORAGE_TYPE2, typename UNITS2> +LL_FORCE_INLINE LLUnitImplicit<typename LLResultTypeSubtract<STORAGE_TYPE1, STORAGE_TYPE2>::type_t, UNITS1> operator - (LLUnitImplicit<STORAGE_TYPE1, UNITS1> first, LLUnit<STORAGE_TYPE2, UNITS2> second) +{ + LLUnitImplicit<typename LLResultTypeSubtract<STORAGE_TYPE1, STORAGE_TYPE2>::type_t, UNITS1> result(first); + result -= LLUnitImplicit<STORAGE_TYPE1, UNITS1>(second); + return result; +} + +template<typename STORAGE_TYPE, typename UNITS, typename UNITLESS_TYPE> +LL_FORCE_INLINE LLUnitImplicit<typename LLResultTypeSubtract<STORAGE_TYPE, typename LLStorageType<UNITLESS_TYPE>::type_t>::type_t, UNITS> operator - (LLUnitImplicit<STORAGE_TYPE, UNITS> first, UNITLESS_TYPE second) +{ + LLUnitImplicit<typename LLResultTypeSubtract<STORAGE_TYPE, typename LLStorageType<UNITLESS_TYPE>::type_t>::type_t, UNITS> result(first); + result -= second; + return result; +} + +template<typename STORAGE_TYPE, typename UNITS, typename UNITLESS_TYPE> +LL_FORCE_INLINE LLUnitImplicit<typename LLResultTypeSubtract<typename LLStorageType<UNITLESS_TYPE>::type_t, STORAGE_TYPE>::type_t, UNITS> operator - (UNITLESS_TYPE first, LLUnitImplicit<STORAGE_TYPE, UNITS> second) +{ + LLUnitImplicit<typename LLResultTypeSubtract<typename LLStorageType<UNITLESS_TYPE>::type_t, STORAGE_TYPE>::type_t, UNITS> result(first); + result -= second; + return result; +} + +// +// operator * +// +template<typename STORAGE_TYPE1, typename UNITS1, typename STORAGE_TYPE2, typename UNITS2> +LLUnit<STORAGE_TYPE1, UNITS1> operator * (LLUnit<STORAGE_TYPE1, UNITS1>, LLUnit<STORAGE_TYPE2, UNITS2>) +{ + // spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template + LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE1, "multiplication of unit types results in new unit type - not supported."); + return LLUnit<STORAGE_TYPE1, UNITS1>(); +} + +template<typename STORAGE_TYPE, typename UNITS, typename UNITLESS_TYPE> +LL_FORCE_INLINE LLUnit<typename LLResultTypeMultiply<STORAGE_TYPE, typename LLStorageType<UNITLESS_TYPE>::type_t>::type_t, UNITS> operator * (LLUnit<STORAGE_TYPE, UNITS> first, UNITLESS_TYPE second) +{ + return LLUnit<typename LLResultTypeMultiply<STORAGE_TYPE, typename LLStorageType<UNITLESS_TYPE>::type_t>::type_t, UNITS>(first.value() * second); +} + +template<typename STORAGE_TYPE, typename UNITS, typename UNITLESS_TYPE> +LL_FORCE_INLINE LLUnit<typename LLResultTypeMultiply<typename LLStorageType<UNITLESS_TYPE>::type_t, STORAGE_TYPE>::type_t, UNITS> operator * (UNITLESS_TYPE first, LLUnit<STORAGE_TYPE, UNITS> second) +{ + return LLUnit<typename LLResultTypeMultiply<typename LLStorageType<UNITLESS_TYPE>::type_t, STORAGE_TYPE>::type_t, UNITS>(first * second.value()); +} + +template<typename STORAGE_TYPE1, typename UNITS1, typename STORAGE_TYPE2, typename UNITS2> +LLUnitImplicit<STORAGE_TYPE1, UNITS1> operator * (LLUnitImplicit<STORAGE_TYPE1, UNITS1>, LLUnitImplicit<STORAGE_TYPE2, UNITS2>) +{ + // spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template + LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE1, "multiplication of unit types results in new unit type - not supported."); + return LLUnitImplicit<STORAGE_TYPE1, UNITS1>(); +} + +template<typename STORAGE_TYPE, typename UNITS, typename UNITLESS_TYPE> +LL_FORCE_INLINE LLUnitImplicit<typename LLResultTypeMultiply<STORAGE_TYPE, typename LLStorageType<UNITLESS_TYPE>::type_t>::type_t, UNITS> operator * (LLUnitImplicit<STORAGE_TYPE, UNITS> first, UNITLESS_TYPE second) +{ + return LLUnitImplicit<typename LLResultTypeMultiply<STORAGE_TYPE, UNITLESS_TYPE>::type_t, UNITS>(first.value() * second); +} + +template<typename STORAGE_TYPE, typename UNITS, typename UNITLESS_TYPE> +LL_FORCE_INLINE LLUnitImplicit<typename LLResultTypeMultiply<typename LLStorageType<UNITLESS_TYPE>::type_t, STORAGE_TYPE>::type_t, UNITS> operator * (UNITLESS_TYPE first, LLUnitImplicit<STORAGE_TYPE, UNITS> second) +{ + return LLUnitImplicit<typename LLResultTypeMultiply<typename LLStorageType<UNITLESS_TYPE>::type_t, STORAGE_TYPE>::type_t, UNITS>(first * second.value()); +} + + +// +// operator / +// + +template<typename STORAGE_TYPE, typename UNITS, typename UNITLESS_TYPE> +LL_FORCE_INLINE LLUnit<typename LLResultTypeDivide<STORAGE_TYPE, typename LLStorageType<UNITLESS_TYPE>::type_t>::type_t, UNITS> operator / (LLUnit<STORAGE_TYPE, UNITS> first, UNITLESS_TYPE second) +{ + return LLUnit<typename LLResultTypeDivide<STORAGE_TYPE, typename LLStorageType<UNITLESS_TYPE>::type_t>::type_t, UNITS>(first.value() / second); +} + +template<typename STORAGE_TYPE1, typename UNITS1, typename STORAGE_TYPE2, typename UNITS2> +LL_FORCE_INLINE typename LLResultTypeDivide<STORAGE_TYPE1, STORAGE_TYPE2>::type_t operator / (LLUnit<STORAGE_TYPE1, UNITS1> first, LLUnit<STORAGE_TYPE2, UNITS2> second) +{ + return first.value() / first.convert(second).value(); +} + +template<typename STORAGE_TYPE, typename UNITS, typename UNITLESS_TYPE> +LL_FORCE_INLINE LLUnitImplicit<typename LLResultTypeDivide<STORAGE_TYPE, typename LLStorageType<UNITLESS_TYPE>::type_t>::type_t, UNITS> operator / (LLUnitImplicit<STORAGE_TYPE, UNITS> first, UNITLESS_TYPE second) +{ + return LLUnitImplicit<typename LLResultTypeDivide<STORAGE_TYPE, typename LLStorageType<UNITLESS_TYPE>::type_t>::type_t, UNITS>(first.value() / second); +} + +template<typename STORAGE_TYPE1, typename UNITS1, typename STORAGE_TYPE2, typename UNITS2> +LL_FORCE_INLINE typename LLResultTypeDivide<STORAGE_TYPE1, STORAGE_TYPE2>::type_t operator / (LLUnitImplicit<STORAGE_TYPE1, UNITS1> first, LLUnitImplicit<STORAGE_TYPE2, UNITS2> second) +{ + return (typename LLResultTypeDivide<STORAGE_TYPE1, STORAGE_TYPE2>::type_t)(first.value() / first.convert(second).value()); +} + +template<typename STORAGE_TYPE1, typename UNITS1, typename STORAGE_TYPE2, typename UNITS2> +LL_FORCE_INLINE typename LLResultTypeDivide<STORAGE_TYPE1, STORAGE_TYPE2>::type_t operator / (LLUnit<STORAGE_TYPE1, UNITS1> first, LLUnitImplicit<STORAGE_TYPE2, UNITS2> second) +{ + return (typename LLResultTypeDivide<STORAGE_TYPE1, STORAGE_TYPE2>::type_t)(first.value() / first.convert(second).value()); +} + +template<typename STORAGE_TYPE1, typename UNITS1, typename STORAGE_TYPE2, typename UNITS2> +LL_FORCE_INLINE typename LLResultTypeDivide<STORAGE_TYPE1, STORAGE_TYPE2>::type_t operator / (LLUnitImplicit<STORAGE_TYPE1, UNITS1> first, LLUnit<STORAGE_TYPE2, UNITS2> second) +{ + return (typename LLResultTypeDivide<STORAGE_TYPE1, STORAGE_TYPE2>::type_t)(first.value() / first.convert(second).value()); +} + +template<typename T> +struct LLGetUnitLabel +{ + static const char* getUnitLabel() { return ""; } +}; + +template<typename T, typename STORAGE_T> +struct LLGetUnitLabel<LLUnit<STORAGE_T, T> > +{ + static const char* getUnitLabel() { return T::getUnitLabel(); } +}; + +template<typename T> +struct LLUnitLinearOps +{ + typedef LLUnitLinearOps<T> self_t; + + LLUnitLinearOps(T val) + : mValue(val), + mDivisor(1) + {} + + template<typename OTHER_T> + self_t operator * (OTHER_T other) + { + return mValue * other; + } + + template<typename OTHER_T> + self_t operator / (OTHER_T other) + { + mDivisor *= other; + return *this; + } + + template<typename OTHER_T> + self_t operator + (OTHER_T other) + { + mValue += other * mDivisor; + return *this; + } + + template<typename OTHER_T> + self_t operator - (OTHER_T other) + { + mValue -= other * mDivisor; + return *this; + } + + T mValue; + T mDivisor; +}; + +template<typename T> +struct LLUnitInverseLinearOps +{ + typedef LLUnitInverseLinearOps<T> self_t; + + LLUnitInverseLinearOps(T val) + : mValue(val), + mDivisor(1), + mMultiplicand(1) + {} + + template<typename OTHER_T> + self_t operator * (OTHER_T other) + { + mDivisor *= other; + return *this; + } + + template<typename OTHER_T> + self_t operator / (OTHER_T other) + { + mValue *= other; + mMultiplicand *= other; + return *this; + } + + template<typename OTHER_T> + self_t operator + (OTHER_T other) + { + mValue -= other * mMultiplicand; + return *this; + } + + template<typename OTHER_T> + self_t operator - (OTHER_T other) + { + mValue += other * mMultiplicand; + return *this; + } + + T mValue; + T mDivisor; + T mMultiplicand; +}; + +#define LL_DECLARE_BASE_UNIT(base_unit_name, unit_label) \ +struct base_unit_name \ +{ \ + static const int sLevel = 0; \ + typedef base_unit_name base_unit_t; \ + static const char* getUnitLabel() { return unit_label; } \ + template<typename T> \ + static LLUnit<T, base_unit_name> fromValue(T value) { return LLUnit<T, base_unit_name>(value); } \ + template<typename STORAGE_T, typename UNIT_T> \ + static LLUnit<STORAGE_T, base_unit_name> fromValue(LLUnit<STORAGE_T, UNIT_T> value) \ + { return LLUnit<STORAGE_T, base_unit_name>(value); } \ +} + + +#define LL_DECLARE_DERIVED_UNIT(unit_name, unit_label, base_unit_name, conversion_operation) \ +struct unit_name \ +{ \ + static const int sLevel = base_unit_name::sLevel + 1; \ + typedef base_unit_name base_unit_t; \ + static const char* getUnitLabel() { return unit_label; } \ + template<typename T> \ + static LLUnit<T, unit_name> fromValue(T value) { return LLUnit<T, unit_name>(value); } \ + template<typename STORAGE_T, typename UNIT_T> \ + static LLUnit<STORAGE_T, unit_name> fromValue(LLUnit<STORAGE_T, UNIT_T> value) \ + { return LLUnit<STORAGE_T, unit_name>(value); } \ +}; \ + \ +template<typename S1, typename S2> \ +LL_FORCE_INLINE S2 ll_convert_units(LLUnit<S1, unit_name> in, LLUnit<S2, base_unit_name>& out) \ +{ \ + typedef typename LLResultTypePromote<S1, S2>::type_t result_storage_t; \ + LLUnitInverseLinearOps<result_storage_t> result = \ + LLUnitInverseLinearOps<result_storage_t>(in.value()) conversion_operation; \ + out = LLUnit<S2, base_unit_name>((S2)result.mValue); \ + return result.mDivisor; \ +} \ + \ +template<typename S1, typename S2> \ +LL_FORCE_INLINE S2 ll_convert_units(LLUnit<S1, base_unit_name> in, LLUnit<S2, unit_name>& out) \ +{ \ + typedef typename LLResultTypePromote<S1, S2>::type_t result_storage_t; \ + LLUnitLinearOps<result_storage_t> result = \ + LLUnitLinearOps<result_storage_t>(in.value()) conversion_operation; \ + out = LLUnit<S2, unit_name>((S2)result.mValue); \ + return result.mDivisor; \ +} + +#define LL_DECLARE_UNIT_TYPEDEFS(ns, unit_name) \ + typedef LLUnit<F32, ns::unit_name> F32##unit_name; \ + typedef LLUnitImplicit<F32, ns::unit_name> F32##unit_name##Implicit;\ + typedef LLUnit<F64, ns::unit_name> F64##unit_name; \ + typedef LLUnitImplicit<F64, ns::unit_name> F64##unit_name##Implicit;\ + typedef LLUnit<S32, ns::unit_name> S32##unit_name; \ + typedef LLUnitImplicit<S32, ns::unit_name> S32##unit_name##Implicit;\ + typedef LLUnit<S64, ns::unit_name> S64##unit_name; \ + typedef LLUnitImplicit<S64, ns::unit_name> S64##unit_name##Implicit;\ + typedef LLUnit<U32, ns::unit_name> U32##unit_name; \ + typedef LLUnitImplicit<U32, ns::unit_name> U32##unit_name##Implicit;\ + typedef LLUnit<U64, ns::unit_name> U64##unit_name; \ + typedef LLUnitImplicit<U64, ns::unit_name> U64##unit_name##Implicit + +#endif //LL_UNITTYPE_H diff --git a/indra/llcommon/lluri.cpp b/indra/llcommon/lluri.cpp index 37f5b3d6a3..9f12d49244 100755 --- a/indra/llcommon/lluri.cpp +++ b/indra/llcommon/lluri.cpp @@ -359,7 +359,7 @@ LLURI LLURI::buildHTTP(const std::string& prefix, it != path.endArray(); ++it) { - lldebugs << "PATH: inserting " << it->asString() << llendl; + LL_DEBUGS() << "PATH: inserting " << it->asString() << LL_ENDL; result.mEscapedPath += "/" + escapePathComponent(it->asString()); } } @@ -399,8 +399,8 @@ LLURI LLURI::buildHTTP(const std::string& prefix, } else { - llwarns << "Valid path arguments to buildHTTP are array, string, or undef, you passed type" - << path.type() << llendl; + LL_WARNS() << "Valid path arguments to buildHTTP are array, string, or undef, you passed type" + << path.type() << LL_ENDL; } result.mEscapedOpaque = "//" + result.mEscapedAuthority + result.mEscapedPath; @@ -584,7 +584,7 @@ LLSD LLURI::queryMap() const // static LLSD LLURI::queryMap(std::string escaped_query_string) { - lldebugs << "LLURI::queryMap query params: " << escaped_query_string << llendl; + LL_DEBUGS() << "LLURI::queryMap query params: " << escaped_query_string << LL_ENDL; LLSD result = LLSD::emptyArray(); while(!escaped_query_string.empty()) @@ -610,12 +610,12 @@ LLSD LLURI::queryMap(std::string escaped_query_string) { std::string key = unescape(tuple.substr(0,key_end)); std::string value = unescape(tuple.substr(key_end+1)); - lldebugs << "inserting key " << key << " value " << value << llendl; + LL_DEBUGS() << "inserting key " << key << " value " << value << LL_ENDL; result[key] = value; } else { - lldebugs << "inserting key " << unescape(tuple) << " value true" << llendl; + LL_DEBUGS() << "inserting key " << unescape(tuple) << " value true" << LL_ENDL; result[unescape(tuple)] = true; } } diff --git a/indra/llcommon/lluuid.cpp b/indra/llcommon/lluuid.cpp index 0aaa50d231..e3671047b4 100755 --- a/indra/llcommon/lluuid.cpp +++ b/indra/llcommon/lluuid.cpp @@ -27,9 +27,7 @@ // We can't use WIN32_LEAN_AND_MEAN here, needs lots of includes. #if LL_WINDOWS -#undef WIN32_LEAN_AND_MEAN -#include <winsock2.h> -#include <windows.h> +#include "llwin32headers.h" // ugh, this is ugly. We need to straighten out our linking for this library #pragma comment(lib, "IPHLPAPI.lib") #include <iphlpapi.h> @@ -234,7 +232,7 @@ BOOL LLUUID::set(const std::string& in_string, BOOL emit) { if(emit) { - llwarns << "Warning! Using broken UUID string format" << llendl; + LL_WARNS() << "Warning! Using broken UUID string format" << LL_ENDL; } broken_format = TRUE; } @@ -244,7 +242,7 @@ BOOL LLUUID::set(const std::string& in_string, BOOL emit) if(emit) { //don't spam the logs because a resident can't spell. - llwarns << "Bad UUID string: " << in_string << llendl; + LL_WARNS() << "Bad UUID string: " << in_string << LL_ENDL; } setNull(); return FALSE; @@ -283,7 +281,7 @@ BOOL LLUUID::set(const std::string& in_string, BOOL emit) { if(emit) { - llwarns << "Invalid UUID string character" << llendl; + LL_WARNS() << "Invalid UUID string character" << LL_ENDL; } setNull(); return FALSE; @@ -308,7 +306,7 @@ BOOL LLUUID::set(const std::string& in_string, BOOL emit) { if(emit) { - llwarns << "Invalid UUID string character" << llendl; + LL_WARNS() << "Invalid UUID string character" << LL_ENDL; } setNull(); return FALSE; diff --git a/indra/llcommon/lluuid.h b/indra/llcommon/lluuid.h index 7889828c85..0699dcda83 100755 --- a/indra/llcommon/lluuid.h +++ b/indra/llcommon/lluuid.h @@ -28,6 +28,7 @@ #include <iostream> #include <set> +#include <vector> #include "stdtypes.h" #include "llpreprocessor.h" diff --git a/indra/llcommon/lluuidhashmap.h b/indra/llcommon/lluuidhashmap.h deleted file mode 100755 index e294670030..0000000000 --- a/indra/llcommon/lluuidhashmap.h +++ /dev/null @@ -1,583 +0,0 @@ -/** - * @file lluuidhashmap.h - * @brief A uuid based hash map. - * - * $LicenseInfo:firstyear=2003&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_LLUUIDHASHMAP_H -#define LL_LLUUIDHASHMAP_H - -#include "stdtypes.h" -#include "llerror.h" -#include "lluuid.h" - -// UUID hash map - - /* - LLUUIDHashMap<uuid_pair, 32> foo(test_equals); - LLUUIDHashMapIter<uuid_pair, 32> bar(&foo); - - LLDynamicArray<LLUUID> source_ids; - const S32 COUNT = 100000; - S32 q; - for (q = 0; q < COUNT; q++) - { - llinfos << "Creating" << llendl; - LLUUID id; - id.generate(); - //llinfos << q << ":" << id << llendl; - uuid_pair pair; - pair.mUUID = id; - pair.mValue = q; - foo.set(id, pair); - source_ids.put(id); - //ms_sleep(1); - } - - uuid_pair cur; - llinfos << "Iterating" << llendl; - for (cur = bar.first(); !bar.done(); cur = bar.next()) - { - if (source_ids[cur.mValue] != cur.mUUID) - { - llerrs << "Incorrect value iterated!" << llendl; - } - //llinfos << cur.mValue << ":" << cur.mUUID << llendl; - //ms_sleep(1); - } - - llinfos << "Finding" << llendl; - for (q = 0; q < COUNT; q++) - { - cur = foo.get(source_ids[q]); - if (source_ids[cur.mValue] != cur.mUUID) - { - llerrs << "Incorrect value found!" << llendl; - } - //llinfos << res.mValue << ":" << res.mUUID << llendl; - //ms_sleep(1); - } - - llinfos << "Removing" << llendl; - for (q = 0; q < COUNT/2; q++) - { - if (!foo.remove(source_ids[q])) - { - llerrs << "Remove failed!" << llendl; - } - //ms_sleep(1); - } - - llinfos << "Iterating" << llendl; - for (cur = bar.first(); !bar.done(); cur = bar.next()) - { - if (source_ids[cur.mValue] != cur.mUUID) - { - llerrs << "Incorrect value found!" << llendl; - } - //llinfos << cur.mValue << ":" << cur.mUUID << llendl; - //ms_sleep(1); - } - llinfos << "Done with UUID map test" << llendl; - - return 0; - */ - - -// -// LLUUIDHashNode -// - -template <class DATA, int SIZE> -class LLUUIDHashNode -{ -public: - LLUUIDHashNode(); - -public: - S32 mCount; - U8 mKey[SIZE]; - DATA mData[SIZE]; - LLUUIDHashNode<DATA, SIZE> *mNextNodep; -}; - - -// -// LLUUIDHashNode implementation -// -template <class DATA, int SIZE> -LLUUIDHashNode<DATA, SIZE>::LLUUIDHashNode() -{ - mCount = 0; - mNextNodep = NULL; -} - - -template <class DATA_TYPE, int SIZE> -class LLUUIDHashMap -{ -public: - // basic constructor including sorter - LLUUIDHashMap(BOOL (*equals)(const LLUUID &uuid, const DATA_TYPE &data), - const DATA_TYPE &null_data); - ~LLUUIDHashMap(); - - inline DATA_TYPE &get(const LLUUID &uuid); - inline BOOL check(const LLUUID &uuid) const; - inline DATA_TYPE &set(const LLUUID &uuid, const DATA_TYPE &type); - inline BOOL remove(const LLUUID &uuid); - void removeAll(); - - inline S32 getLength() const; // Warning, NOT O(1!) -public: - BOOL (*mEquals)(const LLUUID &uuid, const DATA_TYPE &data); - LLUUIDHashNode<DATA_TYPE, SIZE> mNodes[256]; - - S32 mIterCount; -protected: - DATA_TYPE mNull; -}; - - -// -// LLUUIDHashMap implementation -// - -template <class DATA_TYPE, int SIZE> -LLUUIDHashMap<DATA_TYPE, SIZE>::LLUUIDHashMap(BOOL (*equals)(const LLUUID &uuid, const DATA_TYPE &data), - const DATA_TYPE &null_data) -: mEquals(equals), - mIterCount(0), - mNull(null_data) -{ } - -template <class DATA_TYPE, int SIZE> -LLUUIDHashMap<DATA_TYPE, SIZE>::~LLUUIDHashMap() -{ - removeAll(); -} - -template <class DATA_TYPE, int SIZE> -void LLUUIDHashMap<DATA_TYPE, SIZE>::removeAll() -{ - S32 bin; - for (bin = 0; bin < 256; bin++) - { - LLUUIDHashNode<DATA_TYPE, SIZE>* nodep = &mNodes[bin]; - - BOOL first = TRUE; - while (nodep) - { - S32 i; - const S32 count = nodep->mCount; - - // Iterate through all members of this node - for (i = 0; i < count; i++) - { - nodep->mData[i] = mNull; - } - - nodep->mCount = 0; - // Done with all objects in this node, go to the next. - - LLUUIDHashNode<DATA_TYPE, SIZE>* curp = nodep; - nodep = nodep->mNextNodep; - - // Delete the node if it's not the first node - if (first) - { - first = FALSE; - curp->mNextNodep = NULL; - } - else - { - delete curp; - } - } - } -} - -template <class DATA_TYPE, int SIZE> -inline S32 LLUUIDHashMap<DATA_TYPE, SIZE>::getLength() const -{ - S32 count = 0; - S32 bin; - for (bin = 0; bin < 256; bin++) - { - LLUUIDHashNode<DATA_TYPE, SIZE>* nodep = (LLUUIDHashNode<DATA_TYPE, SIZE>*) &mNodes[bin]; - while (nodep) - { - count += nodep->mCount; - nodep = nodep->mNextNodep; - } - } - return count; -} - -template <class DATA_TYPE, int SIZE> -inline DATA_TYPE &LLUUIDHashMap<DATA_TYPE, SIZE>::get(const LLUUID &uuid) -{ - LLUUIDHashNode<DATA_TYPE, SIZE>* nodep = &mNodes[uuid.mData[0]]; - - // Grab the second byte of the UUID, which is the key for the node data - const S32 second_byte = uuid.mData[1]; - while (nodep) - { - S32 i; - const S32 count = nodep->mCount; - - // Iterate through all members of this node - for (i = 0; i < count; i++) - { - if ((nodep->mKey[i] == second_byte) && mEquals(uuid, nodep->mData[i])) - { - // The second byte matched, and our equality test passed. - // We found it. - return nodep->mData[i]; - } - } - - // Done with all objects in this node, go to the next. - nodep = nodep->mNextNodep; - } - return mNull; -} - - -template <class DATA_TYPE, int SIZE> -inline BOOL LLUUIDHashMap<DATA_TYPE, SIZE>::check(const LLUUID &uuid) const -{ - const LLUUIDHashNode<DATA_TYPE, SIZE>* nodep = &mNodes[uuid.mData[0]]; - - // Grab the second byte of the UUID, which is the key for the node data - const S32 second_byte = uuid.mData[1]; - while (nodep) - { - S32 i; - const S32 count = nodep->mCount; - - // Iterate through all members of this node - for (i = 0; i < count; i++) - { - if ((nodep->mKey[i] == second_byte) && mEquals(uuid, nodep->mData[i])) - { - // The second byte matched, and our equality test passed. - // We found it. - return TRUE; - } - } - - // Done with all objects in this node, go to the next. - nodep = nodep->mNextNodep; - } - - // Didn't find anything - return FALSE; -} - - -template <class DATA_TYPE, int SIZE> -inline DATA_TYPE &LLUUIDHashMap<DATA_TYPE, SIZE>::set(const LLUUID &uuid, const DATA_TYPE &data) -{ - // Set is just like a normal find, except that if we find a match - // we replace it with the input value. - // If we don't find a match, we append to the end of the list. - - LLUUIDHashNode<DATA_TYPE, SIZE>* nodep = &mNodes[uuid.mData[0]]; - - const S32 second_byte = uuid.mData[1]; - while (1) - { - const S32 count = nodep->mCount; - - S32 i; - for (i = 0; i < count; i++) - { - if ((nodep->mKey[i] == second_byte) && mEquals(uuid, nodep->mData[i])) - { - // We found a match for this key, replace the data with - // the incoming data. - nodep->mData[i] = data; - return nodep->mData[i]; - } - } - if (!nodep->mNextNodep) - { - // We've iterated through all of the keys without finding a match - if (i < SIZE) - { - // There's still some space on this node, append - // the key and data to it. - nodep->mKey[i] = second_byte; - nodep->mData[i] = data; - nodep->mCount++; - - return nodep->mData[i]; - } - else - { - // This node is full, append a new node to the end. - nodep->mNextNodep = new LLUUIDHashNode<DATA_TYPE, SIZE>; - nodep->mNextNodep->mKey[0] = second_byte; - nodep->mNextNodep->mData[0] = data; - nodep->mNextNodep->mCount = 1; - - return nodep->mNextNodep->mData[0]; - } - } - - // No match on this node, go to the next - nodep = nodep->mNextNodep; - } -} - - -template <class DATA_TYPE, int SIZE> -inline BOOL LLUUIDHashMap<DATA_TYPE, SIZE>::remove(const LLUUID &uuid) -{ - if (mIterCount) - { - // We don't allow remove when we're iterating, it's bad karma! - llerrs << "Attempted remove while an outstanding iterator in LLUUIDHashMap!" << llendl; - } - // Remove is the trickiest operation. - // What we want to do is swap the last element of the last - // node if we find the one that we want to remove, but we have - // to deal with deleting the node from the tail if it's empty, but - // NOT if it's the only node left. - - LLUUIDHashNode<DATA_TYPE, SIZE> *nodep = &mNodes[uuid.mData[0]]; - - // Not empty, we need to search through the nodes - const S32 second_byte = uuid.mData[1]; - - // A modification of the standard search algorithm. - while (nodep) - { - const S32 count = nodep->mCount; - - S32 i; - for (i = 0; i < count; i++) - { - if ((nodep->mKey[i] == second_byte) && mEquals(uuid, nodep->mData[i])) - { - // We found the node that we want to remove. - // Find the last (and next-to-last) node, and the index of the last - // element. We could conceviably start from the node we're on, - // but that makes it more complicated, this is easier. - - LLUUIDHashNode<DATA_TYPE, SIZE> *prevp = &mNodes[uuid.mData[0]]; - LLUUIDHashNode<DATA_TYPE, SIZE> *lastp = prevp; - - // Find the last and next-to-last - while (lastp->mNextNodep) - { - prevp = lastp; - lastp = lastp->mNextNodep; - } - - // First, swap in the last to the current location. - nodep->mKey[i] = lastp->mKey[lastp->mCount - 1]; - nodep->mData[i] = lastp->mData[lastp->mCount - 1]; - - // Now, we delete the entry - lastp->mCount--; - lastp->mData[lastp->mCount] = mNull; - - if (!lastp->mCount) - { - // We deleted the last element! - if (lastp != &mNodes[uuid.mData[0]]) - { - // Only blitz the node if it's not the head - // Set the previous node to point to NULL, then - // blitz the empty last node - prevp->mNextNodep = NULL; - delete lastp; - } - } - return TRUE; - } - } - - // Iterate to the next node, we've scanned all the entries in this one. - nodep = nodep->mNextNodep; - } - return FALSE; -} - - -// -// LLUUIDHashMapIter -// - -template <class DATA_TYPE, int SIZE> -class LLUUIDHashMapIter -{ -public: - LLUUIDHashMapIter(LLUUIDHashMap<DATA_TYPE, SIZE> *hash_mapp); - ~LLUUIDHashMapIter(); - - - inline void reset(); - inline void first(); - inline void next(); - inline BOOL done() const; - - DATA_TYPE& operator*() const - { - return mCurHashNodep->mData[mCurHashNodeKey]; - } - DATA_TYPE* operator->() const - { - return &(operator*()); - } - -protected: - LLUUIDHashMap<DATA_TYPE, SIZE> *mHashMapp; - LLUUIDHashNode<DATA_TYPE, SIZE> *mCurHashNodep; - - S32 mCurHashMapNodeNum; - S32 mCurHashNodeKey; - - DATA_TYPE mNull; -}; - - -// -// LLUUIDHashMapIter Implementation -// -template <class DATA_TYPE, int SIZE> -LLUUIDHashMapIter<DATA_TYPE, SIZE>::LLUUIDHashMapIter(LLUUIDHashMap<DATA_TYPE, SIZE> *hash_mapp) -{ - mHashMapp = hash_mapp; - mCurHashNodep = NULL; - mCurHashMapNodeNum = 0; - mCurHashNodeKey = 0; -} - -template <class DATA_TYPE, int SIZE> -LLUUIDHashMapIter<DATA_TYPE, SIZE>::~LLUUIDHashMapIter() -{ - reset(); -} - -template <class DATA_TYPE, int SIZE> -inline void LLUUIDHashMapIter<DATA_TYPE, SIZE>::reset() -{ - if (mCurHashNodep) - { - // We're partway through an iteration, we can clean up now - mHashMapp->mIterCount--; - mCurHashNodep = NULL; - } -} - -template <class DATA_TYPE, int SIZE> -inline void LLUUIDHashMapIter<DATA_TYPE, SIZE>::first() -{ - // Iterate through until we find the first non-empty node; - S32 i; - for (i = 0; i < 256; i++) - { - if (mHashMapp->mNodes[i].mCount) - { - if (!mCurHashNodep) - { - // Increment, since it's no longer safe for us to do a remove - mHashMapp->mIterCount++; - } - - mCurHashNodep = &mHashMapp->mNodes[i]; - mCurHashMapNodeNum = i; - mCurHashNodeKey = 0; - //return mCurHashNodep->mData[0]; - return; - } - } - - // Completely empty! - mCurHashNodep = NULL; - //return mNull; - return; -} - -template <class DATA_TYPE, int SIZE> -inline BOOL LLUUIDHashMapIter<DATA_TYPE, SIZE>::done() const -{ - return mCurHashNodep ? FALSE : TRUE; -} - -template <class DATA_TYPE, int SIZE> -inline void LLUUIDHashMapIter<DATA_TYPE, SIZE>::next() -{ - // No current entry, this iterator is done - if (!mCurHashNodep) - { - //return mNull; - return; - } - - // Go to the next element - mCurHashNodeKey++; - if (mCurHashNodeKey < mCurHashNodep->mCount) - { - // We're not done with this node, return the current element - //return mCurHashNodep->mData[mCurHashNodeKey]; - return; - } - - // Done with this node, move to the next - mCurHashNodep = mCurHashNodep->mNextNodep; - if (mCurHashNodep) - { - // Return the first element - mCurHashNodeKey = 0; - //return mCurHashNodep->mData[0]; - return; - } - - // Find the next non-empty node (keyed on the first byte) - mCurHashMapNodeNum++; - - S32 i; - for (i = mCurHashMapNodeNum; i < 256; i++) - { - if (mHashMapp->mNodes[i].mCount) - { - // We found one that wasn't empty - mCurHashNodep = &mHashMapp->mNodes[i]; - mCurHashMapNodeNum = i; - mCurHashNodeKey = 0; - //return mCurHashNodep->mData[0]; - return; - } - } - - // OK, we're done, nothing else to iterate - mCurHashNodep = NULL; - mHashMapp->mIterCount--; // Decrement since we're safe to do removes now - //return mNull; -} - -#endif // LL_LLUUIDHASHMAP_H diff --git a/indra/llcommon/llversionserver.h b/indra/llcommon/llwin32headers.h index ef68a0eaf5..8cfa40ada8 100755..100644 --- a/indra/llcommon/llversionserver.h +++ b/indra/llcommon/llwin32headers.h @@ -1,8 +1,8 @@ /** - * @file llversionserver.h - * @brief + * @file llwin32headers.h + * @brief sanitized include of windows header files * - * $LicenseInfo:firstyear=2002&license=viewerlgpl$ + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. * @@ -24,15 +24,19 @@ * $/LicenseInfo$ */ -#ifndef LL_LLVERSIONSERVER_H -#define LL_LLVERSIONSERVER_H - -const S32 LL_VERSION_MAJOR = 2; -const S32 LL_VERSION_MINOR = 1; -const S32 LL_VERSION_PATCH = 0; -const S32 LL_VERSION_BUILD = 264760; - -const char * const LL_CHANNEL = "Second Life Server"; +#ifndef LL_LLWINDOWS_H +#define LL_LLWINDOWS_H +#ifdef LL_WINDOWS +#ifndef NOMINMAX +#define NOMINMAX +#endif +#undef WIN32_LEAN_AND_MEAN +#include <winsock2.h> +#include <windows.h> +// reset to default, which is lean +#define WIN32_LEAN_AND_MEAN +#undef NOMINMAX +#endif #endif diff --git a/indra/llcommon/lldarrayptr.h b/indra/llcommon/llwin32headerslean.h index c9a0b204d1..314e7a85d1 100755..100644 --- a/indra/llcommon/lldarrayptr.h +++ b/indra/llcommon/llwin32headerslean.h @@ -1,6 +1,6 @@ /** - * @file lldarrayptr.h - * @brief Wrapped std::vector for backward compatibility. + * @file llwin32headerslean.h + * @brief sanitized include of windows header files * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code @@ -23,14 +23,18 @@ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ -#ifndef LL_LLDARRAYPTR_H -#define LL_LLDARRAYPTR_H -#include "lldarray.h" +#ifndef LL_LLWINDOWS_H +#define LL_LLWINDOWS_H -template <class Type, int BlockSize = 32> -class LLDynamicArrayPtr : public LLDynamicArray<Type, BlockSize> -{ -}; +#ifdef LL_WINDOWS +#ifndef NOMINMAX +#define NOMINMAX +#endif +#define WIN32_LEAN_AND_MEAN +#include <winsock2.h> +#include <windows.h> +#undef NOMINMAX +#endif -#endif // LL_LLDARRAYPTR_H +#endif diff --git a/indra/llcommon/llworkerthread.cpp b/indra/llcommon/llworkerthread.cpp index 3d05a30ac2..4c197dc1d6 100755 --- a/indra/llcommon/llworkerthread.cpp +++ b/indra/llcommon/llworkerthread.cpp @@ -50,8 +50,8 @@ LLWorkerThread::~LLWorkerThread() // Delete any workers in the delete queue (should be safe - had better be!) if (!mDeleteList.empty()) { - llwarns << "Worker Thread: " << mName << " destroyed with " << mDeleteList.size() - << " entries in delete list." << llendl; + LL_WARNS() << "Worker Thread: " << mName << " destroyed with " << mDeleteList.size() + << " entries in delete list." << LL_ENDL; } delete mDeleteMutex; @@ -65,8 +65,8 @@ void LLWorkerThread::clearDeleteList() // Delete any workers in the delete queue (should be safe - had better be!) if (!mDeleteList.empty()) { - llwarns << "Worker Thread: " << mName << " destroyed with " << mDeleteList.size() - << " entries in delete list." << llendl; + LL_WARNS() << "Worker Thread: " << mName << " destroyed with " << mDeleteList.size() + << " entries in delete list." << LL_ENDL; mDeleteMutex->lock(); for (delete_list_t::iterator iter = mDeleteList.begin(); iter != mDeleteList.end(); ++iter) @@ -142,7 +142,7 @@ LLWorkerThread::handle_t LLWorkerThread::addWorkRequest(LLWorkerClass* workercla bool res = addRequest(req); if (!res) { - llerrs << "add called after LLWorkerThread::cleanupClass()" << llendl; + LL_ERRS() << "add called after LLWorkerThread::cleanupClass()" << LL_ENDL; req->deleteRequest(); handle = nullHandle(); } @@ -209,7 +209,7 @@ LLWorkerClass::LLWorkerClass(LLWorkerThread* workerthread, const std::string& na { if (!mWorkerThread) { - llerrs << "LLWorkerClass() called with NULL workerthread: " << name << llendl; + LL_ERRS() << "LLWorkerClass() called with NULL workerthread: " << name << LL_ENDL; } } @@ -223,12 +223,12 @@ LLWorkerClass::~LLWorkerClass() LLWorkerThread::WorkRequest* workreq = (LLWorkerThread::WorkRequest*)mWorkerThread->getRequest(mRequestHandle); if (!workreq) { - llerrs << "LLWorkerClass destroyed with stale work handle" << llendl; + LL_ERRS() << "LLWorkerClass destroyed with stale work handle" << LL_ENDL; } if (workreq->getStatus() != LLWorkerThread::STATUS_ABORTED && workreq->getStatus() != LLWorkerThread::STATUS_COMPLETE) { - llerrs << "LLWorkerClass destroyed with active worker! Worker Status: " << workreq->getStatus() << llendl; + LL_ERRS() << "LLWorkerClass destroyed with active worker! Worker Status: " << workreq->getStatus() << LL_ENDL; } } } @@ -238,7 +238,7 @@ void LLWorkerClass::setWorkerThread(LLWorkerThread* workerthread) mMutex.lock(); if (mRequestHandle != LLWorkerThread::nullHandle()) { - llerrs << "LLWorkerClass attempt to change WorkerThread with active worker!" << llendl; + LL_ERRS() << "LLWorkerClass attempt to change WorkerThread with active worker!" << LL_ENDL; } mWorkerThread = workerthread; mMutex.unlock(); @@ -298,10 +298,10 @@ void LLWorkerClass::addWork(S32 param, U32 priority) llassert_always(!(mWorkFlags & (WCF_WORKING|WCF_HAVE_WORK))); if (mRequestHandle != LLWorkerThread::nullHandle()) { - llerrs << "LLWorkerClass attempt to add work with active worker!" << llendl; + LL_ERRS() << "LLWorkerClass attempt to add work with active worker!" << LL_ENDL; } #if _DEBUG -// llinfos << "addWork: " << mWorkerClassName << " Param: " << param << llendl; +// LL_INFOS() << "addWork: " << mWorkerClassName << " Param: " << param << LL_ENDL; #endif startWork(param); clearFlags(WCF_WORK_FINISHED|WCF_WORK_ABORTED); @@ -316,7 +316,7 @@ void LLWorkerClass::abortWork(bool autocomplete) #if _DEBUG // LLWorkerThread::WorkRequest* workreq = mWorkerThread->getRequest(mRequestHandle); // if (workreq) -// llinfos << "abortWork: " << mWorkerClassName << " Param: " << workreq->getParam() << llendl; +// LL_INFOS() << "abortWork: " << mWorkerClassName << " Param: " << workreq->getParam() << LL_ENDL; #endif if (mRequestHandle != LLWorkerThread::nullHandle()) { diff --git a/indra/llcommon/llworkerthread.h b/indra/llcommon/llworkerthread.h index be46394d6e..09776816a8 100755 --- a/indra/llcommon/llworkerthread.h +++ b/indra/llcommon/llworkerthread.h @@ -26,10 +26,11 @@ #ifndef LL_LLWORKERTHREAD_H #define LL_LLWORKERTHREAD_H -#include <queue> -#include <string> +#include <list> #include <map> +#include <queue> #include <set> +#include <string> #include "llqueuedthread.h" #include "llapr.h" diff --git a/indra/llcommon/metaclass.cpp b/indra/llcommon/metaclass.cpp deleted file mode 100755 index 5e403511cf..0000000000 --- a/indra/llcommon/metaclass.cpp +++ /dev/null @@ -1,81 +0,0 @@ -/** - * @file metaclass.cpp - * @author Babbage - * @date 2006-05-15 - * @brief Implementation of LLMetaClass - * - * $LicenseInfo:firstyear=2006&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" - -#include "metaclass.h" - -#include "metaproperty.h" -#include "reflective.h" - -LLMetaClass::LLMetaClass() -{ -} - -//virtual -LLMetaClass::~LLMetaClass() -{ -} - -const LLMetaProperty* LLMetaClass::findProperty(const std::string& name) const -{ - PropertyIterator iter = mProperties.find(name); - if(iter == mProperties.end()) - { - return NULL; - } - return (*iter).second; -} - -void LLMetaClass::addProperty(const LLMetaProperty* property) -{ - mProperties.insert(std::make_pair(property->getName(), property)); -} - -U32 LLMetaClass::getPropertyCount() const -{ - return mProperties.size(); -} - -LLMetaClass::PropertyIterator LLMetaClass::beginProperties() const -{ - return mProperties.begin(); -} - -LLMetaClass::PropertyIterator LLMetaClass::endProperties() const -{ - return mProperties.end(); -} - -bool LLMetaClass::isInstance(const LLReflective* object) const -{ - // TODO: Babbage: Search through super classes of objects MetaClass. - const LLMetaClass* object_meta_class = &(object->getMetaClass()); - return (object_meta_class == this); -} - diff --git a/indra/llcommon/metaclass.h b/indra/llcommon/metaclass.h deleted file mode 100755 index 626757d58d..0000000000 --- a/indra/llcommon/metaclass.h +++ /dev/null @@ -1,82 +0,0 @@ -/** - * @file metaclass.h - * @author Babbage - * @date 2006-05-15 - * @brief Reflective meta information describing a class. - * - * $LicenseInfo:firstyear=2006&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_METACLASS_H -#define LL_METACLASS_H - -#include <string> -#include <map> - -#include "stdtypes.h" - -class LLReflective; -class LLMetaProperty; -class LLMetaMethod; -class LL_COMMON_API LLMetaClass -{ -public: - - LLMetaClass(); - virtual ~LLMetaClass(); - - // Create instance of this MetaClass. NULL if class is abstract. - // Gives ownership of returned object. - // virtual LLReflective* create() const = 0; - - // Returns named property or NULL. - const LLMetaProperty* findProperty(const std::string& name) const; - - // Add property to metaclass. Takes ownership of given property. - void addProperty(const LLMetaProperty* property); - - typedef std::map<std::string, const LLMetaProperty*>::const_iterator PropertyIterator; - - U32 getPropertyCount() const; - - PropertyIterator beginProperties() const; - PropertyIterator endProperties() const; - - // Returns named property or NULL. - // const LLMetaMethod* findMethod(const std::string& name) const; - - // Add method to metaclass. Takes ownership of given method. - // void addMethod(const LLMetaMethod* method); - - // Find MetaClass by name. NULL if name is unknown. - // static LLMetaClass* findClass(const std::string& name); - - // True if object is instance of this meta class. - bool isInstance(const LLReflective* object) const; - -private: - - typedef std::map<std::string, const LLMetaProperty*> PropertyMap; - PropertyMap mProperties; -}; - -#endif // LL_METACLASS_H diff --git a/indra/llcommon/metaclasst.h b/indra/llcommon/metaclasst.h deleted file mode 100755 index b9a7ae219d..0000000000 --- a/indra/llcommon/metaclasst.h +++ /dev/null @@ -1,60 +0,0 @@ -/** - * @file metaclasst.h - * - * $LicenseInfo:firstyear=2006&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_METACLASST_H -#define LL_METACLASST_H - -#include "metaclass.h" - -template<class TObject> -class LLMetaClassT : public LLMetaClass -{ - public: - - virtual ~LLMetaClassT() {;} - - static const LLMetaClassT& instance() - { - static const LLMetaClassT& instance = buildMetaClass(); - return instance; - } - - private: - - static const LLMetaClassT& buildMetaClass() - { - LLMetaClassT& meta_class = *(new LLMetaClassT()); - reflectProperties(meta_class); - return meta_class; - } - - LLMetaClassT() {;} - - static void reflectProperties(LLMetaClass&) - { - } -}; - -#endif // LL_METACLASST_H diff --git a/indra/llcommon/metaproperty.cpp b/indra/llcommon/metaproperty.cpp deleted file mode 100755 index 98d850bf1e..0000000000 --- a/indra/llcommon/metaproperty.cpp +++ /dev/null @@ -1,56 +0,0 @@ -/** - * @file metaproperty.cpp - * @author Babbage - * @date 2006-05-15 - * @brief Implementation of LLMetaProperty. - * - * $LicenseInfo:firstyear=2006&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" - -#include "metaproperty.h" - -#include "metaclass.h" - -LLMetaProperty::LLMetaProperty(const std::string& name, const LLMetaClass& object_class) : - mName(name), mObjectClass(object_class) -{ -} - -//virtual -LLMetaProperty::~LLMetaProperty() -{ -} - -const LLMetaClass& LLMetaProperty::getObjectMetaClass() const -{ - return mObjectClass; -} - -void LLMetaProperty::checkObjectClass(const LLReflective* object) const -{ - if(! mObjectClass.isInstance(object)) - { - throw "class cast exception"; - } -} diff --git a/indra/llcommon/metaproperty.h b/indra/llcommon/metaproperty.h deleted file mode 100755 index bd5bb1a30f..0000000000 --- a/indra/llcommon/metaproperty.h +++ /dev/null @@ -1,73 +0,0 @@ -/** - * @file metaproperty.h - * @author Babbage - * @date 2006-05-15 - * @brief Reflective meta information describing a property of a class. - * - * $LicenseInfo:firstyear=2006&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_METAPROPERTY_H -#define LL_METAPROPERTY_H - -#include "stdtypes.h" -#include "llsd.h" -#include "reflective.h" - -class LLMetaClass; -class LLReflective; -class LL_COMMON_API LLMetaProperty -{ -public: - LLMetaProperty(const std::string& name, const LLMetaClass& object_class); - virtual ~LLMetaProperty(); - - // Get property name. - const std::string& getName() const {return mName;} - - // Get value of this property. - virtual const LLReflective* get(const LLReflective* object) const = 0; - - // Set value of this property. - // virtual void set(LLReflective* object, const LLReflective* value) = 0; - - // Get value of this property as LLSD. Default returns undefined LLSD. - virtual LLSD getLLSD(const LLReflective* object) const = 0; - - // Get the MetaClass of legal values of this property. - // const LLMetaClass& getValueMetaClass(); - - // Get the meta class that this property is a member of. - const LLMetaClass& getObjectMetaClass() const; - -protected: - - // Check object is instance of object class, throw exception if not. - void checkObjectClass(const LLReflective* object) const; - -private: - - std::string mName; - const LLMetaClass& mObjectClass; -}; - -#endif // LL_METAPROPERTY_H diff --git a/indra/llcommon/metapropertyt.h b/indra/llcommon/metapropertyt.h deleted file mode 100755 index 7a36c161da..0000000000 --- a/indra/llcommon/metapropertyt.h +++ /dev/null @@ -1,183 +0,0 @@ -/** - * @file metapropertyt.h - * - * $LicenseInfo:firstyear=2006&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_METAPROPERTYT_H -#define LL_METAPROPERTYT_H - -#include "llsd.h" -#include "llstring.h" -#include "metaclasst.h" -#include "metaproperty.h" -#include "reflectivet.h" - -template<class TProperty> -class LLMetaPropertyT : public LLMetaProperty -{ -public: - - virtual ~LLMetaPropertyT() {;} - - // Get value of this property. Gives ownership of returned value. - virtual const LLReflective* get(const LLReflective* object) const - { - checkObjectClass(object); - return getProperty(object); - } - - // Set value of this property. - /*virtual void set(LLReflective* object, const LLReflective* value) - { - // TODO: Babbage: Check types. - ref(object) = static_cast<const LLReflectiveT<TProperty>* >(value)->getValue(); - }*/ - - // Get value of this property as LLSD. - virtual LLSD getLLSD(const LLReflective* object) const - { - return LLSD(); - } - -protected: - - LLMetaPropertyT(const std::string& name, const LLMetaClass& object_class) : LLMetaProperty(name, object_class) {;} - - virtual const TProperty* getProperty(const LLReflective* object) const = 0; -}; - -template <> -inline const LLReflective* LLMetaPropertyT<S32>::get(const LLReflective* object) const -{ - checkObjectClass(object); - return NULL; -} - -template <> -inline const LLReflective* LLMetaPropertyT<std::string>::get(const LLReflective* object) const -{ - checkObjectClass(object); - return NULL; -} - -template <> -inline const LLReflective* LLMetaPropertyT<LLUUID>::get(const LLReflective* object) const -{ - checkObjectClass(object); - return NULL; -} - -template <> -inline const LLReflective* LLMetaPropertyT<bool>::get(const LLReflective* object) const -{ - checkObjectClass(object); - return NULL; -} - -template <> -inline LLSD LLMetaPropertyT<S32>::getLLSD(const LLReflective* object) const -{ - return *(getProperty(object)); -} - -template <> -inline LLSD LLMetaPropertyT<std::string>::getLLSD(const LLReflective* object) const -{ - return *(getProperty(object)); -} - -template <> -inline LLSD LLMetaPropertyT<LLUUID>::getLLSD(const LLReflective* object) const -{ - return *(getProperty(object)); -} - -template <> -inline LLSD LLMetaPropertyT<bool>::getLLSD(const LLReflective* object) const -{ - return *(getProperty(object)); -} - -template<class TObject, class TProperty> -class LLMetaPropertyTT : public LLMetaPropertyT<TProperty> -{ -public: - - LLMetaPropertyTT(const std::string& name, const LLMetaClass& object_class, TProperty (TObject::*property)) : - LLMetaPropertyT<TProperty>(name, object_class), mProperty(property) {;} - -protected: - - // Get void* to property. - virtual const TProperty* getProperty(const LLReflective* object) const - { - const TObject* typed_object = static_cast<const TObject*>(object); - return &(typed_object->*mProperty); - }; - -private: - - TProperty (TObject::*mProperty); -}; - -template<class TObject, class TProperty> -class LLMetaPropertyPtrTT : public LLMetaPropertyT<TProperty> -{ -public: - - LLMetaPropertyPtrTT(const std::string& name, const LLMetaClass& object_class, TProperty* (TObject::*property)) : - LLMetaPropertyT<TProperty>(name, object_class), mProperty(property) {;} - -protected: - - // Get void* to property. - virtual const TProperty* getProperty(const LLReflective* object) const - { - const TObject* typed_object = static_cast<const TObject*>(object); - return typed_object->*mProperty; - }; - -private: - - TProperty* (TObject::*mProperty); -}; - -// Utility function to simplify the registration of members. -template<class TObject, class TProperty> -void reflectProperty(LLMetaClass& meta_class, const std::string& name, TProperty (TObject::*property)) -{ - typedef LLMetaPropertyTT<TObject, TProperty> PropertyType; - const LLMetaProperty* meta_property = new PropertyType(name, meta_class, property); - meta_class.addProperty(meta_property); -} - -// Utility function to simplify the registration of ptr properties. -template<class TObject, class TProperty> -void reflectPtrProperty(LLMetaClass& meta_class, const std::string& name, TProperty* (TObject::*property)) -{ - typedef LLMetaPropertyPtrTT<TObject, TProperty> PropertyType; - const LLMetaProperty* meta_property = new PropertyType(name, meta_class, property); - meta_class.addProperty(meta_property); -} - -#endif // LL_METAPROPERTYT_H diff --git a/indra/llcommon/reflective.cpp b/indra/llcommon/reflective.cpp deleted file mode 100755 index 2cc0e7e1f2..0000000000 --- a/indra/llcommon/reflective.cpp +++ /dev/null @@ -1,40 +0,0 @@ -/** - * @file reflective.cpp - * @author Babbage - * @date 2006-05-15 - * @brief Implementation of LLReflective. - * - * $LicenseInfo:firstyear=2006&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "linden_common.h" - -#include "reflective.h" - -LLReflective::LLReflective() -{ -} - -//virtual -LLReflective::~LLReflective() -{ -} diff --git a/indra/llcommon/reflective.h b/indra/llcommon/reflective.h deleted file mode 100755 index da5c5a2630..0000000000 --- a/indra/llcommon/reflective.h +++ /dev/null @@ -1,42 +0,0 @@ -/** - * @file reflective.h - * @author Babbage - * @date 2006-05-15 - * @brief Interface that must be implemented by all reflective classes. - * - * $LicenseInfo:firstyear=2006&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_REFLECTIVE_H -#define LL_REFLECTIVE_H - -class LLMetaClass; -class LL_COMMON_API LLReflective -{ -public: - LLReflective(); - virtual ~LLReflective(); - - virtual const LLMetaClass& getMetaClass() const = 0; -}; - -#endif // LL_REFLECTIVE_H diff --git a/indra/llcommon/reflectivet.h b/indra/llcommon/reflectivet.h deleted file mode 100755 index 958921f23e..0000000000 --- a/indra/llcommon/reflectivet.h +++ /dev/null @@ -1,48 +0,0 @@ -/** - * @file reflectivet.h - * - * $LicenseInfo:firstyear=2006&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_REFLECTIVET_H -#define LL_REFLECTIVET_H - -#include "reflective.h" - -template <class T> -class LLReflectiveT : public LLReflective -{ -public: - - LLReflectiveT(const T& value) : mValue(value) {;} - virtual ~LLReflectiveT() {;} - - virtual const LLMetaClass& getMetaClass() const {return LLMetaClassT<LLReflectiveT<T> >::instance();} - - const T& getValue() const {return mValue;} - -private: - - T mValue; -}; - -#endif diff --git a/indra/llcommon/roles_constants.h b/indra/llcommon/roles_constants.h deleted file mode 100755 index effd15ea72..0000000000 --- a/indra/llcommon/roles_constants.h +++ /dev/null @@ -1,192 +0,0 @@ -/** - * @file roles_constants.h - * @brief General Roles Constants - * - * $LicenseInfo:firstyear=2006&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_ROLES_CONSTANTS_H -#define LL_ROLES_CONSTANTS_H - -// This value includes the everyone group. -const S32 MAX_ROLES = 10; - -enum LLRoleMemberChangeType -{ - RMC_ADD, - RMC_REMOVE, - RMC_NONE -}; - -enum LLRoleChangeType -{ - RC_UPDATE_NONE, - RC_UPDATE_DATA, - RC_UPDATE_POWERS, - RC_UPDATE_ALL, - RC_CREATE, - RC_DELETE -}; - -// -// Powers -// - -// KNOWN HOLES: use these for any single bit powers you need -// bit 0x1 << 46 -// bit 0x1 << 49 and above - -// These powers were removed to make group roles simpler -// bit 0x1 << 41 (GP_ACCOUNTING_VIEW) -// bit 0x1 << 46 (GP_PROPOSAL_VIEW) - -const U64 GP_NO_POWERS = 0x0; -const U64 GP_ALL_POWERS = 0xFFFFFFFFFFFFFFFFLL; - -// Membership -const U64 GP_MEMBER_INVITE = 0x1 << 1; // Invite member -const U64 GP_MEMBER_EJECT = 0x1 << 2; // Eject member from group -const U64 GP_MEMBER_OPTIONS = 0x1 << 3; // Toggle "Open enrollment" and change "Signup Fee" -const U64 GP_MEMBER_VISIBLE_IN_DIR = 0x1LL << 47; - -// Roles -const U64 GP_ROLE_CREATE = 0x1 << 4; // Create new roles -const U64 GP_ROLE_DELETE = 0x1 << 5; // Delete roles -const U64 GP_ROLE_PROPERTIES = 0x1 << 6; // Change Role Names, Titles, and Descriptions (Of roles the user is in, only, or any role in group?) -const U64 GP_ROLE_ASSIGN_MEMBER_LIMITED = 0x1 << 7; // Assign Member to a Role that the assigner is in -const U64 GP_ROLE_ASSIGN_MEMBER = 0x1 << 8; // Assign Member to Role -const U64 GP_ROLE_REMOVE_MEMBER = 0x1 << 9; // Remove Member from Role -const U64 GP_ROLE_CHANGE_ACTIONS = 0x1 << 10; // Change actions a role can perform - -// Group Identity -const U64 GP_GROUP_CHANGE_IDENTITY = 0x1 << 11; // Charter, insignia, 'Show In Group List', 'Publish on the web', 'Mature', all 'Show Member In Group Profile' checkboxes - -// Parcel Management -const U64 GP_LAND_DEED = 0x1 << 12; // Deed Land and Buy Land for Group -const U64 GP_LAND_RELEASE = 0x1 << 13; // Release Land (to Gov. Linden) -const U64 GP_LAND_SET_SALE_INFO = 0x1 << 14; // Set for sale info (Toggle "For Sale", Set Price, Set Target, Toggle "Sell objects with the land") -const U64 GP_LAND_DIVIDE_JOIN = 0x1 << 15; // Divide and Join Parcels - -// Parcel Identity -const U64 GP_LAND_FIND_PLACES = 0x1 << 17; // Toggle "Show in Find Places" and Set Category. -const U64 GP_LAND_CHANGE_IDENTITY = 0x1 << 18; // Change Parcel Identity: Parcel Name, Parcel Description, Snapshot, 'Publish on the web', and 'Mature' checkbox -const U64 GP_LAND_SET_LANDING_POINT = 0x1 << 19; // Set Landing Point - -// Parcel Settings -const U64 GP_LAND_CHANGE_MEDIA = 0x1 << 20; // Change Media Settings -const U64 GP_LAND_EDIT = 0x1 << 21; // Toggle Edit Land -const U64 GP_LAND_OPTIONS = 0x1 << 22; // Toggle Set Home Point, Fly, Outside Scripts, Create/Edit Objects, Landmark, and Damage checkboxes - -// Parcel Powers -const U64 GP_LAND_ALLOW_EDIT_LAND = 0x1 << 23; // Bypass Edit Land Restriction -const U64 GP_LAND_ALLOW_FLY = 0x1 << 24; // Bypass Fly Restriction -const U64 GP_LAND_ALLOW_CREATE = 0x1 << 25; // Bypass Create/Edit Objects Restriction -const U64 GP_LAND_ALLOW_LANDMARK = 0x1 << 26; // Bypass Landmark Restriction -const U64 GP_LAND_ALLOW_SET_HOME = 0x1 << 28; // Bypass Set Home Point Restriction -const U64 GP_LAND_ALLOW_HOLD_EVENT = 0x1LL << 41; // Allowed to hold events on group-owned land - - -// Parcel Access -const U64 GP_LAND_MANAGE_ALLOWED = 0x1 << 29; // Manage Allowed List -const U64 GP_LAND_MANAGE_BANNED = 0x1 << 30; // Manage Banned List -const U64 GP_LAND_MANAGE_PASSES = 0x1LL << 31; // Change Sell Pass Settings -const U64 GP_LAND_ADMIN = 0x1LL << 32; // Eject and Freeze Users on the land - -// Parcel Content -const U64 GP_LAND_RETURN_GROUP_SET = 0x1LL << 33; // Return objects on parcel that are set to group -const U64 GP_LAND_RETURN_NON_GROUP = 0x1LL << 34; // Return objects on parcel that are not set to group -const U64 GP_LAND_RETURN_GROUP_OWNED= 0x1LL << 48; // Return objects on parcel that are owned by the group - -// Select a power-bit based on an object's relationship to a parcel. -const U64 GP_LAND_RETURN = GP_LAND_RETURN_GROUP_OWNED - | GP_LAND_RETURN_GROUP_SET - | GP_LAND_RETURN_NON_GROUP; - -const U64 GP_LAND_GARDENING = 0x1LL << 35; // Parcel Gardening - plant and move linden trees - -// Object Management -const U64 GP_OBJECT_DEED = 0x1LL << 36; // Deed Object -const U64 GP_OBJECT_MANIPULATE = 0x1LL << 38; // Manipulate Group Owned Objects (Move, Copy, Mod) -const U64 GP_OBJECT_SET_SALE = 0x1LL << 39; // Set Group Owned Object for Sale - -// Accounting -const U64 GP_ACCOUNTING_ACCOUNTABLE = 0x1LL << 40; // Pay Group Liabilities and Receive Group Dividends - -// Notices -const U64 GP_NOTICES_SEND = 0x1LL << 42; // Send Notices -const U64 GP_NOTICES_RECEIVE = 0x1LL << 43; // Receive Notices and View Notice History - -// Proposals -// TODO: _DEPRECATED suffix as part of vote removal - DEV-24856: -const U64 GP_PROPOSAL_START = 0x1LL << 44; // Start Proposal -// TODO: _DEPRECATED suffix as part of vote removal - DEV-24856: -const U64 GP_PROPOSAL_VOTE = 0x1LL << 45; // Vote on Proposal - -// Group chat moderation related -const U64 GP_SESSION_JOIN = 0x1LL << 16; //can join session -const U64 GP_SESSION_VOICE = 0x1LL << 27; //can hear/talk -const U64 GP_SESSION_MODERATOR = 0x1LL << 37; //can mute people's session - -const U64 GP_DEFAULT_MEMBER = GP_ACCOUNTING_ACCOUNTABLE - | GP_LAND_ALLOW_SET_HOME - | GP_NOTICES_RECEIVE - | GP_SESSION_JOIN - | GP_SESSION_VOICE - ; - -const U64 GP_DEFAULT_OFFICER = GP_DEFAULT_MEMBER // Superset of GP_DEFAULT_MEMBER - | GP_GROUP_CHANGE_IDENTITY - | GP_LAND_ADMIN - | GP_LAND_ALLOW_EDIT_LAND - | GP_LAND_ALLOW_FLY - | GP_LAND_ALLOW_CREATE - | GP_LAND_ALLOW_LANDMARK - | GP_LAND_CHANGE_IDENTITY - | GP_LAND_CHANGE_MEDIA - | GP_LAND_DEED - | GP_LAND_DIVIDE_JOIN - | GP_LAND_EDIT - | GP_LAND_FIND_PLACES - | GP_LAND_GARDENING - | GP_LAND_MANAGE_ALLOWED - | GP_LAND_MANAGE_BANNED - | GP_LAND_MANAGE_PASSES - | GP_LAND_OPTIONS - | GP_LAND_RELEASE - | GP_LAND_RETURN_GROUP_OWNED - | GP_LAND_RETURN_GROUP_SET - | GP_LAND_RETURN_NON_GROUP - | GP_LAND_SET_LANDING_POINT - | GP_LAND_SET_SALE_INFO - | GP_MEMBER_EJECT - | GP_MEMBER_INVITE - | GP_MEMBER_OPTIONS - | GP_MEMBER_VISIBLE_IN_DIR - | GP_NOTICES_SEND - | GP_OBJECT_DEED - | GP_OBJECT_MANIPULATE - | GP_OBJECT_SET_SALE - | GP_ROLE_ASSIGN_MEMBER_LIMITED - | GP_ROLE_PROPERTIES - | GP_SESSION_MODERATOR - ; -#endif diff --git a/indra/llcommon/stdenums.h b/indra/llcommon/stdenums.h deleted file mode 100755 index efcbe76795..0000000000 --- a/indra/llcommon/stdenums.h +++ /dev/null @@ -1,137 +0,0 @@ -/** - * @file stdenums.h - * @brief Enumerations for indra. - * - * $LicenseInfo:firstyear=2002&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_STDENUMS_H -#define LL_STDENUMS_H - -//---------------------------------------------------------------------------- -// DEPRECATED - create new, more specific files for shared enums/constants -//---------------------------------------------------------------------------- - -// this enum is used by the llview.h (viewer) and the llassetstorage.h (viewer and sim) -enum EDragAndDropType -{ - DAD_NONE = 0, - DAD_TEXTURE = 1, - DAD_SOUND = 2, - DAD_CALLINGCARD = 3, - DAD_LANDMARK = 4, - DAD_SCRIPT = 5, - DAD_CLOTHING = 6, - DAD_OBJECT = 7, - DAD_NOTECARD = 8, - DAD_CATEGORY = 9, - DAD_ROOT_CATEGORY = 10, - DAD_BODYPART = 11, - DAD_ANIMATION = 12, - DAD_GESTURE = 13, - DAD_LINK = 14, - DAD_MESH = 15, - DAD_WIDGET = 16, - DAD_PERSON = 17, - DAD_COUNT = 18, // number of types in this enum -}; - -// Reasons for drags to be denied. -// ordered by priority for multi-drag -enum EAcceptance -{ - ACCEPT_POSTPONED, // we are asynchronously determining acceptance - ACCEPT_NO, // Uninformative, general purpose denial. - ACCEPT_NO_LOCKED, // Operation would be valid, but permissions are set to disallow it. - ACCEPT_YES_COPY_SINGLE, // We'll take a copy of a single item - ACCEPT_YES_SINGLE, // Accepted. OK to drag and drop single item here. - ACCEPT_YES_COPY_MULTI, // We'll take a copy of multiple items - ACCEPT_YES_MULTI // Accepted. OK to drag and drop multiple items here. -}; - -// This is used by the DeRezObject message to determine where to put -// derezed tasks. -enum EDeRezDestination -{ - DRD_SAVE_INTO_AGENT_INVENTORY = 0, - DRD_ACQUIRE_TO_AGENT_INVENTORY = 1, // try to leave copy in world - DRD_SAVE_INTO_TASK_INVENTORY = 2, - DRD_ATTACHMENT = 3, - DRD_TAKE_INTO_AGENT_INVENTORY = 4, // delete from world - DRD_FORCE_TO_GOD_INVENTORY = 5, // force take copy - DRD_TRASH = 6, - DRD_ATTACHMENT_TO_INV = 7, - DRD_ATTACHMENT_EXISTS = 8, - DRD_RETURN_TO_OWNER = 9, // back to owner's inventory - DRD_RETURN_TO_LAST_OWNER = 10, // deeded object back to last owner's inventory - - DRD_COUNT = 11 -}; - - -// This is used by the return to owner code to determine the reason -// that this object is being returned. -enum EReturnReason -{ - RR_GENERIC = 0, - RR_SANDBOX = 1, - RR_PARCEL_OWNER = 2, - RR_PARCEL_AUTO = 3, - RR_PARCEL_FULL = 4, - RR_OFF_WORLD = 5, - - RR_COUNT = 6 -}; - -// This is used for filling in the first byte of the ExtraID field of -// the ObjectProperties message. -enum EObjectPropertiesExtraID -{ - OPEID_NONE = 0, - OPEID_ASSET_ID = 1, - OPEID_FROM_TASK_ID = 2, - - OPEID_COUNT = 3 -}; - -enum EAddPosition -{ - ADD_TOP, - ADD_BOTTOM, - ADD_DEFAULT -}; - -enum LLGroupChange -{ - GC_PROPERTIES, - GC_MEMBER_DATA, - GC_ROLE_DATA, - GC_ROLE_MEMBER_DATA, - GC_TITLES, - GC_ALL -}; - -//---------------------------------------------------------------------------- -// DEPRECATED - create new, more specific files for shared enums/constants -//---------------------------------------------------------------------------- - -#endif diff --git a/indra/llcommon/string_table.h b/indra/llcommon/string_table.h index fe6416fb50..fe6416fb50 100755..100644 --- a/indra/llcommon/string_table.h +++ b/indra/llcommon/string_table.h diff --git a/indra/llcommon/stringize.h b/indra/llcommon/stringize.h index 72f2e58ce1..2df008febb 100755 --- a/indra/llcommon/stringize.h +++ b/indra/llcommon/stringize.h @@ -31,21 +31,64 @@ #include <sstream> #include <boost/lambda/lambda.hpp> +#include <llstring.h> /** - * stringize(item) encapsulates an idiom we use constantly, using + * gstringize(item) encapsulates an idiom we use constantly, using * operator<<(std::ostringstream&, TYPE) followed by std::ostringstream::str() + * or their wstring equivalents * to render a string expressing some item. */ -template <typename T> -std::string stringize(const T& item) +template <typename CHARTYPE, typename T> +std::basic_string<CHARTYPE> gstringize(const T& item) { - std::ostringstream out; + std::basic_ostringstream<CHARTYPE> out; out << item; return out.str(); } /** + *partial specialization of stringize for handling wstring + *TODO: we should have similar specializations for wchar_t[] but not until it is needed. + */ +inline std::string stringize(const std::wstring& item) +{ + LL_WARNS() << "WARNING: Possible narrowing" << LL_ENDL; + + std::string s; + + s = wstring_to_utf8str(item); + return gstringize<char>(s); +} + +/** + * Specialization of gstringize for std::string return types + */ +template <typename T> +std::string stringize(const T& item) +{ + return gstringize<char>(item); +} + +/** + * Specialization for generating wstring from string. + * Both a convenience function and saves a miniscule amount of overhead. + */ +inline std::wstring wstringize(const std::string& item) +{ + return gstringize<wchar_t>(item.c_str()); +} + +/** + * Specialization of gstringize for std::wstring return types + */ +template <typename T> +std::wstring wstringize(const T& item) +{ + return gstringize<wchar_t>(item); +} + +/** * stringize_f(functor) */ template <typename Functor> diff --git a/indra/llcommon/tests/bitpack_test.cpp b/indra/llcommon/tests/bitpack_test.cpp index afc0c18cd0..9bfd567068 100755 --- a/indra/llcommon/tests/bitpack_test.cpp +++ b/indra/llcommon/tests/bitpack_test.cpp @@ -28,7 +28,7 @@ #include "linden_common.h" -#include "../bitpack.h" +#include "../llbitpack.h" #include "../test/lltut.h" diff --git a/indra/llcommon/tests/commonmisc_test.cpp b/indra/llcommon/tests/commonmisc_test.cpp index b115c153c1..4b3e07fa75 100755 --- a/indra/llcommon/tests/commonmisc_test.cpp +++ b/indra/llcommon/tests/commonmisc_test.cpp @@ -339,7 +339,7 @@ namespace tut /* if(actual != expected) { - llwarns << "iteration " << i << llendl; + LL_WARNS() << "iteration " << i << LL_ENDL; std::ostringstream e_str; std::string::iterator iter = expected.begin(); std::string::iterator end = expected.end(); @@ -349,8 +349,8 @@ namespace tut } e_str << std::endl; llsd_serialize_string(e_str, expected); - llwarns << "expected size: " << expected.size() << llendl; - llwarns << "expected: " << e_str.str() << llendl; + LL_WARNS() << "expected size: " << expected.size() << LL_ENDL; + LL_WARNS() << "expected: " << e_str.str() << LL_ENDL; std::ostringstream a_str; iter = actual.begin(); @@ -361,8 +361,8 @@ namespace tut } a_str << std::endl; llsd_serialize_string(a_str, actual); - llwarns << "actual size: " << actual.size() << llendl; - llwarns << "actual: " << a_str.str() << llendl; + LL_WARNS() << "actual size: " << actual.size() << LL_ENDL; + LL_WARNS() << "actual: " << a_str.str() << LL_ENDL; } */ ensure_equals("string value", actual, expected); diff --git a/indra/llcommon/tests/lldeadmantimer_test.cpp b/indra/llcommon/tests/lldeadmantimer_test.cpp index 7fd2dde6e0..23167762c3 100644 --- a/indra/llcommon/tests/lldeadmantimer_test.cpp +++ b/indra/llcommon/tests/lldeadmantimer_test.cpp @@ -37,12 +37,12 @@ static LLDeadmanTimer::time_type float_time_to_u64(F64 delta) { - return LLDeadmanTimer::time_type(delta * gClockFrequency); + return LLDeadmanTimer::time_type(delta * get_timer_info().mClockFrequency); } static F64 u64_time_to_float(LLDeadmanTimer::time_type delta) { - return delta * gClockFrequencyInv; + return delta * get_timer_info().mClockFrequencyInv; } @@ -54,7 +54,7 @@ struct deadmantimer_test deadmantimer_test() { // LLTimer internals updating - update_clock_frequencies(); + get_timer_info().update(); } }; diff --git a/indra/llcommon/tests/llerror_test.cpp b/indra/llcommon/tests/llerror_test.cpp index 279a90e51b..b28c5ba4b3 100755 --- a/indra/llcommon/tests/llerror_test.cpp +++ b/indra/llcommon/tests/llerror_test.cpp @@ -40,7 +40,7 @@ namespace { void test_that_error_h_includes_enough_things_to_compile_a_message() { - llinfos << "!" << llendl; + LL_INFOS() << "!" << LL_ENDL; } } @@ -55,7 +55,7 @@ namespace tut class TestRecorder : public LLError::Recorder { public: - TestRecorder() : mWantsTime(false) { } + TestRecorder() { mWantsTime = false; } ~TestRecorder() { LLError::removeRecorder(this); } void recordMessage(LLError::ELevel level, @@ -68,7 +68,6 @@ namespace tut void clearMessages() { mMessages.clear(); } void setWantsTime(bool t) { mWantsTime = t; } - bool wantsTime() { return mWantsTime; } std::string message(int n) { @@ -82,8 +81,6 @@ namespace tut private: typedef std::vector<std::string> MessageVector; MessageVector mMessages; - - bool mWantsTime; }; struct ErrorTestData @@ -144,8 +141,8 @@ namespace tut void ErrorTestObject::test<1>() // basic test of output { - llinfos << "test" << llendl; - llinfos << "bob" << llendl; + LL_INFOS() << "test" << LL_ENDL; + LL_INFOS() << "bob" << LL_ENDL; ensure_message_contains(0, "test"); ensure_message_contains(1, "bob"); @@ -156,11 +153,11 @@ namespace { void writeSome() { - lldebugs << "one" << llendl; - llinfos << "two" << llendl; - llwarns << "three" << llendl; - llerrs << "four" << llendl; - // fatal messages write out and addtional "error" message + LL_DEBUGS() << "one" << LL_ENDL; + LL_INFOS() << "two" << LL_ENDL; + LL_WARNS() << "three" << LL_ENDL; + // fatal messages write out an additional "error" message + LL_ERRS() << "four" << LL_ENDL; } }; @@ -259,19 +256,20 @@ namespace std::string writeReturningLocation() { - llinfos << "apple" << llendl; int this_line = __LINE__; + LL_INFOS() << "apple" << LL_ENDL; int this_line = __LINE__; return locationString(this_line); } - std::string writeReturningLocationAndFunction() + void writeReturningLocationAndFunction(std::string& location, std::string& function) { - llinfos << "apple" << llendl; int this_line = __LINE__; - return locationString(this_line) + __FUNCTION__; + LL_INFOS() << "apple" << LL_ENDL; int this_line = __LINE__; + location = locationString(this_line); + function = __FUNCTION__; } std::string errorReturningLocation() { - llerrs << "die" << llendl; int this_line = __LINE__; + LL_ERRS() << "die" << LL_ENDL; int this_line = __LINE__; return locationString(this_line); } } @@ -306,13 +304,13 @@ namespace tut std::string logFromGlobal(bool id) { - llinfos << (id ? "logFromGlobal: " : "") << "hi" << llendl; + LL_INFOS() << (id ? "logFromGlobal: " : "") << "hi" << LL_ENDL; return "logFromGlobal"; } static std::string logFromStatic(bool id) { - llinfos << (id ? "logFromStatic: " : "") << "hi" << llendl; + LL_INFOS() << (id ? "logFromStatic: " : "") << "hi" << LL_ENDL; return "logFromStatic"; } @@ -320,7 +318,7 @@ namespace { std::string logFromAnon(bool id) { - llinfos << (id ? "logFromAnon: " : "") << "hi" << llendl; + LL_INFOS() << (id ? "logFromAnon: " : "") << "hi" << LL_ENDL; return "logFromAnon"; } } @@ -328,7 +326,7 @@ namespace namespace Foo { std::string logFromNamespace(bool id) { - llinfos << (id ? "Foo::logFromNamespace: " : "") << "hi" << llendl; + LL_INFOS() << (id ? "Foo::logFromNamespace: " : "") << "hi" << LL_ENDL; //return "Foo::logFromNamespace"; // there is no standard way to get the namespace name, hence // we won't be testing for it @@ -342,12 +340,12 @@ namespace public: std::string logFromMember(bool id) { - llinfos << (id ? "ClassWithNoLogType::logFromMember: " : "") << "hi" << llendl; + LL_INFOS() << (id ? "ClassWithNoLogType::logFromMember: " : "") << "hi" << LL_ENDL; return "ClassWithNoLogType::logFromMember"; } static std::string logFromStatic(bool id) { - llinfos << (id ? "ClassWithNoLogType::logFromStatic: " : "") << "hi" << llendl; + LL_INFOS() << (id ? "ClassWithNoLogType::logFromStatic: " : "") << "hi" << LL_ENDL; return "ClassWithNoLogType::logFromStatic"; } }; @@ -357,12 +355,12 @@ namespace public: std::string logFromMember(bool id) { - llinfos << (id ? "ClassWithLogType::logFromMember: " : "") << "hi" << llendl; + LL_INFOS() << (id ? "ClassWithLogType::logFromMember: " : "") << "hi" << LL_ENDL; return "ClassWithLogType::logFromMember"; } static std::string logFromStatic(bool id) { - llinfos << (id ? "ClassWithLogType::logFromStatic: " : "") << "hi" << llendl; + LL_INFOS() << (id ? "ClassWithLogType::logFromStatic: " : "") << "hi" << LL_ENDL; return "ClassWithLogType::logFromStatic"; } }; @@ -434,19 +432,19 @@ namespace { std::string innerLogger() { - llinfos << "inside" << llendl; + LL_INFOS() << "inside" << LL_ENDL; return "moo"; } std::string outerLogger() { - llinfos << "outside(" << innerLogger() << ")" << llendl; + LL_INFOS() << "outside(" << innerLogger() << ")" << LL_ENDL; return "bar"; } void uberLogger() { - llinfos << "uber(" << outerLogger() << "," << innerLogger() << ")" << llendl; + LL_INFOS() << "uber(" << outerLogger() << "," << innerLogger() << ")" << LL_ENDL; } class LogWhileLogging @@ -454,7 +452,7 @@ namespace public: void print(std::ostream& out) const { - llinfos << "logging" << llendl; + LL_INFOS() << "logging" << LL_ENDL; out << "baz"; } }; @@ -465,7 +463,7 @@ namespace void metaLogger() { LogWhileLogging l; - llinfos << "meta(" << l << ")" << llendl; + LL_INFOS() << "meta(" << l << ")" << LL_ENDL; } } @@ -495,7 +493,7 @@ namespace tut } template<> template<> - // special handling of llerrs calls + // special handling of LL_ERRS() calls void ErrorTestObject::test<8>() { LLError::setPrintLocation(false); @@ -518,7 +516,7 @@ namespace void ufoSighting() { - llinfos << "ufo" << llendl; + LL_INFOS() << "ufo" << LL_ENDL; } } @@ -548,11 +546,13 @@ namespace tut LLError::setPrintLocation(true); LLError::setTimeFunction(roswell); mRecorder->setWantsTime(true); - std::string locationAndFunction = writeReturningLocationAndFunction(); + std::string location, + function; + writeReturningLocationAndFunction(location, function); - ensure_equals("order is time type location function message", + ensure_equals("order is location time type function message", mRecorder->message(0), - roswell() + " INFO: " + locationAndFunction + ": apple"); + location + roswell() + " INFO: " + function + ": apple"); } template<> template<> @@ -562,7 +562,7 @@ namespace tut TestRecorder* altRecorder(new TestRecorder); LLError::addRecorder(altRecorder); - llinfos << "boo" << llendl; + LL_INFOS() << "boo" << LL_ENDL; ensure_message_contains(0, "boo"); ensure_equals("alt recorder count", altRecorder->countMessages(), 1); @@ -574,7 +574,7 @@ namespace tut anotherRecorder->setWantsTime(true); LLError::addRecorder(anotherRecorder); - llinfos << "baz" << llendl; + LL_INFOS() << "baz" << LL_ENDL; std::string when = roswell(); @@ -590,10 +590,10 @@ class TestAlpha { LOG_CLASS(TestAlpha); public: - static void doDebug() { lldebugs << "add dice" << llendl; } - static void doInfo() { llinfos << "any idea" << llendl; } - static void doWarn() { llwarns << "aim west" << llendl; } - static void doError() { llerrs << "ate eels" << llendl; } + static void doDebug() { LL_DEBUGS() << "add dice" << LL_ENDL; } + static void doInfo() { LL_INFOS() << "any idea" << LL_ENDL; } + static void doWarn() { LL_WARNS() << "aim west" << LL_ENDL; } + static void doError() { LL_ERRS() << "ate eels" << LL_ENDL; } static void doAll() { doDebug(); doInfo(); doWarn(); doError(); } }; @@ -601,10 +601,10 @@ class TestBeta { LOG_CLASS(TestBeta); public: - static void doDebug() { lldebugs << "bed down" << llendl; } - static void doInfo() { llinfos << "buy iron" << llendl; } - static void doWarn() { llwarns << "bad word" << llendl; } - static void doError() { llerrs << "big easy" << llendl; } + static void doDebug() { LL_DEBUGS() << "bed down" << LL_ENDL; } + static void doInfo() { LL_INFOS() << "buy iron" << LL_ENDL; } + static void doWarn() { LL_WARNS() << "bad word" << LL_ENDL; } + static void doError() { LL_ERRS() << "big easy" << LL_ENDL; } static void doAll() { doDebug(); doInfo(); doWarn(); doError(); } }; diff --git a/indra/llcommon/tests/lleventcoro_test.cpp b/indra/llcommon/tests/lleventcoro_test.cpp index 5ebde1a31d..cb5e15eff2 100755 --- a/indra/llcommon/tests/lleventcoro_test.cpp +++ b/indra/llcommon/tests/lleventcoro_test.cpp @@ -346,13 +346,13 @@ namespace tut LLCoroEventPumps waiter; replyName = waiter.getName0(); errorName = waiter.getName1(); - WrapLL_ERRS capture; + WrapLLErrs capture; try { result = waiter.waitWithLog(self); debug("no exception"); } - catch (const WrapLL_ERRS::FatalException& e) + catch (const WrapLLErrs::FatalException& e) { debug(STRINGIZE("exception " << e.what())); threw = e.what(); @@ -436,7 +436,7 @@ namespace tut BEGIN { LLCoroEventPumps waiter; - WrapLL_ERRS capture; + WrapLLErrs capture; try { result = waiter.postAndWaitWithLog(self, @@ -444,7 +444,7 @@ namespace tut immediateAPI.getPump(), "reply", "error"); debug("no exception"); } - catch (const WrapLL_ERRS::FatalException& e) + catch (const WrapLLErrs::FatalException& e) { debug(STRINGIZE("exception " << e.what())); threw = e.what(); diff --git a/indra/llcommon/tests/lleventdispatcher_test.cpp b/indra/llcommon/tests/lleventdispatcher_test.cpp index 263c9b171f..5a4df81bf1 100755 --- a/indra/llcommon/tests/lleventdispatcher_test.cpp +++ b/indra/llcommon/tests/lleventdispatcher_test.cpp @@ -312,7 +312,7 @@ namespace tut { struct lleventdispatcher_data { - WrapLL_ERRS redirect; + WrapLLErrs redirect; Dispatcher work; Vars v; std::string name, desc; diff --git a/indra/llcommon/tests/lleventfilter_test.cpp b/indra/llcommon/tests/lleventfilter_test.cpp index ca05ef62a9..2cdfb52f2f 100755 --- a/indra/llcommon/tests/lleventfilter_test.cpp +++ b/indra/llcommon/tests/lleventfilter_test.cpp @@ -244,7 +244,7 @@ namespace tut void filter_object::test<4>() { set_test_name("LLEventTimeout::errorAfter()"); - WrapLL_ERRS capture; + WrapLLErrs capture; LLEventPump& driver(pumps.obtain("driver")); TestEventTimeout filter(driver); listener0.reset(0); @@ -274,7 +274,7 @@ namespace tut { mainloop.post(17); } - catch (const WrapLL_ERRS::FatalException& e) + catch (const WrapLLErrs::FatalException& e) { threw = e.what(); } diff --git a/indra/llcommon/tests/llinstancetracker_test.cpp b/indra/llcommon/tests/llinstancetracker_test.cpp index e769c3e22c..c7d4b8a06b 100755 --- a/indra/llcommon/tests/llinstancetracker_test.cpp +++ b/indra/llcommon/tests/llinstancetracker_test.cpp @@ -194,15 +194,15 @@ namespace tut { set_test_name("delete Keyed with outstanding instance_iter"); std::string what; - Keyed* keyed = new Keyed("one"); + Keyed* keyed = new Keyed("delete Keyed with outstanding instance_iter"); { - WrapLL_ERRS wrapper; + WrapLLErrs wrapper; Keyed::instance_iter i(Keyed::beginInstances()); try { delete keyed; } - catch (const WrapLL_ERRS::FatalException& e) + catch (const WrapLLErrs::FatalException& e) { what = e.what(); } @@ -215,15 +215,15 @@ namespace tut { set_test_name("delete Keyed with outstanding key_iter"); std::string what; - Keyed* keyed = new Keyed("one"); + Keyed* keyed = new Keyed("delete Keyed with outstanding key_it"); { - WrapLL_ERRS wrapper; + WrapLLErrs wrapper; Keyed::key_iter i(Keyed::beginKeys()); try { delete keyed; } - catch (const WrapLL_ERRS::FatalException& e) + catch (const WrapLLErrs::FatalException& e) { what = e.what(); } @@ -238,13 +238,13 @@ namespace tut std::string what; Unkeyed* unkeyed = new Unkeyed; { - WrapLL_ERRS wrapper; + WrapLLErrs wrapper; Unkeyed::instance_iter i(Unkeyed::beginInstances()); try { delete unkeyed; } - catch (const WrapLL_ERRS::FatalException& e) + catch (const WrapLLErrs::FatalException& e) { what = e.what(); } diff --git a/indra/llcommon/tests/llleap_test.cpp b/indra/llcommon/tests/llleap_test.cpp index 29060d4ef5..9ea822cb8d 100755 --- a/indra/llcommon/tests/llleap_test.cpp +++ b/indra/llcommon/tests/llleap_test.cpp @@ -22,7 +22,6 @@ // other Linden headers #include "../test/lltut.h" #include "../test/namedtempfile.h" -#include "../test/manageapr.h" #include "../test/catch_and_store_what_in.h" #include "wrapllerrs.h" #include "llevents.h" @@ -33,8 +32,6 @@ using boost::assign::list_of; -static ManageAPR manager; - StringVec sv(const StringVec& listof) { return listof; } #if defined(LL_WINDOWS) diff --git a/indra/llcommon/tests/llprocess_test.cpp b/indra/llcommon/tests/llprocess_test.cpp index 3e68ef068e..e4e766d51b 100755 --- a/indra/llcommon/tests/llprocess_test.cpp +++ b/indra/llcommon/tests/llprocess_test.cpp @@ -29,7 +29,6 @@ //#include <boost/lambda/bind.hpp> // other Linden headers #include "../test/lltut.h" -#include "../test/manageapr.h" #include "../test/namedtempfile.h" #include "../test/catch_and_store_what_in.h" #include "stringize.h" @@ -46,9 +45,12 @@ #endif //namespace lambda = boost::lambda; - -// static instance of this manages APR init/cleanup -static ManageAPR manager; + std::string apr_strerror_helper(apr_status_t rv) +{ + char errbuf[256]; + apr_strerror(rv, errbuf, sizeof(errbuf)); + return errbuf; +} /***************************************************************************** * Helpers @@ -60,7 +62,8 @@ static ManageAPR manager; #define aprchk(expr) aprchk_(#expr, (expr)) static void aprchk_(const char* call, apr_status_t rv, apr_status_t expected=APR_SUCCESS) { - tut::ensure_equals(STRINGIZE(call << " => " << rv << ": " << manager.strerror(rv)), + tut::ensure_equals(STRINGIZE(call << " => " << rv << ": " << apr_strerror_helper + (rv)), rv, expected); } diff --git a/indra/llcommon/tests/llsdserialize_test.cpp b/indra/llcommon/tests/llsdserialize_test.cpp index 4d436e8897..b5893135ea 100755 --- a/indra/llcommon/tests/llsdserialize_test.cpp +++ b/indra/llcommon/tests/llsdserialize_test.cpp @@ -56,12 +56,9 @@ namespace lambda = boost::lambda; #include "../llformat.h" #include "../test/lltut.h" -#include "../test/manageapr.h" #include "../test/namedtempfile.h" #include "stringize.h" -static ManageAPR manager; - std::vector<U8> string_to_vector(const std::string& str) { return std::vector<U8>(str.begin(), str.end()); @@ -268,7 +265,7 @@ namespace tut { std::stringstream stream; mFormatter->format(v, stream); - //llinfos << "checkRoundTrip: length " << stream.str().length() << llendl; + //LL_INFOS() << "checkRoundTrip: length " << stream.str().length() << LL_ENDL; LLSD w; mParser->reset(); // reset() call is needed since test code re-uses mParser mParser->parse(stream, w, stream.str().size()); @@ -1723,5 +1720,6 @@ namespace tut "This string\n" "has several\n" "lines."); + } } diff --git a/indra/llcommon/tests/lltrace_test.cpp b/indra/llcommon/tests/lltrace_test.cpp new file mode 100644 index 0000000000..0a9d85ad00 --- /dev/null +++ b/indra/llcommon/tests/lltrace_test.cpp @@ -0,0 +1,142 @@ +/** + * @file llsingleton_test.cpp + * @date 2011-08-11 + * @brief Unit test for the LLSingleton class + * + * $LicenseInfo:firstyear=2011&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2011, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "lltrace.h" +#include "lltracethreadrecorder.h" +#include "lltracerecording.h" +#include "../test/lltut.h" + +namespace LLUnits +{ + // using powers of 2 to allow strict floating point equality + LL_DECLARE_BASE_UNIT(Ounces, "oz"); + LL_DECLARE_DERIVED_UNIT(TallCup, "", Ounces, / 12); + LL_DECLARE_DERIVED_UNIT(GrandeCup, "", Ounces, / 16); + LL_DECLARE_DERIVED_UNIT(VentiCup, "", Ounces, / 20); + + LL_DECLARE_BASE_UNIT(Grams, "g"); + LL_DECLARE_DERIVED_UNIT(Milligrams, "mg", Grams, * 1000); +} + +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Ounces); +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, TallCup); +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, GrandeCup); +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, VentiCup); +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Grams); +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Milligrams); + + +namespace tut +{ + using namespace LLTrace; + struct trace + { + ThreadRecorder mRecorder; + }; + + typedef test_group<trace> trace_t; + typedef trace_t::object trace_object_t; + tut::trace_t tut_singleton("LLTrace"); + + static CountStatHandle<S32> sCupsOfCoffeeConsumed("coffeeconsumed", "Delicious cup of dark roast."); + static SampleStatHandle<F32Milligrams> sCaffeineLevelStat("caffeinelevel", "Coffee buzz quotient"); + static EventStatHandle<S32Ounces> sOuncesPerCup("cupsize", "Large, huge, or ginormous"); + + static F32 sCaffeineLevel(0.f); + const F32Milligrams sCaffeinePerOz(18.f); + + void drink_coffee(S32 num_cups, S32Ounces cup_size) + { + add(sCupsOfCoffeeConsumed, num_cups); + for (S32 i = 0; i < num_cups; i++) + { + record(sOuncesPerCup, cup_size); + } + + sCaffeineLevel += F32Ounces(num_cups * cup_size).value() * sCaffeinePerOz.value(); + sample(sCaffeineLevelStat, sCaffeineLevel); + } + + // basic data collection + template<> template<> + void trace_object_t::test<1>() + { + sample(sCaffeineLevelStat, sCaffeineLevel); + + Recording all_day; + Recording at_work; + Recording after_3pm; + + all_day.start(); + { + // warm up with one grande cup + drink_coffee(1, S32TallCup(1)); + + // go to work + at_work.start(); + { + // drink 3 tall cups, 1 after 3 pm + drink_coffee(2, S32GrandeCup(1)); + after_3pm.start(); + drink_coffee(1, S32GrandeCup(1)); + } + at_work.stop(); + drink_coffee(1, S32VentiCup(1)); + } + // don't need to stop recordings to get accurate values out of them + //after_3pm.stop(); + //all_day.stop(); + + ensure("count stats are counted when recording is active", + at_work.getSum(sCupsOfCoffeeConsumed) == 3 + && all_day.getSum(sCupsOfCoffeeConsumed) == 5 + && after_3pm.getSum(sCupsOfCoffeeConsumed) == 2); + ensure("measurement sums are counted when recording is active", + at_work.getSum(sOuncesPerCup) == S32Ounces(48) + && all_day.getSum(sOuncesPerCup) == S32Ounces(80) + && after_3pm.getSum(sOuncesPerCup) == S32Ounces(36)); + ensure("measurement min is specific to when recording is active", + at_work.getMin(sOuncesPerCup) == S32GrandeCup(1) + && all_day.getMin(sOuncesPerCup) == S32TallCup(1) + && after_3pm.getMin(sOuncesPerCup) == S32GrandeCup(1)); + ensure("measurement max is specific to when recording is active", + at_work.getMax(sOuncesPerCup) == S32GrandeCup(1) + && all_day.getMax(sOuncesPerCup) == S32VentiCup(1) + && after_3pm.getMax(sOuncesPerCup) == S32VentiCup(1)); + ensure("sample min is specific to when recording is active", + at_work.getMin(sCaffeineLevelStat) == sCaffeinePerOz * ((S32Ounces)S32TallCup(1)).value() + && all_day.getMin(sCaffeineLevelStat) == F32Milligrams(0.f) + && after_3pm.getMin(sCaffeineLevelStat) == sCaffeinePerOz * ((S32Ounces)S32TallCup(1) + (S32Ounces)S32GrandeCup(2)).value()); + ensure("sample max is specific to when recording is active", + at_work.getMax(sCaffeineLevelStat) == sCaffeinePerOz * ((S32Ounces)S32TallCup(1) + (S32Ounces)S32GrandeCup(3)).value() + && all_day.getMax(sCaffeineLevelStat) == sCaffeinePerOz * ((S32Ounces)S32TallCup(1) + (S32Ounces)S32GrandeCup(3) + (S32Ounces)S32VentiCup(1)).value() + && after_3pm.getMax(sCaffeineLevelStat) == sCaffeinePerOz * ((S32Ounces)S32TallCup(1) + (S32Ounces)S32GrandeCup(3) + (S32Ounces)S32VentiCup(1)).value()); + } + +} diff --git a/indra/llcommon/tests/llunits_test.cpp b/indra/llcommon/tests/llunits_test.cpp new file mode 100644 index 0000000000..57cf9810af --- /dev/null +++ b/indra/llcommon/tests/llunits_test.cpp @@ -0,0 +1,388 @@ +/** + * @file llsingleton_test.cpp + * @date 2011-08-11 + * @brief Unit test for the LLSingleton class + * + * $LicenseInfo:firstyear=2011&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2011, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "llunits.h" +#include "../test/lltut.h" + +namespace LLUnits +{ + // using powers of 2 to allow strict floating point equality + LL_DECLARE_BASE_UNIT(Quatloos, "Quat"); + LL_DECLARE_DERIVED_UNIT(Latinum, "Lat", Quatloos, / 4); + LL_DECLARE_DERIVED_UNIT(Solari, "Sol", Latinum, * 16); +} + +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Quatloos); +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Latinum); +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Solari); + +namespace LLUnits +{ + LL_DECLARE_BASE_UNIT(Celcius, "c"); + LL_DECLARE_DERIVED_UNIT(Fahrenheit, "f", Celcius, * 9 / 5 + 32); + LL_DECLARE_DERIVED_UNIT(Kelvin, "k", Celcius, + 273.15f); +} + +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Celcius); +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Fahrenheit); +LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Kelvin); + + +namespace tut +{ + using namespace LLUnits; + struct units + { + }; + + typedef test_group<units> units_t; + typedef units_t::object units_object_t; + tut::units_t tut_singleton("LLUnit"); + + // storage type conversions + template<> template<> + void units_object_t::test<1>() + { + LLUnit<F32, Quatloos> float_quatloos; + ensure("default float unit is zero", float_quatloos == F32Quatloos(0.f)); + + LLUnit<F32, Quatloos> float_initialize_quatloos(1); + ensure("non-zero initialized unit", float_initialize_quatloos == F32Quatloos(1.f)); + + LLUnit<S32, Quatloos> int_quatloos; + ensure("default int unit is zero", int_quatloos == S32Quatloos(0)); + + int_quatloos = S32Quatloos(42); + ensure("int assignment is preserved", int_quatloos == S32Quatloos(42)); + float_quatloos = int_quatloos; + ensure("float assignment from int preserves value", float_quatloos == F32Quatloos(42.f)); + + int_quatloos = float_quatloos; + ensure("int assignment from float preserves value", int_quatloos == S32Quatloos(42)); + + float_quatloos = F32Quatloos(42.1f); + int_quatloos = float_quatloos; + ensure("int units truncate float units on assignment", int_quatloos == S32Quatloos(42)); + + LLUnit<U32, Quatloos> unsigned_int_quatloos(float_quatloos); + ensure("unsigned int can be initialized from signed int", unsigned_int_quatloos == S32Quatloos(42)); + + S32Solari int_solari(1); + + float_quatloos = int_solari; + ensure("fractional units are preserved in conversion from integer to float type", float_quatloos == F32Quatloos(0.25f)); + + int_quatloos = S32Quatloos(1); + F32Solari float_solari = int_quatloos; + ensure("can convert with fractional intermediates from integer to float type", float_solari == F32Solari(4.f)); + } + + // conversions to/from base unit + template<> template<> + void units_object_t::test<2>() + { + LLUnit<F32, Quatloos> quatloos(1.f); + LLUnit<F32, Latinum> latinum_bars(quatloos); + ensure("conversion between units is automatic via initialization", latinum_bars == F32Latinum(1.f / 4.f)); + + latinum_bars = S32Latinum(256); + quatloos = latinum_bars; + ensure("conversion between units is automatic via assignment, and bidirectional", quatloos == S32Quatloos(1024)); + + LLUnit<S32, Quatloos> single_quatloo(1); + LLUnit<F32, Latinum> quarter_latinum = single_quatloo; + ensure("division of integer unit preserves fractional values when converted to float unit", quarter_latinum == F32Latinum(0.25f)); + } + + // conversions across non-base units + template<> template<> + void units_object_t::test<3>() + { + LLUnit<F32, Quatloos> quatloos(1024); + LLUnit<F32, Solari> solari(quatloos); + ensure("conversions can work between indirectly related units: Quatloos -> Latinum -> Solari", solari == S32Solari(4096)); + + LLUnit<F32, Latinum> latinum_bars = solari; + ensure("Non base units can be converted between each other", latinum_bars == S32Latinum(256)); + } + + // math operations + template<> template<> + void units_object_t::test<4>() + { + // exercise math operations + LLUnit<F32, Quatloos> quatloos(1.f); + quatloos *= 4.f; + ensure(quatloos == S32Quatloos(4)); + quatloos = quatloos * 2; + ensure(quatloos == S32Quatloos(8)); + quatloos = 2.f * quatloos; + ensure(quatloos == S32Quatloos(16)); + + quatloos += F32Quatloos(4.f); + ensure(quatloos == S32Quatloos(20)); + quatloos += S32Quatloos(4); + ensure(quatloos == S32Quatloos(24)); + quatloos = quatloos + S32Quatloos(4); + ensure(quatloos == S32Quatloos(28)); + quatloos = S32Quatloos(4) + quatloos; + ensure(quatloos == S32Quatloos(32)); + quatloos += quatloos * 3; + ensure(quatloos == S32Quatloos(128)); + + quatloos -= quatloos / 4 * 3; + ensure(quatloos == S32Quatloos(32)); + quatloos = quatloos - S32Quatloos(8); + ensure(quatloos == S32Quatloos(24)); + quatloos -= S32Quatloos(4); + ensure(quatloos == S32Quatloos(20)); + quatloos -= F32Quatloos(4.f); + ensure(quatloos == S32Quatloos(16)); + + quatloos /= 2.f; + ensure(quatloos == S32Quatloos(8)); + quatloos = quatloos / 4; + ensure(quatloos == S32Quatloos(2)); + + F32 ratio = quatloos / LLUnit<F32, Quatloos>(2.f); + ensure(ratio == 1); + ratio = quatloos / LLUnit<F32, Solari>(8.f); + ensure(ratio == 1); + + quatloos += LLUnit<F32, Solari>(8.f); + ensure(quatloos == S32Quatloos(4)); + quatloos -= LLUnit<F32, Latinum>(1.f); + ensure(quatloos == S32Quatloos(0)); + } + + // comparison operators + template<> template<> + void units_object_t::test<5>() + { + LLUnit<S32, Quatloos> quatloos(1); + ensure("can perform less than comparison against same type", quatloos < S32Quatloos(2)); + ensure("can perform less than comparison against different storage type", quatloos < F32Quatloos(2.f)); + ensure("can perform less than comparison against different units", quatloos < S32Latinum(5)); + ensure("can perform less than comparison against different storage type and units", quatloos < F32Latinum(5.f)); + + ensure("can perform greater than comparison against same type", quatloos > S32Quatloos(0)); + ensure("can perform greater than comparison against different storage type", quatloos > F32Quatloos(0.f)); + ensure("can perform greater than comparison against different units", quatloos > S32Latinum(0)); + ensure("can perform greater than comparison against different storage type and units", quatloos > F32Latinum(0.f)); + + } + + bool accept_explicit_quatloos(S32Quatloos q) + { + return true; + } + + bool accept_implicit_quatloos(S32Quatloos q) + { + return true; + } + + // signature compatibility + template<> template<> + void units_object_t::test<6>() + { + S32Quatloos quatloos(1); + ensure("can pass unit values as argument", accept_explicit_quatloos(S32Quatloos(1))); + ensure("can pass unit values as argument", accept_explicit_quatloos(quatloos)); + } + + // implicit units + template<> template<> + void units_object_t::test<7>() + { + LLUnit<F32, Quatloos> quatloos; + LLUnitImplicit<F32, Quatloos> quatloos_implicit = quatloos + S32Quatloos(1); + ensure("can initialize implicit unit from explicit", quatloos_implicit == 1); + + quatloos = quatloos_implicit; + ensure("can assign implicit unit to explicit unit", quatloos == S32Quatloos(1)); + quatloos += quatloos_implicit; + ensure("can perform math operation using mixture of implicit and explicit units", quatloos == S32Quatloos(2)); + + // math operations on implicits + quatloos_implicit = 1; + ensure(quatloos_implicit == 1); + + quatloos_implicit += 2; + ensure(quatloos_implicit == 3); + + quatloos_implicit *= 2; + ensure(quatloos_implicit == 6); + + quatloos_implicit -= 1; + ensure(quatloos_implicit == 5); + + quatloos_implicit /= 5; + ensure(quatloos_implicit == 1); + + quatloos_implicit = quatloos_implicit + 3 + quatloos_implicit; + ensure(quatloos_implicit == 5); + + quatloos_implicit = 10 - quatloos_implicit - 1; + ensure(quatloos_implicit == 4); + + quatloos_implicit = 2 * quatloos_implicit * 2; + ensure(quatloos_implicit == 16); + + F32 one_half = quatloos_implicit / (quatloos_implicit * 2); + ensure(one_half == 0.5f); + + // implicit conversion to POD + F32 float_val = quatloos_implicit; + ensure("implicit units convert implicitly to regular values", float_val == 16); + + S32 int_val = quatloos_implicit; + ensure("implicit units convert implicitly to regular values", int_val == 16); + + // conversion of implicits + LLUnitImplicit<F32, Latinum> latinum_implicit(2); + ensure("implicit units of different types are comparable", latinum_implicit * 2 == quatloos_implicit); + + quatloos_implicit += F32Quatloos(10); + ensure("can add-assign explicit units", quatloos_implicit == 26); + + quatloos_implicit -= F32Quatloos(10); + ensure("can subtract-assign explicit units", quatloos_implicit == 16); + + // comparisons + ensure("can compare greater than implicit unit", quatloos_implicit > F32QuatloosImplicit(0.f)); + ensure("can compare greater than non-implicit unit", quatloos_implicit > F32Quatloos(0.f)); + ensure("can compare greater than or equal to implicit unit", quatloos_implicit >= F32QuatloosImplicit(0.f)); + ensure("can compare greater than or equal to non-implicit unit", quatloos_implicit >= F32Quatloos(0.f)); + ensure("can compare less than implicit unit", quatloos_implicit < F32QuatloosImplicit(20.f)); + ensure("can compare less than non-implicit unit", quatloos_implicit < F32Quatloos(20.f)); + ensure("can compare less than or equal to implicit unit", quatloos_implicit <= F32QuatloosImplicit(20.f)); + ensure("can compare less than or equal to non-implicit unit", quatloos_implicit <= F32Quatloos(20.f)); + } + + // precision tests + template<> template<> + void units_object_t::test<8>() + { + U32Bytes max_bytes(U32_MAX); + S32Megabytes mega_bytes = max_bytes; + ensure("max available precision is used when converting units", mega_bytes == (S32Megabytes)4095); + + mega_bytes = (S32Megabytes)-5 + (U32Megabytes)1; + ensure("can mix signed and unsigned in units addition", mega_bytes == (S32Megabytes)-4); + + mega_bytes = (U32Megabytes)5 + (S32Megabytes)-1; + ensure("can mix unsigned and signed in units addition", mega_bytes == (S32Megabytes)4); + } + + // default units + template<> template<> + void units_object_t::test<9>() + { + U32Gigabytes GB(1); + U32Megabytes MB(GB); + U32Kilobytes KB(GB); + U32Bytes B(GB); + + ensure("GB -> MB conversion", MB.value() == 1024); + ensure("GB -> KB conversion", KB.value() == 1024 * 1024); + ensure("GB -> B conversion", B.value() == 1024 * 1024 * 1024); + + KB = U32Kilobytes(1); + U32Kilobits Kb(KB); + U32Bits b(KB); + ensure("KB -> Kb conversion", Kb.value() == 8); + ensure("KB -> b conversion", b.value() == 8 * 1024); + + U32Days days(1); + U32Hours hours(days); + U32Minutes minutes(days); + U32Seconds seconds(days); + U32Milliseconds ms(days); + + ensure("days -> hours conversion", hours.value() == 24); + ensure("days -> minutes conversion", minutes.value() == 24 * 60); + ensure("days -> seconds conversion", seconds.value() == 24 * 60 * 60); + ensure("days -> ms conversion", ms.value() == 24 * 60 * 60 * 1000); + + U32Kilometers km(1); + U32Meters m(km); + U32Centimeters cm(km); + U32Millimeters mm(km); + + ensure("km -> m conversion", m.value() == 1000); + ensure("km -> cm conversion", cm.value() == 1000 * 100); + ensure("km -> mm conversion", mm.value() == 1000 * 1000); + + U32Gigahertz GHz(1); + U32Megahertz MHz(GHz); + U32Kilohertz KHz(GHz); + U32Hertz Hz(GHz); + + ensure("GHz -> MHz conversion", MHz.value() == 1000); + ensure("GHz -> KHz conversion", KHz.value() == 1000 * 1000); + ensure("GHz -> Hz conversion", Hz.value() == 1000 * 1000 * 1000); + + F32Radians rad(6.2831853071795f); + S32Degrees deg(rad); + ensure("radians -> degrees conversion", deg.value() == 360); + + F32Percent percent(50); + F32Ratio ratio(percent); + ensure("percent -> ratio conversion", ratio.value() == 0.5f); + + U32Kilotriangles ktris(1); + U32Triangles tris(ktris); + ensure("kilotriangles -> triangles conversion", tris.value() == 1000); + } + + bool value_near(F32 value, F32 target, F32 threshold) + { + return fabsf(value - target) < threshold; + } + + // linear transforms + template<> template<> + void units_object_t::test<10>() + { + F32Celcius float_celcius(100); + F32Fahrenheit float_fahrenheit(float_celcius); + ensure("floating point celcius -> fahrenheit conversion using linear transform", value_near(float_fahrenheit.value(), 212, 0.1f) ); + + float_celcius = float_fahrenheit; + ensure("floating point fahrenheit -> celcius conversion using linear transform (round trip)", value_near(float_celcius.value(), 100.f, 0.1f) ); + + S32Celcius int_celcius(100); + S32Fahrenheit int_fahrenheit(int_celcius); + ensure("integer celcius -> fahrenheit conversion using linear transform", int_fahrenheit.value() == 212); + + int_celcius = int_fahrenheit; + ensure("integer fahrenheit -> celcius conversion using linear transform (round trip)", int_celcius.value() == 100); + } +} diff --git a/indra/llcommon/tests/reflection_test.cpp b/indra/llcommon/tests/reflection_test.cpp deleted file mode 100755 index 8980ebb1f1..0000000000 --- a/indra/llcommon/tests/reflection_test.cpp +++ /dev/null @@ -1,220 +0,0 @@ -/** - * @file reflection_test.cpp - * @date May 2006 - * @brief Reflection unit tests. - * - * $LicenseInfo:firstyear=2006&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#include "../linden_common.h" -#include "../reflective.h" -#include "../metaclasst.h" -#include "../metapropertyt.h" -#include "../stdtypes.h" - -#include "../test/lltut.h" - -namespace tut -{ - class TestAggregatedData : public LLReflective - { - public: - TestAggregatedData() {;} - virtual const LLMetaClass& getMetaClass() const; - - private: - }; - - class TestReflectionData : public LLReflective - { - public: - TestReflectionData() : mInt(42), mString("foo"), mNullPtr(NULL), mPtr(new TestAggregatedData()), mRef(*(new TestAggregatedData)) {;} - virtual ~TestReflectionData() {delete mPtr;} - virtual const LLMetaClass& getMetaClass() const; - - static U32 getPropertyCount() {return 5;} - - private: - - friend class LLMetaClassT<TestReflectionData>; - S32 mInt; - std::string mString; - TestAggregatedData* mNullPtr; - TestAggregatedData* mPtr; - TestAggregatedData mObj; - TestAggregatedData& mRef; - }; -} - -template <> -void LLMetaClassT<tut::TestReflectionData>::reflectProperties(LLMetaClass& meta_class) -{ - reflectProperty(meta_class, "mInt", &tut::TestReflectionData::mInt); - reflectProperty(meta_class, "mString", &tut::TestReflectionData::mString); - reflectPtrProperty(meta_class, "mNullPtr", &tut::TestReflectionData::mNullPtr); - reflectPtrProperty(meta_class, "mPtr", &tut::TestReflectionData::mPtr); - reflectProperty(meta_class, "mObj", &tut::TestReflectionData::mObj); - //reflectProperty(meta_class, "mRef", &tut::TestReflectionData::mRef); // AARGH! -} - -namespace tut -{ - // virtual - const LLMetaClass& TestReflectionData::getMetaClass() const - { - return LLMetaClassT<TestReflectionData>::instance(); - } - - const LLMetaClass& TestAggregatedData::getMetaClass() const - { - return LLMetaClassT<TestAggregatedData>::instance(); - } -} - -namespace tut -{ - typedef tut::test_group<TestReflectionData> TestReflectionGroup; - typedef TestReflectionGroup::object TestReflectionObject; - TestReflectionGroup gTestReflectionGroup("reflection"); - - template<> template<> - void TestReflectionObject::test<1>() - { - // Check properties can be found. - const LLMetaClass& meta_class = LLMetaClassT<TestReflectionData>::instance(); - const LLMetaProperty* null = NULL; - ensure_not_equals(meta_class.findProperty("mInt"), null); - ensure_not_equals(meta_class.findProperty("mString"), null); - } - - template<> template<> - void TestReflectionObject::test<2>() - { - // Check non-existent property cannot be found. - const LLMetaClass& meta_class = LLMetaClassT<TestReflectionData>::instance(); - const LLMetaProperty* null = NULL; - ensure_equals(meta_class.findProperty("foo"), null); - } - - template<> template<> - void TestReflectionObject::test<3>() - { - // Check integer property has correct value. - const LLMetaClass& meta_class = LLMetaClassT<TestReflectionData>::instance(); - ensure_equals(meta_class.findProperty("mInt")->getLLSD(this).asInteger(), 42); - } - - template<> template<> - void TestReflectionObject::test<4>() - { - // Check string property has correct value. - const LLMetaClass& meta_class = LLMetaClassT<TestReflectionData>::instance(); - ensure_equals(meta_class.findProperty("mString")->getLLSD(this).asString(), std::string("foo")); - } - - template<> template<> - void TestReflectionObject::test<5>() - { - // Check NULL reference property has correct value. - const LLMetaClass& meta_class = LLMetaClassT<TestReflectionData>::instance(); - const LLReflective* null = NULL; - ensure_equals(meta_class.findProperty("mNullPtr")->get(this), null); - } - - template<> template<> - void TestReflectionObject::test<6>() - { - // Check reference property has correct value. - const LLMetaClass& meta_class = LLMetaClassT<TestReflectionData>::instance(); - const LLReflective* null = NULL; - const LLReflective* ref = meta_class.findProperty("mPtr")->get(this); - ensure_not_equals(ref, null); - } - - template<> template<> - void TestReflectionObject::test<7>() - { - // Check reflective property has correct value. - const LLMetaClass& meta_class = LLMetaClassT<TestReflectionData>::instance(); - const LLReflective* null = NULL; - const LLReflective* ref = meta_class.findProperty("mObj")->get(this); - ensure_not_equals(ref, null); - } - - template<> template<> - void TestReflectionObject::test<8>() - { - // Check property count. - const LLMetaClass& meta_class = LLMetaClassT<TestReflectionData>::instance(); - ensure_equals(meta_class.getPropertyCount(), TestReflectionData::getPropertyCount()); - } - - template<> template<> - void TestReflectionObject::test<9>() - { - // Check property iteration. - const LLMetaClass& meta_class = LLMetaClassT<TestReflectionData>::instance(); - U32 count = 0; - LLMetaClass::PropertyIterator iter; - for(iter = meta_class.beginProperties(); iter != meta_class.endProperties(); ++iter) - { - ++count; - } - ensure_equals(count, TestReflectionData::getPropertyCount()); - } - - template<> template<> - void TestReflectionObject::test<10>() - { - // Check meta classes of different types do not compare equal. - const LLMetaClass* reflection_data_meta_class = &(LLMetaClassT<TestReflectionData>::instance()); - const LLMetaClass* aggregated_data_meta_class = &(LLMetaClassT<TestAggregatedData>::instance()); - ensure_not_equals(reflection_data_meta_class, aggregated_data_meta_class); - } - - template<> template<> - void TestReflectionObject::test<11>() - { - // Check class cast checks. - const LLMetaClass& meta_class = LLMetaClassT<TestReflectionData>::instance(); - TestAggregatedData* aggregated_data = new TestAggregatedData(); - LLMetaClass::PropertyIterator iter; - U32 exception_count = 0; - for(iter = meta_class.beginProperties(); iter != meta_class.endProperties(); ++iter) - { - try - { - const LLMetaProperty* property = (*iter).second; - const LLReflective* reflective = property->get(aggregated_data); // Wrong reflective type, should throw exception. - - // useless op to get rid of compiler warning. - reflective = reflective; - } - catch(...) - { - ++exception_count; - } - } - ensure_equals(exception_count, getPropertyCount()); - - } -} diff --git a/indra/llcommon/tests/stringize_test.cpp b/indra/llcommon/tests/stringize_test.cpp index 3d34f23998..3e4ca548e5 100755 --- a/indra/llcommon/tests/stringize_test.cpp +++ b/indra/llcommon/tests/stringize_test.cpp @@ -67,6 +67,8 @@ namespace tut llsd["i"] = i; llsd["d"] = d; llsd["abc"] = abc; + def = L"def ghi"; + } char c; @@ -76,6 +78,7 @@ namespace tut float f; double d; std::string abc; + std::wstring def; LLSD llsd; }; typedef test_group<stringize_data> stringize_group; @@ -92,6 +95,7 @@ namespace tut ensure_equals(stringize(f), "3.14159"); ensure_equals(stringize(d), "3.14159"); ensure_equals(stringize(abc), "abc def"); + ensure_equals(stringize(def), "def ghi"); //Will generate llwarns due to narrowing. ensure_equals(stringize(llsd), "{'abc':'abc def','d':r3.14159,'i':i34}"); } @@ -101,4 +105,20 @@ namespace tut ensure_equals(STRINGIZE("c is " << c), "c is c"); ensure_equals(STRINGIZE(std::setprecision(4) << d), "3.142"); } + + template<> template<> + void stringize_object::test<3>() + { + //Tests rely on validity of wstring_to_utf8str() + ensure_equals(wstring_to_utf8str(wstringize(c)), wstring_to_utf8str(L"c")); + ensure_equals(wstring_to_utf8str(wstringize(s)), wstring_to_utf8str(L"17")); + ensure_equals(wstring_to_utf8str(wstringize(i)), wstring_to_utf8str(L"34")); + ensure_equals(wstring_to_utf8str(wstringize(l)), wstring_to_utf8str(L"68")); + ensure_equals(wstring_to_utf8str(wstringize(f)), wstring_to_utf8str(L"3.14159")); + ensure_equals(wstring_to_utf8str(wstringize(d)), wstring_to_utf8str(L"3.14159")); + ensure_equals(wstring_to_utf8str(wstringize(abc)), wstring_to_utf8str(L"abc def")); + ensure_equals(wstring_to_utf8str(wstringize(abc)), wstring_to_utf8str(wstringize(abc.c_str()))); + ensure_equals(wstring_to_utf8str(wstringize(def)), wstring_to_utf8str(L"def ghi")); + // ensure_equals(wstring_to_utf8str(wstringize(llsd)), wstring_to_utf8str(L"{'abc':'abc def','d':r3.14159,'i':i34}")); + } } // namespace tut diff --git a/indra/llcommon/tests/wrapllerrs.h b/indra/llcommon/tests/wrapllerrs.h index a4d3a4e026..3137bd8fea 100755 --- a/indra/llcommon/tests/wrapllerrs.h +++ b/indra/llcommon/tests/wrapllerrs.h @@ -46,9 +46,9 @@ // replicate, but better to reuse extern void wouldHaveCrashed(const std::string& message); -struct WrapLL_ERRS +struct WrapLLErrs { - WrapLL_ERRS(): + WrapLLErrs(): // Resetting Settings discards the default Recorder that writes to // stderr. Otherwise, expected llerrs (LL_ERRS) messages clutter the // console output of successful tests, potentially confusing things. @@ -57,10 +57,10 @@ struct WrapLL_ERRS mPriorFatal(LLError::getFatalFunction()) { // Make LL_ERRS call our own operator() method - LLError::setFatalFunction(boost::bind(&WrapLL_ERRS::operator(), this, _1)); + LLError::setFatalFunction(boost::bind(&WrapLLErrs::operator(), this, _1)); } - ~WrapLL_ERRS() + ~WrapLLErrs() { LLError::setFatalFunction(mPriorFatal); LLError::restoreSettings(mPriorErrorSettings); diff --git a/indra/llcommon/timing.h b/indra/llcommon/timing.h deleted file mode 100755 index c408d4c446..0000000000 --- a/indra/llcommon/timing.h +++ /dev/null @@ -1,42 +0,0 @@ -/** - * @file timing.h - * @brief Cross-platform routines for doing timing. - * - * $LicenseInfo:firstyear=2000&license=viewerlgpl$ - * Second Life Viewer Source Code - * Copyright (C) 2010, Linden Research, Inc. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; - * version 2.1 of the License only. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * - * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA - * $/LicenseInfo$ - */ - -#ifndef LL_TIMING_H -#define LL_TIMING_H - - -#if LL_LINUX || LL_DARWIN || LL_SOLARIS -#include <sys/time.h> -#endif - - -const F32 SEC_TO_MICROSEC = 1000000.f; -const U64 SEC_TO_MICROSEC_U64 = 1000000; -const U32 SEC_PER_DAY = 86400; - -// functionality has been moved lltimer.{cpp,h}. This file will be deprecated in the future. - -#endif diff --git a/indra/llcommon/u64.cpp b/indra/llcommon/u64.cpp index eea16c5036..02c2c15d26 100755 --- a/indra/llcommon/u64.cpp +++ b/indra/llcommon/u64.cpp @@ -36,7 +36,7 @@ U64 str_to_U64(const std::string& str) if (!aptr) { - llwarns << "str_to_U64: Bad string to U64 conversion attempt: format\n" << llendl; + LL_WARNS() << "str_to_U64: Bad string to U64 conversion attempt: format\n" << LL_ENDL; } else { |