summaryrefslogtreecommitdiff
path: root/indra/llcommon
diff options
context:
space:
mode:
authorRichard Linden <none@none>2013-06-05 19:05:43 -0700
committerRichard Linden <none@none>2013-06-05 19:05:43 -0700
commit0a96b47663c99914c587cdcb8bcdc096bbf55fa3 (patch)
tree67bca4958927ed7f6df423de05e42cd271292391 /indra/llcommon
parentdcfb18373eca7986a73d8b9a1d34970cc0a23ed9 (diff)
parenta74b5dfa923f8eeccc9b786143f0f832de3ad450 (diff)
merge with viewer-release
Diffstat (limited to 'indra/llcommon')
-rwxr-xr-xindra/llcommon/CMakeLists.txt46
-rwxr-xr-xindra/llcommon/doublelinkedlist.h1397
-rwxr-xr-xindra/llcommon/llapr.cpp25
-rwxr-xr-xindra/llcommon/llapr.h47
-rwxr-xr-xindra/llcommon/llassoclist.h296
-rwxr-xr-xindra/llcommon/llcommon.cpp7
-rwxr-xr-xindra/llcommon/llcriticaldamp.cpp77
-rwxr-xr-xindra/llcommon/llcriticaldamp.h32
-rwxr-xr-xindra/llcommon/lldate.cpp14
-rwxr-xr-xindra/llcommon/lldate.h5
-rwxr-xr-xindra/llcommon/lldefs.h3
-rwxr-xr-xindra/llcommon/lldeleteutils.h47
-rwxr-xr-xindra/llcommon/lldepthstack.h34
-rwxr-xr-xindra/llcommon/lldlinked.h93
-rwxr-xr-xindra/llcommon/lldqueueptr.h352
-rwxr-xr-xindra/llcommon/llenum.h78
-rwxr-xr-xindra/llcommon/llerrorlegacy.h9
-rwxr-xr-xindra/llcommon/llevents.cpp1
-rwxr-xr-xindra/llcommon/llfasttimer.cpp636
-rwxr-xr-xindra/llcommon/llfasttimer.h315
-rwxr-xr-xindra/llcommon/llfile.cpp4
-rwxr-xr-xindra/llcommon/llfindlocale.cpp2
-rwxr-xr-xindra/llcommon/llindexedqueue.h155
-rwxr-xr-xindra/llcommon/llinitparam.cpp36
-rwxr-xr-xindra/llcommon/llinitparam.h434
-rwxr-xr-xindra/llcommon/llinstancetracker.cpp26
-rwxr-xr-xindra/llcommon/llinstancetracker.h67
-rwxr-xr-xindra/llcommon/lllazy.h399
-rwxr-xr-xindra/llcommon/llleap.cpp2
-rwxr-xr-xindra/llcommon/lllocalidhashmap.h895
-rwxr-xr-xindra/llcommon/llmd5.cpp1
-rwxr-xr-xindra/llcommon/llmemory.cpp1
-rwxr-xr-xindra/llcommon/llmemory.h17
-rwxr-xr-xindra/llcommon/llmetricperformancetester.cpp7
-rwxr-xr-xindra/llcommon/llmortician.h1
-rw-r--r--indra/llcommon/llmutex.cpp179
-rw-r--r--indra/llcommon/llmutex.h101
-rwxr-xr-xindra/llcommon/llpointer.h72
-rw-r--r--[-rwxr-xr-x]indra/llcommon/llpredicate.cpp (renamed from indra/llcommon/lllazy.cpp)37
-rw-r--r--indra/llcommon/llpredicate.h210
-rwxr-xr-xindra/llcommon/llprocess.h4
-rwxr-xr-xindra/llcommon/llprocessor.cpp6
-rwxr-xr-xindra/llcommon/llprocessor.h4
-rwxr-xr-xindra/llcommon/llptrskiplist.h724
-rwxr-xr-xindra/llcommon/llptrskipmap.h1239
-rwxr-xr-xindra/llcommon/llqueuedthread.cpp15
-rwxr-xr-xindra/llcommon/llregistry.h12
-rwxr-xr-xindra/llcommon/llsdparam.cpp12
-rwxr-xr-xindra/llcommon/llsdparam.h20
-rwxr-xr-xindra/llcommon/llsingleton.cpp1
-rwxr-xr-xindra/llcommon/llsingleton.h153
-rwxr-xr-xindra/llcommon/llskiplist.h517
-rwxr-xr-xindra/llcommon/llskipmap.h1022
-rwxr-xr-xindra/llcommon/llsortedvector.h152
-rwxr-xr-xindra/llcommon/llstack.h48
-rwxr-xr-xindra/llcommon/llstacktrace.cpp2
-rwxr-xr-xindra/llcommon/llstat.cpp404
-rwxr-xr-xindra/llcommon/llstat.h116
-rwxr-xr-xindra/llcommon/llstatenums.h2
-rwxr-xr-xindra/llcommon/llstl.h1
-rwxr-xr-xindra/llcommon/llstring.cpp5
-rwxr-xr-xindra/llcommon/llstring.h3
-rwxr-xr-xindra/llcommon/llsys.cpp5
-rwxr-xr-xindra/llcommon/llthread.cpp176
-rwxr-xr-xindra/llcommon/llthread.h91
-rw-r--r--indra/llcommon/llthreadlocalstorage.cpp117
-rw-r--r--indra/llcommon/llthreadlocalstorage.h357
-rwxr-xr-xindra/llcommon/lltimer.cpp20
-rwxr-xr-xindra/llcommon/lltimer.h21
-rw-r--r--indra/llcommon/lltrace.cpp115
-rw-r--r--indra/llcommon/lltrace.h1083
-rw-r--r--indra/llcommon/lltracerecording.cpp944
-rw-r--r--indra/llcommon/lltracerecording.h527
-rw-r--r--indra/llcommon/lltracethreadrecorder.cpp291
-rw-r--r--indra/llcommon/lltracethreadrecorder.h126
-rwxr-xr-xindra/llcommon/lltypeinfolookup.h117
-rw-r--r--indra/llcommon/llunit.h481
-rwxr-xr-xindra/llcommon/lluuid.cpp4
-rwxr-xr-xindra/llcommon/lluuidhashmap.h583
-rw-r--r--[-rwxr-xr-x]indra/llcommon/llwin32headers.h (renamed from indra/llcommon/reflective.cpp)32
-rw-r--r--[-rwxr-xr-x]indra/llcommon/llwin32headerslean.h (renamed from indra/llcommon/lldarrayptr.h)24
-rwxr-xr-xindra/llcommon/llworkerthread.h5
-rwxr-xr-xindra/llcommon/metaclass.cpp81
-rwxr-xr-xindra/llcommon/metaclass.h82
-rwxr-xr-xindra/llcommon/metaclasst.h60
-rwxr-xr-xindra/llcommon/metaproperty.cpp56
-rwxr-xr-xindra/llcommon/metaproperty.h73
-rwxr-xr-xindra/llcommon/metapropertyt.h183
-rwxr-xr-xindra/llcommon/reflective.h42
-rwxr-xr-xindra/llcommon/reflectivet.h48
-rw-r--r--indra/llcommon/tests/llunits_test.cpp208
-rwxr-xr-xindra/llcommon/tests/reflection_test.cpp220
92 files changed, 5924 insertions, 10870 deletions
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt
index 3a4a8facc2..bf99a4c3a0 100755
--- a/indra/llcommon/CMakeLists.txt
+++ b/indra/llcommon/CMakeLists.txt
@@ -75,8 +75,10 @@ set(llcommon_SOURCE_FILES
llmetrics.cpp
llmetricperformancetester.cpp
llmortician.cpp
+ llmutex.cpp
lloptioninterface.cpp
llptrto.cpp
+ llpredicate.cpp
llprocess.cpp
llprocessor.cpp
llqueuedthread.cpp
@@ -90,7 +92,6 @@ set(llcommon_SOURCE_FILES
llsdutil.cpp
llsecondlifeurls.cpp
llsingleton.cpp
- llstat.cpp
llstacktrace.cpp
llstreamqueue.cpp
llstreamtools.cpp
@@ -98,14 +99,15 @@ set(llcommon_SOURCE_FILES
llstringtable.cpp
llsys.cpp
llthread.cpp
+ llthreadlocalstorage.cpp
llthreadsafequeue.cpp
lltimer.cpp
+ lltrace.cpp
+ lltracerecording.cpp
+ lltracethreadrecorder.cpp
lluri.cpp
lluuid.cpp
llworkerthread.cpp
- metaclass.cpp
- metaproperty.cpp
- reflective.cpp
timing.cpp
u64.cpp
)
@@ -115,7 +117,6 @@ set(llcommon_HEADER_FILES
bitpack.h
ctype_workaround.h
- doublelinkedlist.h
fix_macros.h
imageids.h
indra_constants.h
@@ -129,7 +130,6 @@ set(llcommon_HEADER_FILES
llapp.h
llapr.h
llassettype.h
- llassoclist.h
llavatarconstants.h
llbase32.h
llbase64.h
@@ -143,18 +143,14 @@ set(llcommon_HEADER_FILES
llcriticaldamp.h
llcursortypes.h
lldarray.h
- lldarrayptr.h
lldate.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
@@ -178,18 +174,15 @@ set(llcommon_HEADER_FILES
llhash.h
llheartbeat.h
llhttpstatuscodes.h
- llindexedqueue.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
@@ -199,15 +192,15 @@ set(llcommon_HEADER_FILES
llmetrics.h
llmetricperformancetester.h
llmortician.h
+ llmutex.h
llnametable.h
lloptioninterface.h
llpointer.h
+ llpredicate.h
llpreprocessor.h
llpriqueuemap.h
llprocess.h
llprocessor.h
- llptrskiplist.h
- llptrskipmap.h
llptrto.h
llqueuedthread.h
llrand.h
@@ -224,12 +217,7 @@ set(llcommon_HEADER_FILES
llsecondlifeurls.h
llsimplehash.h
llsingleton.h
- llskiplist.h
- llskipmap.h
- llsortedvector.h
- llstack.h
llstacktrace.h
- llstat.h
llstatenums.h
llstl.h
llstreamqueue.h
@@ -239,22 +227,21 @@ set(llcommon_HEADER_FILES
llstringtable.h
llsys.h
llthread.h
+ llthreadlocalstorage.h
llthreadsafequeue.h
lltimer.h
+ lltrace.h
+ lltracerecording.h
+ lltracethreadrecorder.h
lltreeiterators.h
- lltypeinfolookup.h
+ llunit.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
@@ -326,7 +313,6 @@ 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(llrand "" "${test_libs}")
LL_ADD_INTEGRATION_TEST(llsdserialize "" "${test_libs}")
@@ -334,7 +320,7 @@ if (LL_TESTS)
LL_ADD_INTEGRATION_TEST(llstring "" "${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}")
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/llapr.cpp b/indra/llcommon/llapr.cpp
index d1c44c9403..47fa70614f 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
@@ -52,13 +56,23 @@ void ll_init_apr()
if(!LLAPRFile::sAPRFilePoolp)
{
- LLAPRFile::sAPRFilePoolp = new LLVolatileAPRPool(FALSE) ;
+ 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);
@@ -84,7 +101,7 @@ void ll_cleanup_apr()
}
if (LLAPRFile::sAPRFilePoolp)
{
- delete LLAPRFile::sAPRFilePoolp ;
+ delete LLAPRFile::sAPRFilePoolp ;
LLAPRFile::sAPRFilePoolp = NULL ;
}
apr_terminate();
diff --git a/indra/llcommon/llapr.h b/indra/llcommon/llapr.h
index 752574c65d..e9b13c5919 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.
@@ -163,14 +172,17 @@ public:
LLAtomic32<Type>(Type x) {apr_atomic_set32(&mData, apr_uint32_t(x)); };
~LLAtomic32<Type>() {};
- operator const Type() { apr_uint32_t data = apr_atomic_read32(&mData); return Type(data); }
+ operator const Type() { return get(); }
Type operator =(const Type& x) { apr_atomic_set32(&mData, apr_uint32_t(x)); return Type(mData); }
void operator -=(Type x) { apr_atomic_sub32(&mData, apr_uint32_t(x)); }
void operator +=(Type x) { apr_atomic_add32(&mData, apr_uint32_t(x)); }
Type operator ++(int) { return apr_atomic_inc32(&mData); } // Type++
- Type operator --(int) { return apr_atomic_dec32(&mData); } // approximately --Type (0 if final is 0, non-zero otherwise)
+ Type operator ++() { apr_atomic_inc32(&mData); return get(); } // ++Type
+ Type operator --(int) { const Type result(get()); apr_atomic_dec32(&mData); return result; } // Type--
+ Type operator --() { return apr_atomic_dec32(&mData); } // approximately --Type (0 if final is 0, non-zero otherwise)
private:
+ const Type get() { apr_uint32_t data = apr_atomic_read32(&mData); return Type(data); }
apr_uint32_t mData;
};
@@ -257,18 +269,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/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/llcommon.cpp b/indra/llcommon/llcommon.cpp
index 8be9e4f4de..c720df7555 100755
--- a/indra/llcommon/llcommon.cpp
+++ b/indra/llcommon/llcommon.cpp
@@ -29,6 +29,7 @@
#include "llmemory.h"
#include "llthread.h"
+#include "lltrace.h"
//static
BOOL LLCommon::sAprInitialized = FALSE;
@@ -44,15 +45,13 @@ void LLCommon::initClass()
}
LLTimer::initClass();
LLThreadSafeRefCount::initThreadSafeRefCount();
-// LLWorkerThread::initClass();
-// LLFrameCallbackManager::initClass();
+ LLTrace::init();
}
//static
void LLCommon::cleanupClass()
{
-// LLFrameCallbackManager::cleanupClass();
-// LLWorkerThread::cleanupClass();
+ LLTrace::cleanup();
LLThreadSafeRefCount::cleanupThreadSafeRefCount();
LLTimer::cleanupClass();
if (sAprInitialized)
diff --git a/indra/llcommon/llcriticaldamp.cpp b/indra/llcommon/llcriticaldamp.cpp
index 87d79b1ee0..2f013fe255 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,43 +67,54 @@ 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(LLUnit<LLUnits::Seconds, F32> 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..ab5d4ba6e2 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 "llunit.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(LLUnit<LLUnits::Seconds, F32> time_constant, bool use_cache = true);
-protected:
+ template<typename T>
+ static T lerp(T a, T b, LLUnit<LLUnits::Seconds, F32> 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/lldate.cpp b/indra/llcommon/lldate.cpp
index 030ef6a3c7..2efe39e158 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,18 +49,15 @@ 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(LLUnit<LLUnits::Seconds, F64> seconds_since_epoch) :
+ mSecondsSinceEpoch(seconds_since_epoch.value())
+{}
LLDate::LLDate(const std::string& iso8601_date)
{
diff --git a/indra/llcommon/lldate.h b/indra/llcommon/lldate.h
index 7ff8b550ad..b62a846147 100755
--- a/indra/llcommon/lldate.h
+++ b/indra/llcommon/lldate.h
@@ -33,6 +33,7 @@
#include <string>
#include "stdtypes.h"
+#include "llunit.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(LLUnit<LLUnits::Seconds, F64> seconds_since_epoch);
/**
* @brief Construct a date from a string representation
diff --git a/indra/llcommon/lldefs.h b/indra/llcommon/lldefs.h
index 5a4b8325f4..d57b9dccff 100755
--- a/indra/llcommon/lldefs.h
+++ b/indra/llcommon/lldefs.h
@@ -244,5 +244,8 @@ inline void llswap(LLDATATYPE& lhs, LLDATATYPE& rhs)
rhs = tmp;
}
+#define LL_GLUE_IMPL(x, y) x##y
+#define LL_GLUE_TOKENS(x, y) LL_GLUE_IMPL(x, y)
+
#endif // LL_LLDEFS_H
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..ac435a30fa 100755
--- a/indra/llcommon/lldepthstack.h
+++ b/indra/llcommon/lldepthstack.h
@@ -27,17 +27,20 @@
#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()
+ : mCurrentDepth(0), mMaxDepth(0)
+ {}
+
~LLDepthStack() {}
void setDepth(U32 depth)
@@ -54,24 +57,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 +85,20 @@ public:
DATA_TYPE *check()
{
- DATA_TYPE *tempp = mStack.getFirstData();
- return tempp;
+ return mStack.empty() ? NULL : mStack.back();
}
void deleteAllData()
{
mCurrentDepth = 0;
- mStack.deleteAllData();
+ std::for_each(mStack.begin(), mStack.end(), DeletePointer());
+ mStack.clear();
}
void removeAllNodes()
{
mCurrentDepth = 0;
- mStack.removeAllNodes();
+ mStack.clear();
}
};
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/llerrorlegacy.h b/indra/llcommon/llerrorlegacy.h
index 37cee579cd..097a533b1a 100755
--- a/indra/llcommon/llerrorlegacy.h
+++ b/indra/llcommon/llerrorlegacy.h
@@ -29,6 +29,7 @@
#define LL_LLERRORLEGACY_H
#include "llpreprocessor.h"
+#include <boost/static_assert.hpp>
/*
LEGACY -- DO NOT USE THIS STUFF ANYMORE
@@ -111,6 +112,14 @@ const int LL_ERR_PRICE_MISMATCH = -23018;
#define llverify(func) do {if (func) {}} while(0)
#endif
+#ifdef LL_WINDOWS
+#define llstatic_assert(func, msg) static_assert(func, msg)
+#define llstatic_assert_template(type, func, msg) static_assert(func, msg)
+#else
+#define llstatic_assert(func, msg) BOOST_STATIC_ASSERT(func)
+#define llstatic_assert_template(type, func, msg) BOOST_STATIC_ASSERT(sizeof(type) != 0 && func);
+#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
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/llfasttimer.cpp b/indra/llcommon/llfasttimer.cpp
index 9b15804e97..dfc72bd2ce 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 "llunit.h"
+#include "llsd.h"
+#include "lltracerecording.h"
+#include "lltracethreadrecorder.h"
#include <boost/bind.hpp>
+#include <queue>
#if LL_WINDOWS
@@ -49,37 +54,36 @@
#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 TimeBlock::sLog = false;
+std::string TimeBlock::sLogName = "";
+bool TimeBlock::sMetricLog = false;
#if LL_LINUX || LL_SOLARIS
-U64 LLFastTimer::sClockResolution = 1000000000; // Nanosecond resolution
+U64 TimeBlock::sClockResolution = 1000000000; // Nanosecond resolution
#else
-U64 LLFastTimer::sClockResolution = 1000000; // Microsecond resolution
+U64 TimeBlock::sClockResolution = 1000000; // Microsecond resolution
#endif
+static LLMutex* sLogLock = NULL;
+static std::queue<LLSD> sLogQueue;
+
+
// 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;
+typedef LLTreeDFSPostIter<TimeBlock, TimeBlock::child_const_iter> timer_tree_bottom_up_iterator_t;
-static timer_tree_bottom_up_iterator_t begin_timer_tree_bottom_up(LLFastTimer::NamedTimer& id)
+static timer_tree_bottom_up_iterator_t begin_timer_tree_bottom_up(TimeBlock& 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));
+ boost::bind(boost::mem_fn(&TimeBlock::beginChildren), _1),
+ boost::bind(boost::mem_fn(&TimeBlock::endChildren), _1));
}
static timer_tree_bottom_up_iterator_t end_timer_tree_bottom_up()
@@ -87,14 +91,14 @@ static timer_tree_bottom_up_iterator_t end_timer_tree_bottom_up()
return timer_tree_bottom_up_iterator_t();
}
-typedef LLTreeDFSIter<LLFastTimer::NamedTimer, LLFastTimer::NamedTimer::child_const_iter> timer_tree_dfs_iterator_t;
+typedef LLTreeDFSIter<TimeBlock, TimeBlock::child_const_iter> timer_tree_dfs_iterator_t;
-static timer_tree_dfs_iterator_t begin_timer_tree(LLFastTimer::NamedTimer& id)
+static timer_tree_dfs_iterator_t begin_timer_tree(TimeBlock& id)
{
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));
+ boost::bind(boost::mem_fn(&TimeBlock::beginChildren), _1),
+ boost::bind(boost::mem_fn(&TimeBlock::endChildren), _1));
}
static timer_tree_dfs_iterator_t end_timer_tree()
@@ -102,90 +106,48 @@ static timer_tree_dfs_iterator_t end_timer_tree()
return timer_tree_dfs_iterator_t();
}
-// factory class that creates NamedTimers via static DeclareTimer objects
-class NamedTimerFactory : public LLSingleton<NamedTimerFactory>
-{
-public:
- NamedTimerFactory()
- : mTimerRoot(NULL)
- {}
- /*virtual */ void initSingleton()
+// sort child timers by name
+struct SortTimerByName
+{
+ bool operator()(const TimeBlock* i1, const TimeBlock* i2)
{
- mTimerRoot = new LLFastTimer::NamedTimer("root");
- mRootFrameState.setNamedTimer(mTimerRoot);
- mTimerRoot->setFrameState(&mRootFrameState);
- mTimerRoot->mParent = mTimerRoot;
- mTimerRoot->setCollapsed(false);
- mRootFrameState.mParent = &mRootFrameState;
+ return i1->getName() < i2->getName();
}
+};
- ~NamedTimerFactory()
+TimeBlock& TimeBlock::getRootTimeBlock()
{
- std::for_each(mTimers.begin(), mTimers.end(), DeletePairedPointer());
-
- delete mTimerRoot;
+ static TimeBlock root_timer("root", true, NULL);
+ return root_timer;
}
- LLFastTimer::NamedTimer& createNamedTimer(const std::string& name, LLFastTimer::FrameState* state)
+void TimeBlock::pushLog(LLSD log)
{
- LLFastTimer::NamedTimer* timer = new LLFastTimer::NamedTimer(name);
- timer->setFrameState(state);
- timer->setParent(mTimerRoot);
- mTimers.insert(std::make_pair(name, timer));
+ LLMutexLock lock(sLogLock);
- return *timer;
+ sLogQueue.push(log);
}
- LLFastTimer::NamedTimer* getTimerByName(const std::string& name)
- {
- timer_map_t::iterator found_it = mTimers.find(name);
- if (found_it != mTimers.end())
- {
- return found_it->second;
- }
- 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))
+void TimeBlock::setLogLock(LLMutex* lock)
{
- mTimer.setCollapsed(!open);
+ sLogLock = lock;
}
-LLFastTimer::DeclareTimer::DeclareTimer(const std::string& name)
-: mTimer(NamedTimerFactory::instance().createNamedTimer(name, &mFrameState))
-{
-}
//static
#if (LL_DARWIN || LL_LINUX || LL_SOLARIS) && !(defined(__i386__) || defined(__amd64__))
-U64 LLFastTimer::countsPerSecond() // counts per second for the *32-bit* timer
+U64 TimeBlock::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 TimeBlock::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);
+ static LLUnit<LLUnits::Hertz, U64> sCPUClockFrequency = LLProcessorInfo().getCPUFrequency();
- // we drop the low-order byte in our timers, so report a lower frequency
#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())
@@ -198,269 +160,189 @@ U64 LLFastTimer::countsPerSecond() // counts per second for the *32-bit* timer
firstcall = false;
}
#endif
- return sCPUClockFrequency >> 8;
+ return sCPUClockFrequency.value();
}
#endif
-LLFastTimer::FrameState::FrameState()
-: mActiveCount(0),
- mCalls(0),
- mSelfTimeCounter(0),
- mParent(NULL),
- mLastCaller(NULL),
- mMoveUpTree(false)
-{}
-
-
-LLFastTimer::NamedTimer::NamedTimer(const std::string& name)
-: mName(name),
- mCollapsed(true),
- mParent(NULL),
- mTotalTimeCounter(0),
- mCountAverage(0),
- mCallAverage(0),
- mNeedsSorting(false),
- mFrameState(NULL)
-{
- mCountHistory = new U32[HISTORY_NUM];
- memset(mCountHistory, 0, sizeof(U32) * HISTORY_NUM);
- mCallHistory = new U32[HISTORY_NUM];
- memset(mCallHistory, 0, sizeof(U32) * HISTORY_NUM);
-}
-
-LLFastTimer::NamedTimer::~NamedTimer()
-{
- delete[] mCountHistory;
- delete[] mCallHistory;
-}
-
-std::string LLFastTimer::NamedTimer::getToolTip(S32 history_idx)
-{
- 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
- {
- return llformat("%s (%d ms, %d calls)", getName().c_str(), (S32)(getHistoricalCount(history_idx) * ms_multiplier), (S32)getHistoricalCalls(history_idx));
- }
-}
-
-void LLFastTimer::NamedTimer::setParent(NamedTimer* parent)
-{
- llassert_always(parent != this);
- llassert_always(parent != NULL);
-
- if (mParent)
- {
- // 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);
- }
- }
-
- mParent = parent;
- if (parent)
- {
- getFrameState().mParent = &parent->getFrameState();
- parent->getChildren().push_back(this);
- parent->mNeedsSorting = true;
- }
-}
-
-S32 LLFastTimer::NamedTimer::getDepth()
+TimeBlock::TimeBlock(const char* name, bool open, TimeBlock* parent)
+: TraceType<TimeBlockAccumulator>(name),
+ mCollapsed(true)
{
- S32 depth = 0;
- NamedTimer* timerp = mParent;
- while(timerp)
- {
- depth++;
- if (timerp->getParent() == timerp) break;
- timerp = timerp->mParent;
- }
- return depth;
+ setCollapsed(!open);
}
-// static
-void LLFastTimer::NamedTimer::processTimes()
+TimeBlockTreeNode& TimeBlock::getTreeNode() const
{
- if (sCurFrameIndex < 0) return;
-
- buildHierarchy();
- accumulateTimings();
+ TimeBlockTreeNode* nodep = LLTrace::get_thread_recorder()->getTimeBlockTreeNode(getIndex());
+ llassert(nodep);
+ return *nodep;
}
-// sort child timers by name
-struct SortTimerByName
-{
- bool operator()(const LLFastTimer::NamedTimer* i1, const LLFastTimer::NamedTimer* i2)
- {
- return i1->getName() < i2->getName();
- }
-};
+static LLFastTimer::DeclareTimer FTM_PROCESS_TIMES("Process FastTimer Times");
+// not thread safe, so only call on main thread
//static
-void LLFastTimer::NamedTimer::buildHierarchy()
+void TimeBlock::processTimes()
{
- if (sCurFrameIndex < 0 ) return;
+ LLFastTimer _(FTM_PROCESS_TIMES);
+ get_clock_count(); // good place to calculate clock frequency
+ U64 cur_time = getCPUClockCount64();
// set up initial tree
+ for (LLInstanceTracker<TimeBlock>::instance_iter begin_it = LLInstanceTracker<TimeBlock>::beginInstances(), end_it = LLInstanceTracker<TimeBlock>::endInstances(), it = begin_it;
+ it != end_it;
+ ++it)
{
- for (instance_iter it = beginInstances(); it != endInstances(); ++it)
+ TimeBlock& timer = *it;
+ if (&timer == &TimeBlock::getRootTimeBlock()) continue;
+
+ // bootstrap tree construction by attaching to last timer to be on stack
+ // when this timer was called
+ if (timer.getParent() == &TimeBlock::getRootTimeBlock())
{
- NamedTimer& timer = *it;
- if (&timer == NamedTimerFactory::instance().getRootTimer()) continue;
+ TimeBlockAccumulator* accumulator = timer.getPrimaryAccumulator();
- // 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())
+ if (accumulator->mLastCaller)
{
- timer.setParent(timer.getFrameState().mLastCaller->mTimer);
- // no need to push up tree on first use, flag can be set spuriously
- timer.getFrameState().mMoveUpTree = false;
+ 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;
}
}
- // bump timers up tree if they've been flagged as being in the wrong place
+ // 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
- for(timer_tree_bottom_up_iterator_t it = begin_timer_tree_bottom_up(*NamedTimerFactory::instance().getRootTimer());
+ for(timer_tree_bottom_up_iterator_t it = begin_timer_tree_bottom_up(TimeBlock::getRootTimeBlock());
it != end_timer_tree_bottom_up();
++it)
{
- NamedTimer* timerp = *it;
- // skip root timer
- if (timerp == NamedTimerFactory::instance().getRootTimer()) continue;
+ TimeBlock* timerp = *it;
- if (timerp->getFrameState().mMoveUpTree)
+ // sort timers by time last called, so call graph makes sense
+ TimeBlockTreeNode& tree_node = timerp->getTreeNode();
+ if (tree_node.mNeedsSorting)
{
- // since ancestors have already been visited, reparenting 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;
-
- // don't bubble up any ancestors until descendants are done bubbling up
- it.skipAncestors();
+ std::sort(tree_node.mChildren.begin(), tree_node.mChildren.end(), SortTimerByName());
}
- }
- // 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)
- {
- NamedTimer* timerp = (*it);
- if (timerp->mNeedsSorting)
+ // skip root timer
+ if (timerp != &TimeBlock::getRootTimeBlock())
{
- std::sort(timerp->getChildren().begin(), timerp->getChildren().end(), SortTimerByName());
+ TimeBlockAccumulator* accumulator = timerp->getPrimaryAccumulator();
+
+ if (accumulator->mMoveUpTree)
+ {
+ // 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());
+ 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();
+ }
}
- timerp->mNeedsSorting = false;
}
-}
-
-//static
-void LLFastTimer::NamedTimer::accumulateTimings()
-{
- U32 cur_time = getCPUClockCount32();
// 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)
+ BlockTimerStackRecord* stack_record = ThreadTimerStack::getInstance();
+ BlockTimer* cur_timer = stack_record->mActiveTimer;
+ TimeBlockAccumulator* accumulator = stack_record->mTimeBlock->getPrimaryAccumulator();
+
+ while(cur_timer
+ && cur_timer->mParentTimerData.mActiveTimer != cur_timer) // root defined by parent pointing to self
{
- 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;
+ U64 cumulative_time_delta = cur_time - cur_timer->mStartTime;
+ accumulator->mTotalTimeCounter += cumulative_time_delta - (accumulator->mTotalTimeCounter - cur_timer->mBlockStartTotalTimeCounter);
+ accumulator->mSelfTimeCounter += cumulative_time_delta - stack_record->mChildTime;
+ stack_record->mChildTime = 0;
+
cur_timer->mStartTime = cur_time;
+ cur_timer->mBlockStartTotalTimeCounter = accumulator->mTotalTimeCounter;
- cur_data = &cur_timer->mLastTimerData;
- cur_data->mChildTime += cumulative_time_delta;
+ stack_record = &cur_timer->mParentTimerData;
+ accumulator = stack_record->mTimeBlock->getPrimaryAccumulator();
+ cur_timer = stack_record->mActiveTimer;
- cur_timer = cur_timer->mLastTimerData.mCurTimer;
+ stack_record->mChildTime += cumulative_time_delta;
}
- // 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 (LLInstanceTracker<TimeBlock>::instance_iter it = LLInstanceTracker<TimeBlock>::beginInstances(),
+ end_it = LLInstanceTracker<TimeBlock>::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)
+ TimeBlock& timer = *it;
+ TimeBlockAccumulator* accumulator = timer.getPrimaryAccumulator();
+
+ accumulator->mLastCaller = NULL;
+ accumulator->mMoveUpTree = false;
+ }
+}
+
+
+std::vector<TimeBlock*>::iterator TimeBlock::beginChildren()
{
- timerp->mTotalTimeCounter += (*child_it)->mTotalTimeCounter;
+ return getTreeNode().mChildren.begin();
}
- S32 cur_frame = sCurFrameIndex;
- if (cur_frame >= 0)
+std::vector<TimeBlock*>::iterator TimeBlock::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<TimeBlock*>& TimeBlock::getChildren()
+{
+ return getTreeNode().mChildren;
}
// static
-void LLFastTimer::NamedTimer::resetFrame()
+void TimeBlock::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()) / (LLUnit<LLUnits::Hertz, F64>(LLProcessorInfo().getCPUFrequency())) << LL_ENDL;
}
call_count++;
- F64 iclock_freq = 1000.0 / countsPerSecond(); // good place to calculate clock frequency
-
- F64 total_time = 0;
+ LLUnit<LLUnits::Seconds, F64> total_time(0);
LLSD sd;
{
- for (instance_iter it = beginInstances(); it != endInstances(); ++it)
+ for (LLInstanceTracker<TimeBlock>::instance_iter it = LLInstanceTracker<TimeBlock>::beginInstances(),
+ end_it = LLInstanceTracker<TimeBlock>::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;
+ TimeBlock& timer = *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;
{
@@ -469,168 +351,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
+void TimeBlock::dumpCurTimes()
{
- 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()
-{
- // 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(timer_tree_dfs_iterator_t it = begin_timer_tree(TimeBlock::getRootTimeBlock());
it != end_timer_tree();
++it)
{
- NamedTimer* timerp = (*it);
- F64 total_time_ms = ((F64)timerp->getHistoricalCount(0) * iclock_freq);
+ TimeBlock* timerp = (*it);
+ LLUnit<LLUnits::Seconds, F64> total_time_ms = 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;
std::ostringstream out_str;
- for (S32 i = 0; i < timerp->getDepth(); i++)
+ TimeBlock* 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_ms.as<LLUnits::Milliseconds>().value() << " ms, "
+ << num_calls << " calls";
llinfos << out_str.str() << llendl;
}
}
//static
-void LLFastTimer::reset()
-{
- NamedTimer::reset();
-}
-
-
-//static
-void LLFastTimer::writeLog(std::ostream& os)
+void TimeBlock::writeLog(std::ostream& os)
{
while (!sLogQueue.empty())
{
@@ -641,22 +399,62 @@ void LLFastTimer::writeLog(std::ostream& os)
}
}
-//static
-const LLFastTimer::NamedTimer* LLFastTimer::getTimerByName(const std::string& name)
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+// TimeBlockAccumulator
+//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+TimeBlockAccumulator::TimeBlockAccumulator()
+: mTotalTimeCounter(0),
+ mSelfTimeCounter(0),
+ mStartTotalTimeCounter(0),
+ mCalls(0),
+ mLastCaller(NULL),
+ mActiveCount(0),
+ mMoveUpTree(false),
+ mParent(NULL)
+{}
+
+void TimeBlockAccumulator::addSamples( const TimeBlockAccumulator& other, bool append )
{
- return NamedTimerFactory::instance().getTimerByName(name);
+ // 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);
+ mTotalTimeCounter += other.mTotalTimeCounter - other.mStartTotalTimeCounter;
+ mSelfTimeCounter += other.mSelfTimeCounter;
+ mCalls += other.mCalls;
+ mLastCaller = other.mLastCaller;
+ mActiveCount = other.mActiveCount;
+ mMoveUpTree = other.mMoveUpTree;
+ mParent = other.mParent;
}
-LLFastTimer::LLFastTimer(LLFastTimer::FrameState* state)
-: mFrameState(state)
+void TimeBlockAccumulator::reset( const TimeBlockAccumulator* 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;
+ mCalls = 0;
+ mSelfTimeCounter = 0;
+
+ if (other)
+ {
+ mStartTotalTimeCounter = other->mTotalTimeCounter;
+ mTotalTimeCounter = mStartTotalTimeCounter;
+
+ mLastCaller = other->mLastCaller;
+ mActiveCount = other->mActiveCount;
+ mMoveUpTree = other->mMoveUpTree;
+ mParent = other->mParent;
+ }
+ else
+{
+ mStartTotalTimeCounter = mTotalTimeCounter;
+ }
+}
+
+LLUnit<LLUnits::Seconds, F64> BlockTimer::getElapsedTime()
+{
+ U64 total_time = TimeBlock::getCPUClockCount64() - mStartTime;
+
+ return (F64)total_time / (F64)TimeBlock::countsPerSecond();
}
+} // namespace LLTrace
diff --git a/indra/llcommon/llfasttimer.h b/indra/llcommon/llfasttimer.h
index 81c4b78775..20514d1638 100755
--- a/indra/llcommon/llfasttimer.h
+++ b/indra/llcommon/llfasttimer.h
@@ -28,216 +28,98 @@
#define LL_FASTTIMER_H
#include "llinstancetracker.h"
+#include "lltrace.h"
#define FAST_TIMER_ON 1
-#define DEBUG_FAST_TIMER_THREADS 1
+#define LL_FASTTIMER_USE_RDTSC 1
class LLMutex;
-#include <queue>
-#include "llsd.h"
-
-#define LL_FASTTIMER_USE_RDTSC 1
-
+namespace LLTrace
+{
-LL_COMMON_API void assert_main_thread();
+struct BlockTimerStackRecord
+{
+ class BlockTimer* mActiveTimer;
+ class TimeBlock* mTimeBlock;
+ U64 mChildTime;
+};
-class LL_COMMON_API LLFastTimer
+class ThreadTimerStack
+: public BlockTimerStackRecord,
+ public LLThreadLocalSingleton<ThreadTimerStack>
{
-public:
- class NamedTimer;
+ friend class LLThreadLocalSingleton<ThreadTimerStack>;
+ ThreadTimerStack()
+ {}
- 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>
+public:
+ ThreadTimerStack& operator=(const BlockTimerStackRecord& other)
{
- 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;
+ BlockTimerStackRecord::operator=(other);
+ return *this;
+ }
+};
- std::string mName;
+class BlockTimer
+{
+public:
+ friend class TimeBlock;
+ typedef BlockTimer self_t;
+ typedef class TimeBlock DeclareTimer;
- U32 mTotalTimeCounter;
+ BlockTimer(TimeBlock& timer);
+ ~BlockTimer();
- U32 mCountAverage;
- U32 mCallAverage;
+ LLUnit<LLUnits::Seconds, F64> getElapsedTime();
- U32* mCountHistory;
- U32* mCallHistory;
+private:
- // 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
- };
+ U64 mStartTime;
+ U64 mBlockStartTotalTimeCounter;
+ BlockTimerStackRecord mParentTimerData;
+};
- // 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);
+// stores a "named" timer instance to be reused via multiple BlockTimer stack instances
+class TimeBlock
+: public TraceType<TimeBlockAccumulator>,
+ public LLInstanceTracker<TimeBlock>
+{
+public:
+ TimeBlock(const char* name, bool open = false, TimeBlock* parent = &getRootTimeBlock());
- NamedTimer& getNamedTimer() { return mTimer; }
+ TimeBlockTreeNode& getTreeNode() const;
+ TimeBlock* getParent() const { return getTreeNode().getParent(); }
+ void setParent(TimeBlock* parent) { getTreeNode().setParent(parent); }
- private:
- FrameState mFrameState;
- NamedTimer& mTimer;
- };
+ typedef std::vector<TimeBlock*>::iterator child_iter;
+ typedef std::vector<TimeBlock*>::const_iterator child_const_iter;
+ child_iter beginChildren();
+ child_iter endChildren();
+ std::vector<TimeBlock*>& getChildren();
-public:
- LLFastTimer(LLFastTimer::FrameState* state);
+ void setCollapsed(bool collapsed) { mCollapsed = collapsed; }
+ bool getCollapsed() const { return mCollapsed; }
- LL_FORCE_INLINE LLFastTimer(LLFastTimer::DeclareTimer& timer)
- : mFrameState(&timer.mFrameState)
+ TraceType<TimeBlockAccumulator::CallCountFacet>& callCount()
{
-#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
+ return static_cast<TraceType<TimeBlockAccumulator::CallCountFacet>&>(*(TraceType<TimeBlockAccumulator>*)this);
}
- LL_FORCE_INLINE ~LLFastTimer()
+ TraceType<TimeBlockAccumulator::SelfTimeFacet>& selfTime()
{
-#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
+ return static_cast<TraceType<TimeBlockAccumulator::SelfTimeFacet>&>(*(TraceType<TimeBlockAccumulator>*)this);
}
-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();
+ static TimeBlock& getRootTimeBlock();
+ static void pushLog(LLSD sd);
+ static void setLogLock(LLMutex* mutex);
+ static void writeLog(std::ostream& os);
// dumps current cumulative frame stats to log
// call nextFrame() to reset timers
static void dumpCurTimes();
- // call this to reset timer hierarchy, averages, etc.
- static void reset();
-
- static U64 countsPerSecond();
- static S32 getLastFrameIndex() { return sLastFrameIndex; }
- static S32 getCurFrameIndex() { return sCurFrameIndex; }
-
- static void writeLog(std::ostream& os);
- static const NamedTimer* getTimerByName(const std::string& name);
-
- struct CurTimerData
- {
- LLFastTimer* mCurTimer;
- FrameState* mFrameState;
- U32 mChildTime;
- };
- static CurTimerData sCurTimerData;
-
-private:
-
-
//////////////////////////////////////////////////////////////////////////////
//
// Important note: These implementations must be FAST!
@@ -260,14 +142,14 @@ private:
//#undef _interlockedbittestandset
//#undef _interlockedbittestandreset
- //inline U32 LLFastTimer::getCPUClockCount32()
+ //inline U32 TimeBlock::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 TimeBlock::getCPUClockCount64()
//{
// return __rdtsc();
//}
@@ -307,7 +189,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()
{
@@ -374,18 +256,71 @@ private:
#endif
- static U64 sClockResolution;
+ static U64 countsPerSecond();
- static S32 sCurFrameIndex;
- static S32 sLastFrameIndex;
- static U64 sLastFrameTime;
+ // updates cumulative times and hierarchy,
+ // can be called multiple times in a frame, at any point
+ static void processTimes();
- U32 mStartTime;
- LLFastTimer::FrameState* mFrameState;
- LLFastTimer::CurTimerData mLastTimerData;
+ // call this once a frame to periodically log timers
+ static void logStats();
+ bool mCollapsed; // don't show children
+
+ // statics
+ static std::string sLogName;
+ static bool sMetricLog,
+ sLog;
+ static U64 sClockResolution;
};
-typedef class LLFastTimer LLFastTimer;
+LL_FORCE_INLINE BlockTimer::BlockTimer(TimeBlock& timer)
+{
+#if FAST_TIMER_ON
+ BlockTimerStackRecord* cur_timer_data = ThreadTimerStack::getIfExists();
+ TimeBlockAccumulator* accumulator = timer.getPrimaryAccumulator();
+ accumulator->mActiveCount++;
+ mBlockStartTotalTimeCounter = accumulator->mTotalTimeCounter;
+ // keep current parent as long as it is active when we are
+ accumulator->mMoveUpTree |= (accumulator->mParent->getPrimaryAccumulator()->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 = TimeBlock::getCPUClockCount64();
+#endif
+}
+
+LL_FORCE_INLINE BlockTimer::~BlockTimer()
+{
+#if FAST_TIMER_ON
+ U64 total_time = TimeBlock::getCPUClockCount64() - mStartTime;
+ BlockTimerStackRecord* cur_timer_data = ThreadTimerStack::getIfExists();
+ TimeBlockAccumulator* accumulator = cur_timer_data->mTimeBlock->getPrimaryAccumulator();
+
+ accumulator->mCalls++;
+ accumulator->mTotalTimeCounter += total_time - (accumulator->mTotalTimeCounter - mBlockStartTotalTimeCounter);
+ 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 864b6e6975..40a57c2ae4 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>
@@ -848,7 +848,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)
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/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/llinitparam.cpp b/indra/llcommon/llinitparam.cpp
index 89c831d296..dbd4eba7a0 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
//
@@ -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)
{
@@ -209,11 +219,18 @@ namespace LLInitParam
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
diff --git a/indra/llcommon/llinitparam.h b/indra/llcommon/llinitparam.h
index ae836645b9..a32557b4ac 100755
--- a/indra/llcommon/llinitparam.h
+++ b/indra/llcommon/llinitparam.h
@@ -29,14 +29,15 @@
#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"
namespace LLTypeTags
{
@@ -195,6 +196,8 @@ namespace LLInitParam
return mValue;
}
+ bool isValid() const { return true; }
+
protected:
T mValue;
};
@@ -209,13 +212,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 +233,6 @@ namespace LLInitParam
{
return *this;
}
-
- protected:
- mutable bool mValidated; // lazy validation flag
};
@@ -497,25 +495,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*)&param);
- }
-
- 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*)&param);
- }
+ }
else
- {
+ {
found_it = mParserReadFuncs->find(&typeid(S32));
if (found_it != mParserReadFuncs->end())
{
@@ -579,6 +577,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 +600,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 +628,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 +840,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 +879,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 +929,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 +1025,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 +1055,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 +1084,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 +1169,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 +1204,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 +1222,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 +1244,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 +1274,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 +1287,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 +1303,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 +1354,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 +1369,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 +1382,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 +1403,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 +1425,20 @@ 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;
+ if (!typed_param.isProvided()) return false;
+
+ 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,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;
+ if (!typed_param.isProvided()) return false;
+ 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 +1705,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 +1785,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 +1824,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 +2132,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 +2275,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 +2306,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 +2327,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 +2336,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 +2367,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 +2398,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 +2410,7 @@ namespace LLInitParam
if (deserialize_func
&& paramp
&& deserialize_func(*paramp, p, name_stack_range, new_name))
- {
+ {
++mCurParam;
return true;
}
@@ -2304,19 +2418,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 +2448,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 +2475,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 +2495,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 +2526,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 +2545,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 +2575,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 +2601,10 @@ namespace LLInitParam
return mValue.get().getValue();
}
- mutable bool mValidated; // lazy validation flag
+ bool isValid() const
+ {
+ return true;
+ }
private:
LazyValue<T> mValue;
@@ -2504,12 +2619,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 +2632,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 +2657,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 +2689,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 +2729,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 +2829,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 5dc3ea5d7b..7ff8324fe3 100755
--- a/indra/llcommon/llinstancetracker.cpp
+++ b/indra/llcommon/llinstancetracker.cpp
@@ -27,23 +27,25 @@
#include "linden_common.h"
// associated header
#include "llinstancetracker.h"
+#include "llapr.h"
+
// STL headers
// std headers
// external library headers
// other Linden headers
-//static
-void * & LLInstanceTrackerBase::getInstances(std::type_info const & info)
+void LLInstanceTrackerBase::StaticBase::incrementDepth()
+{
+ apr_atomic_inc32(&sIterationNestDepth);
+}
+
+void LLInstanceTrackerBase::StaticBase::decrementDepth()
{
- typedef std::map<std::string, void *> InstancesMap;
- static InstancesMap instances;
+ apr_atomic_dec32(&sIterationNestDepth);
+}
- // std::map::insert() is just what we want here. You attempt to insert a
- // (key, value) pair. If the specified key doesn't yet exist, it inserts
- // the pair and returns a std::pair of (iterator, true). If the specified
- // key DOES exist, insert() simply returns (iterator, false). One lookup
- // handles both cases.
- return instances.insert(InstancesMap::value_type(info.name(),
- InstancesMap::mapped_type()))
- .first->second;
+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 1eab270e3c..c8e1d9cd84 100755
--- a/indra/llcommon/llinstancetracker.h
+++ b/indra/llcommon/llinstancetracker.h
@@ -46,22 +46,6 @@
class LL_COMMON_API LLInstanceTrackerBase
{
protected:
- /// Get a process-unique void* pointer slot for the specified type_info
- static void * & getInstances(std::type_info const & info);
-
- /// Find or create a STATICDATA instance for the specified TRACKED class.
- /// STATICDATA must be default-constructible.
- template<typename STATICDATA, class TRACKED>
- static STATICDATA& getStatic()
- {
- void *& instances = getInstances(typeid(TRACKED));
- if (! instances)
- {
- instances = new STATICDATA;
- }
- return *static_cast<STATICDATA*>(instances);
- }
-
/// It's not essential to derive your STATICDATA (for use with
/// getStatic()) from StaticBase; it's just that both known
/// implementations do.
@@ -70,15 +54,21 @@ protected:
StaticBase():
sIterationNestDepth(0)
{}
- S32 sIterationNestDepth;
+
+ void incrementDepth();
+ void decrementDepth();
+ U32 getDepth();
+ private:
+ U32 sIterationNestDepth;
};
};
/// 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>
class LLInstanceTracker : public LLInstanceTrackerBase
{
typedef LLInstanceTracker<T, KEY> MyT;
@@ -87,7 +77,7 @@ class LLInstanceTracker : public LLInstanceTrackerBase
{
InstanceMap sMap;
};
- static StaticData& getStatic() { return LLInstanceTrackerBase::getStatic<StaticData, MyT>(); }
+ static StaticData& getStatic() { static StaticData sData; return sData;}
static InstanceMap& getMap_() { return getStatic().sMap; }
public:
@@ -99,12 +89,12 @@ public:
instance_iter(const typename InstanceMap::iterator& it)
: mIterator(it)
{
- ++getStatic().sIterationNestDepth;
+ getStatic().incrementDepth();
}
~instance_iter()
{
- --getStatic().sIterationNestDepth;
+ getStatic().decrementDepth();
}
@@ -131,20 +121,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();
}
@@ -182,7 +172,10 @@ public:
return instance_iter(getMap_().end());
}
- static S32 instanceCount() { return getMap_().size(); }
+ static S32 instanceCount()
+ {
+ return getMap_().size();
+ }
static key_iter beginKeys()
{
@@ -203,7 +196,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); }
@@ -227,18 +220,18 @@ 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
+class LLInstanceTracker<T, void> : public LLInstanceTrackerBase
{
- typedef LLInstanceTracker<T, T*> MyT;
+ typedef LLInstanceTracker<T, void> MyT;
typedef typename std::set<T*> InstanceSet;
struct StaticData: public StaticBase
{
InstanceSet sSet;
};
- static StaticData& getStatic() { return LLInstanceTrackerBase::getStatic<StaticData, MyT>(); }
+ static StaticData& getStatic() { static StaticData sData; return sData; }
static InstanceSet& getSet_() { return getStatic().sSet; }
public:
@@ -265,18 +258,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:
@@ -309,7 +302,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.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/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/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..c6b02df939 100755
--- a/indra/llcommon/llmemory.cpp
+++ b/indra/llcommon/llmemory.cpp
@@ -32,7 +32,6 @@
//#endif
#if defined(LL_WINDOWS)
-//# include <windows.h>
# include <psapi.h>
#elif defined(LL_DARWIN)
# include <sys/types.h>
diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h
index e725bdd9fa..95500753e4 100755
--- a/indra/llcommon/llmemory.h
+++ b/indra/llcommon/llmemory.h
@@ -27,6 +27,9 @@
#define LLMEMORY_H
#include "linden_common.h"
+#if !LL_WINDOWS
+#include <stdint.h>
+#endif
class LLMutex ;
@@ -36,6 +39,20 @@ class LLMutex ;
#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
+
inline void* ll_aligned_malloc( size_t size, int align )
{
void* mem = malloc( size + (align - 1) + sizeof(void*) );
diff --git a/indra/llcommon/llmetricperformancetester.cpp b/indra/llcommon/llmetricperformancetester.cpp
index 731e58bd20..fd89cb818a 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
@@ -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::TimeBlock::sMetricLog && ((LLTrace::TimeBlock::sLogName == name) || (LLTrace::TimeBlock::sLogName == DEFAULT_METRIC_NAME)));
}
/*static*/
@@ -194,8 +194,7 @@ void LLMetricPerformanceTesterBasic::preOutputTestResults(LLSD* sd)
void LLMetricPerformanceTesterBasic::postOutputTestResults(LLSD* sd)
{
- LLMutexLock lock(LLFastTimer::sLogLock);
- LLFastTimer::sLogQueue.push((*sd));
+ LLTrace::TimeBlock::pushLog(*sd);
}
void LLMetricPerformanceTesterBasic::outputTestResults()
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..ad0287c6d5
--- /dev/null
+++ b/indra/llcommon/llmutex.cpp
@@ -0,0 +1,179 @@
+/**
+ * @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)
+ llerrs << "Already locked in Thread: " << id << llendl;
+ 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)
+ 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()
+{
+ return mLockingThread == LLThread::currentID();
+}
+
+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);
+}
+
+
+//============================================================================
diff --git a/indra/llcommon/llmutex.h b/indra/llcommon/llmutex.h
new file mode 100644
index 0000000000..cbde4c47a9
--- /dev/null
+++ b/indra/llcommon/llmutex.h
@@ -0,0 +1,101 @@
+/**
+ * @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 "llapr.h"
+#include "apr_thread_cond.h"
+
+//============================================================================
+
+#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); // NULL pool constructs a new pool for the mutex
+ virtual ~LLMutex();
+
+ void lock(); // blocks
+ void unlock();
+ 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;
+};
+
+#endif // LL_LLTHREAD_H
diff --git a/indra/llcommon/llpointer.h b/indra/llcommon/llpointer.h
index 88c09c8dca..e640ffd595 100755
--- a/indra/llcommon/llpointer.h
+++ b/indra/llcommon/llpointer.h
@@ -97,24 +97,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 +111,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 +128,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,9 +150,9 @@ 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;
@@ -171,4 +165,40 @@ protected:
Type* mPointer;
};
+template<typename Type>
+class LLCopyOnWritePointer : public LLPointer<Type>
+{
+public:
+ typedef LLCopyOnWritePointer<Type> self_t;
+ typedef LLPointer<Type> pointer_t;
+
+ LLCopyOnWritePointer()
+ {}
+
+ LLCopyOnWritePointer(Type* ptr)
+ : LLPointer<Type>(ptr)
+ {}
+
+ LLCopyOnWritePointer(LLPointer<Type>& ptr)
+ : LLPointer<Type>(ptr)
+ {}
+
+ 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; }
+};
+
#endif
diff --git a/indra/llcommon/lllazy.cpp b/indra/llcommon/llpredicate.cpp
index 29fa040387..1278948e24 100755..100644
--- a/indra/llcommon/lllazy.cpp
+++ b/indra/llcommon/llpredicate.cpp
@@ -1,10 +1,8 @@
-/**
- * @file lllazy.cpp
- * @author Nat Goodspeed
- * @date 2009-01-28
- * @brief Implementation for lllazy.
- *
- * $LicenseInfo:firstyear=2009&license=viewerlgpl$
+/**
+ * @file llpredicate.cpp
+ * @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.
*
@@ -25,16 +23,19 @@
* 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;
+#include "llpredicate.h"
+
+namespace LLPredicate
+{
+ const U32 cPredicateFlagsFromEnum[5] =
+ {
+ 0xAAAAaaaa, // 10101010101010101010101010101010
+ 0xCCCCcccc, // 11001100110011001100110011001100
+ 0xF0F0F0F0, // 11110000111100001111000011110000
+ 0xFF00FF00, // 11111111000000001111111100000000
+ 0xFFFF0000 // 11111111111111110000000000000000
+ };
+}
+
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/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..5ddfa6fcef 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>
@@ -877,7 +875,7 @@ LLProcessorInfo::LLProcessorInfo() : mImpl(NULL)
LLProcessorInfo::~LLProcessorInfo() {}
-F64 LLProcessorInfo::getCPUFrequency() const { return mImpl->getCPUFrequency(); }
+LLUnitImplicit<LLUnits::Megahertz, F64> 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..fbd427f484 100755
--- a/indra/llcommon/llprocessor.h
+++ b/indra/llcommon/llprocessor.h
@@ -27,6 +27,8 @@
#ifndef LLPROCESSOR_H
#define LLPROCESSOR_H
+#include "llunit.h"
+
class LLProcessorInfoImpl;
class LL_COMMON_API LLProcessorInfo
@@ -35,7 +37,7 @@ public:
LLProcessorInfo();
~LLProcessorInfo();
- F64 getCPUFrequency() const;
+ LLUnitImplicit<LLUnits::Megahertz, F64> 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/llqueuedthread.cpp b/indra/llcommon/llqueuedthread.cpp
index abf47a0f57..4339f203db 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"
//============================================================================
@@ -134,8 +135,8 @@ S32 LLQueuedThread::updateQueue(F32 max_time_ms)
pending = getPending();
if(pending > 0)
{
- unpause();
- }
+ unpause();
+ }
}
else
{
@@ -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()->pushToMaster();
}
S32 pending = getPending();
-
return pending;
}
@@ -499,6 +502,7 @@ void LLQueuedThread::run()
if (isQuitting())
{
+ LLTrace::get_thread_recorder()->pushToMaster();
endThread();
break;
}
@@ -507,8 +511,9 @@ void LLQueuedThread::run()
threadedUpdate();
- int res = processNextRequest();
- if (res == 0)
+ int pending_work = processNextRequest();
+
+ if (pending_work == 0)
{
mIdleThread = TRUE;
ms_sleep(1);
diff --git a/indra/llcommon/llregistry.h b/indra/llcommon/llregistry.h
index bb0d60247e..c8ec0a0bc0 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
{
diff --git a/indra/llcommon/llsdparam.cpp b/indra/llcommon/llsdparam.cpp
index 9f4460a988..50815b2cc6 100755
--- a/indra/llcommon/llsdparam.cpp
+++ b/indra/llcommon/llsdparam.cpp
@@ -102,13 +102,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 +299,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 +330,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..7cfc265c62 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>
diff --git a/indra/llcommon/llsingleton.cpp b/indra/llcommon/llsingleton.cpp
index eb8e2c9456..9b49e52377 100755
--- a/indra/llcommon/llsingleton.cpp
+++ b/indra/llcommon/llsingleton.cpp
@@ -28,5 +28,4 @@
#include "llsingleton.h"
-std::map<std::string, void *> * LLSingletonRegistry::sSingletonMap = NULL;
diff --git a/indra/llcommon/llsingleton.h b/indra/llcommon/llsingleton.h
index 49d99f2cd0..b9cb8e3d41 100755
--- a/indra/llcommon/llsingleton.h
+++ b/indra/llcommon/llsingleton.h
@@ -30,38 +30,6 @@
#include <typeinfo>
#include <boost/noncopyable.hpp>
-/// @brief A global registry of all singletons to prevent duplicate allocations
-/// across shared library boundaries
-class LL_COMMON_API LLSingletonRegistry {
- private:
- typedef std::map<std::string, void *> TypeMap;
- static TypeMap * sSingletonMap;
-
- static void checkInit()
- {
- if(sSingletonMap == NULL)
- {
- sSingletonMap = new TypeMap();
- }
- }
-
- public:
- template<typename T> static void * & get()
- {
- std::string name(typeid(T).name());
-
- checkInit();
-
- // the first entry of the pair returned by insert will be either the existing
- // iterator matching our key, or the newly inserted NULL initialized entry
- // see "Insert element" in http://www.sgi.com/tech/stl/UniqueAssociativeContainer.html
- TypeMap::iterator result =
- sSingletonMap->insert(std::make_pair(name, (void*)NULL)).first;
-
- return result->second;
- }
-};
-
// LLSingleton implements the getInstance() method part of the Singleton
// pattern. It can't make the derived class constructors protected, though, so
// you have to do that yourself.
@@ -99,22 +67,30 @@ private:
INITIALIZED,
DELETED
} EInitState;
+
+ static DERIVED_TYPE* constructSingleton()
+ {
+ return new DERIVED_TYPE();
+ }
// stores pointer to singleton instance
- // and tracks initialization state of singleton
- struct SingletonInstanceData
+ struct SingletonLifetimeManager
{
- EInitState mInitState;
- DERIVED_TYPE* mSingletonInstance;
-
- SingletonInstanceData()
- : mSingletonInstance(NULL),
- mInitState(UNINITIALIZED)
- {}
-
- ~SingletonInstanceData()
+ SingletonLifetimeManager()
+ {
+ construct();
+ }
+
+ static void construct()
{
- if (mInitState != DELETED)
+ sData.mInitState = CONSTRUCTING;
+ sData.mInstance = constructSingleton();
+ sData.mInitState = INITIALIZING;
+ }
+
+ ~SingletonLifetimeManager()
+ {
+ if (sData.mInitState != DELETED)
{
deleteSingleton();
}
@@ -124,9 +100,8 @@ private:
public:
virtual ~LLSingleton()
{
- SingletonInstanceData& data = getData();
- data.mSingletonInstance = NULL;
- data.mInitState = DELETED;
+ sData.mInstance = NULL;
+ sData.mInitState = DELETED;
}
/**
@@ -151,50 +126,49 @@ public:
*/
static void deleteSingleton()
{
- delete getData().mSingletonInstance;
- getData().mSingletonInstance = NULL;
- getData().mInitState = DELETED;
+ delete sData.mInstance;
+ sData.mInstance = NULL;
+ sData.mInitState = DELETED;
}
- static SingletonInstanceData& getData()
- {
- // this is static to cache the lookup results
- static void * & registry = LLSingletonRegistry::get<DERIVED_TYPE>();
-
- // *TODO - look into making this threadsafe
- if(NULL == registry)
- {
- static SingletonInstanceData data;
- registry = &data;
- }
-
- return *static_cast<SingletonInstanceData *>(registry);
- }
static DERIVED_TYPE* getInstance()
{
- SingletonInstanceData& data = getData();
+ static SingletonLifetimeManager sLifeTimeMgr;
- if (data.mInitState == CONSTRUCTING)
+ switch (sData.mInitState)
{
+ case UNINITIALIZED:
+ // should never be uninitialized at this point
+ llassert(false);
+ return NULL;
+ case CONSTRUCTING:
llerrs << "Tried to access singleton " << typeid(DERIVED_TYPE).name() << " from singleton constructor!" << llendl;
- }
-
- if (data.mInitState == DELETED)
- {
+ 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;
+ SingletonLifetimeManager::construct();
+ // same as first time construction
+ sData.mInitState = INITIALIZED;
+ sData.mInstance->initSingleton();
+ return sData.mInstance;
}
-
- if (!data.mSingletonInstance)
- {
- data.mInitState = CONSTRUCTING;
- data.mSingletonInstance = new DERIVED_TYPE();
- data.mInitState = INITIALIZING;
- data.mSingletonInstance->initSingleton();
- data.mInitState = INITIALIZED;
- }
-
- return data.mSingletonInstance;
+
+ return NULL;
+ }
+
+ static DERIVED_TYPE* getIfExists()
+ {
+ return sData.mInstance;
}
// Reference version of getInstance()
@@ -208,18 +182,31 @@ public:
// Use this to avoid accessing singletons before the can safely be constructed
static bool instanceExists()
{
- return getData().mInitState == INITIALIZED;
+ return sData.mInitState == INITIALIZED;
}
// Has this singleton already been deleted?
// Use this to avoid accessing singletons from a static object's destructor
static bool destroyed()
{
- return getData().mInitState == DELETED;
+ return sData.mInitState == DELETED;
}
private:
+
virtual void initSingleton() {}
+
+ 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;
+ };
+ static SingletonData sData;
};
+template<typename T>
+typename LLSingleton<T>::SingletonData LLSingleton<T>::sData;
+
#endif
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..ab9b6709e8 100755
--- a/indra/llcommon/llstatenums.h
+++ b/indra/llcommon/llstatenums.h
@@ -26,7 +26,7 @@
#ifndef LL_LLSTATENUMS_H
#define LL_LLSTATENUMS_H
-enum
+enum ESimStatID
{
LL_SIM_STAT_TIME_DILATION = 0,
LL_SIM_STAT_FPS = 1,
diff --git a/indra/llcommon/llstl.h b/indra/llcommon/llstl.h
index d3941e1bc9..424138dad1 100755
--- a/indra/llcommon/llstl.h
+++ b/indra/llcommon/llstl.h
@@ -31,6 +31,7 @@
#include <algorithm>
#include <map>
#include <vector>
+#include <list>
#include <set>
#include <deque>
#include <typeinfo>
diff --git a/indra/llcommon/llstring.cpp b/indra/llcommon/llstring.cpp
index 22c8681983..66c416bfdd 100755
--- a/indra/llcommon/llstring.cpp
+++ b/indra/llcommon/llstring.cpp
@@ -28,11 +28,10 @@
#include "llstring.h"
#include "llerror.h"
+#include "llfasttimer.h"
#if LL_WINDOWS
-#define WIN32_LEAN_AND_MEAN
-#include <winsock2.h>
-#include <windows.h>
+#include "llwin32headerslean.h"
#include <winnls.h> // for WideCharToMultiByte
#endif
diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h
index f9702868c8..17893c1910 100755
--- a/indra/llcommon/llstring.h
+++ b/indra/llcommon/llstring.h
@@ -31,8 +31,9 @@
#include <cstdio>
#include <locale>
#include <iomanip>
+#include <algorithm>
#include "llsd.h"
-#include "llfasttimer.h"
+#include "llformat.h"
#if LL_LINUX || LL_SOLARIS
#include <wctype.h>
diff --git a/indra/llcommon/llsys.cpp b/indra/llcommon/llsys.cpp
index 57a6de9060..95bbcbc816 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>
diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp
index 1d56a52c32..118568d5ef 100755
--- a/indra/llcommon/llthread.cpp
+++ b/indra/llcommon/llthread.cpp
@@ -29,8 +29,11 @@
#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>
@@ -56,12 +59,17 @@
//
//----------------------------------------------------------------------------
-#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();
@@ -85,6 +93,8 @@ void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap
{
LLThread *threadp = (LLThread *)datap;
+ LLTrace::ThreadRecorder* thread_recorder = new LLTrace::SlaveThreadRecorder(LLTrace::getUIThreadRecorder());
+
#if !LL_DARWIN
sThreadID = threadp->mID;
#endif
@@ -97,16 +107,18 @@ void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap
// We're done with the run function, this thread is done executing now.
threadp->mStatus = STOPPED;
+ delete thread_recorder;
+
return NULL;
}
-
LLThread::LLThread(const std::string& name, apr_pool_t *poolp) :
mPaused(FALSE),
mName(name),
mAPRThreadp(NULL),
mStatus(STOPPED)
{
+
mID = ++sIDIter;
// Thread creation probably CAN be paranoid about APR being initialized, if necessary
@@ -152,7 +164,7 @@ void LLThread::shutdown()
//llinfos << "LLThread::~LLThread() Killing thread " << mName << " Status: " << mStatus << llendl;
// 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)
@@ -282,7 +294,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
@@ -315,155 +333,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
-}
-
-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
@@ -514,7 +383,6 @@ LLThreadSafeRefCount::~LLThreadSafeRefCount()
}
}
-
//============================================================================
LLResponder::~LLResponder()
diff --git a/indra/llcommon/llthread.h b/indra/llcommon/llthread.h
index 0fb89c5613..4a84a14a65 100755
--- a/indra/llcommon/llthread.h
+++ b/indra/llcommon/llthread.h
@@ -31,20 +31,14 @@
#include "llapr.h"
#include "apr_thread_cond.h"
#include "boost/intrusive_ptr.hpp"
+#include "llmutex.h"
-class LLThread;
-class LLMutex;
-class LLCondition;
-
-#if LL_WINDOWS
-#define ll_thread_local __declspec(thread)
-#else
-#define ll_thread_local __thread
-#endif
+LL_COMMON_API void assert_main_thread();
class LL_COMMON_API LLThread
{
private:
+ friend class LLMutex;
static U32 sIDIter;
public:
@@ -98,15 +92,15 @@ 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;
- apr_pool_t *mAPRPoolp;
+ apr_thread_t* mAPRThreadp;
+ apr_pool_t* mAPRPoolp;
BOOL mIsLocalPool;
EThreadStatus mStatus;
U32 mID;
@@ -114,7 +108,7 @@ protected:
//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.
// otherwise it will cause severe memory leaking!!! --bao
- LLVolatileAPRPool *mLocalAPRFilePoolp ;
+ LLVolatileAPRPool* mLocalAPRFilePoolp ;
void setQuitting();
@@ -140,75 +134,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
- void unlock();
- 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;
-};
-
-//============================================================================
void LLThread::lockData()
{
diff --git a/indra/llcommon/llthreadlocalstorage.cpp b/indra/llcommon/llthreadlocalstorage.cpp
new file mode 100644
index 0000000000..32d94331a6
--- /dev/null
+++ b/indra/llcommon/llthreadlocalstorage.cpp
@@ -0,0 +1,117 @@
+/**
+ * @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);
+ llerrs << "Failed to set thread local data" << llendl;
+ }
+}
+
+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);
+ llerrs << "Failed to get thread local data" << llendl;
+ }
+ 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);
+ llerrs << "Failed to allocate thread local data" << llendl;
+ }
+}
+
+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);
+ llerrs << "Failed to delete thread local data" << llendl;
+ }
+ }
+ }
+}
+
+void LLThreadLocalPointerBase::initAllThreadLocalStorage()
+{
+ if (!sInitialized)
+ {
+ for (LLInstanceTracker<LLThreadLocalPointerBase>::instance_iter it = beginInstances(), end_it = endInstances();
+ it != end_it;
+ ++it)
+ {
+ (*it).initStorage();
+ }
+ sInitialized = true;
+ }
+}
+
+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..a15f9185b1
--- /dev/null
+++ b/indra/llcommon/llthreadlocalstorage.h
@@ -0,0 +1,357 @@
+/**
+ * @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 LLThreadLocalSingleton
+{
+ typedef enum e_init_state
+ {
+ UNINITIALIZED = 0,
+ CONSTRUCTING,
+ INITIALIZING,
+ INITIALIZED,
+ DELETED
+ } EInitState;
+
+public:
+ LLThreadLocalSingleton()
+ {}
+
+ virtual ~LLThreadLocalSingleton()
+ {
+#if LL_DARWIN
+ pthread_setspecific(sInstanceKey, NULL);
+#else
+ sInstance = NULL;
+#endif
+ setInitState(DELETED);
+ }
+
+ static void deleteSingleton()
+ {
+ delete getIfExists();
+ }
+
+ static DERIVED_TYPE* getInstance()
+ {
+ EInitState init_state = getInitState();
+ if (init_state == CONSTRUCTING)
+ {
+ llerrs << "Tried to access singleton " << typeid(DERIVED_TYPE).name() << " from singleton constructor!" << llendl;
+ }
+
+ if (init_state == DELETED)
+ {
+ llwarns << "Trying to access deleted singleton " << typeid(DERIVED_TYPE).name() << " creating new instance" << llendl;
+ }
+
+#if LL_DARWIN
+ createTLSInstance();
+#endif
+ if (!getIfExists())
+ {
+ setInitState(CONSTRUCTING);
+ DERIVED_TYPE* instancep = new DERIVED_TYPE();
+#if LL_DARWIN
+ S32 result = pthread_setspecific(sInstanceKey, (void*)instancep);
+ if (result != 0)
+ {
+ llerrs << "Could not set thread local storage" << llendl;
+ }
+#else
+ sInstance = instancep;
+#endif
+ setInitState(INITIALIZING);
+ instancep->initSingleton();
+ setInitState(INITIALIZED);
+ }
+
+ return getIfExists();
+ }
+
+ static DERIVED_TYPE* getIfExists()
+ {
+#if LL_DARWIN
+ return (DERIVED_TYPE*)pthread_getspecific(sInstanceKey);
+#else
+ return sInstance;
+#endif
+ }
+
+ // Reference version of getInstance()
+ // Preferred over getInstance() as it disallows checking for NULL
+ static DERIVED_TYPE& instance()
+ {
+ return *getInstance();
+ }
+
+ // Has this singleton been created uet?
+ // Use this to avoid accessing singletons before the can safely be constructed
+ static bool instanceExists()
+ {
+ return getInitState() == INITIALIZED;
+ }
+
+ // Has this singleton already been deleted?
+ // Use this to avoid accessing singletons from a static object's destructor
+ static bool destroyed()
+ {
+ return getInitState() == DELETED;
+ }
+private:
+#if LL_DARWIN
+ static void createTLSInitState()
+ {
+ static S32 key_created = pthread_key_create(&sInitStateKey, NULL);
+ if (key_created != 0)
+ {
+ llerrs << "Could not create thread local storage" << llendl;
+ }
+ }
+
+ static void createTLSInstance()
+ {
+ static S32 key_created = pthread_key_create(&sInstanceKey, NULL);
+ if (key_created != 0)
+ {
+ llerrs << "Could not create thread local storage" << llendl;
+ }
+ }
+#endif
+ static EInitState getInitState()
+ {
+#if LL_DARWIN
+ createTLSInitState();
+ return (EInitState)(int)pthread_getspecific(sInitStateKey);
+#else
+ return sInitState;
+#endif
+ }
+
+ static void setInitState(EInitState state)
+ {
+#if LL_DARWIN
+ createTLSInitState();
+ pthread_setspecific(sInitStateKey, (void*)state);
+#else
+ sInitState = state;
+#endif
+ }
+ LLThreadLocalSingleton(const LLThreadLocalSingleton& other);
+ virtual void initSingleton() {}
+
+#ifdef LL_WINDOWS
+ static __declspec(thread) DERIVED_TYPE* sInstance;
+ static __declspec(thread) EInitState sInitState;
+#elif LL_LINUX
+ static __thread DERIVED_TYPE* sInstance;
+ static __thread EInitState sInitState;
+#elif LL_DARWIN
+ static pthread_key_t sInstanceKey;
+ static pthread_key_t sInitStateKey;
+#endif
+};
+
+#if LL_WINDOWS
+template<typename DERIVED_TYPE>
+__declspec(thread) DERIVED_TYPE* LLThreadLocalSingleton<DERIVED_TYPE>::sInstance = NULL;
+
+template<typename DERIVED_TYPE>
+__declspec(thread) typename LLThreadLocalSingleton<DERIVED_TYPE>::EInitState LLThreadLocalSingleton<DERIVED_TYPE>::sInitState = LLThreadLocalSingleton<DERIVED_TYPE>::UNINITIALIZED;
+#elif LL_LINUX
+template<typename DERIVED_TYPE>
+__thread DERIVED_TYPE* LLThreadLocalSingleton<DERIVED_TYPE>::sInstance = NULL;
+
+template<typename DERIVED_TYPE>
+__thread typename LLThreadLocalSingleton<DERIVED_TYPE>::EInitState LLThreadLocalSingleton<DERIVED_TYPE>::sInitState = LLThreadLocalSingleton<DERIVED_TYPE>::UNINITIALIZED;
+#elif LL_DARWIN
+template<typename DERIVED_TYPE>
+pthread_key_t LLThreadLocalSingleton<DERIVED_TYPE>::sInstanceKey;
+
+template<typename DERIVED_TYPE>
+pthread_key_t LLThreadLocalSingleton<DERIVED_TYPE>::sInitStateKey;
+
+#endif
+
+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()
+ {
+ llerrs << "Could not create thread local storage" << llendl;
+ }
+ static void createTLSKey()
+ {
+ static S32 key_created = pthread_key_create(&sInstanceKey, NULL);
+ if (key_created != 0)
+ {
+ llerrs << "Could not create thread local storage" << llendl;
+ }
+ }
+ 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/lltimer.cpp b/indra/llcommon/lltimer.cpp
index 9ebc6de7f4..838155d54d 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"
@@ -287,14 +285,14 @@ LLTimer::~LLTimer()
}
// static
-U64 LLTimer::getTotalTime()
+LLUnitImplicit<LLUnits::Microseconds, U64> LLTimer::getTotalTime()
{
// simply call into the implementation function.
return totalTime();
}
// static
-F64 LLTimer::getTotalSeconds()
+LLUnitImplicit<LLUnits::Seconds, F64> LLTimer::getTotalSeconds()
{
return U64_to_F64(getTotalTime()) * USEC_TO_SEC_F64;
}
@@ -343,23 +341,23 @@ U64 getElapsedTimeAndUpdate(U64& lastClockCount)
}
-F64 LLTimer::getElapsedTimeF64() const
+LLUnitImplicit<LLUnits::Seconds, F64> LLTimer::getElapsedTimeF64() const
{
U64 last = mLastClockCount;
return (F64)getElapsedTimeAndUpdate(last) * gClockFrequencyInv;
}
-F32 LLTimer::getElapsedTimeF32() const
+LLUnitImplicit<LLUnits::Seconds, F32> LLTimer::getElapsedTimeF32() const
{
return (F32)getElapsedTimeF64();
}
-F64 LLTimer::getElapsedTimeAndResetF64()
+LLUnitImplicit<LLUnits::Seconds, F64> LLTimer::getElapsedTimeAndResetF64()
{
return (F64)getElapsedTimeAndUpdate(mLastClockCount) * gClockFrequencyInv;
}
-F32 LLTimer::getElapsedTimeAndResetF32()
+LLUnitImplicit<LLUnits::Seconds, F32> LLTimer::getElapsedTimeAndResetF32()
{
return (F32)getElapsedTimeAndResetF64();
}
@@ -372,7 +370,7 @@ void LLTimer::setTimerExpirySec(F32 expiration)
+ (U64)((F32)(expiration * gClockFrequency));
}
-F32 LLTimer::getRemainingTimeF32() const
+LLUnitImplicit<LLUnits::Seconds, F32> LLTimer::getRemainingTimeF32() const
{
U64 cur_ticks = get_clock_count();
if (cur_ticks > mExpirationTicks)
diff --git a/indra/llcommon/lltimer.h b/indra/llcommon/lltimer.h
index 513de0605d..0ba87d1e15 100755
--- a/indra/llcommon/lltimer.h
+++ b/indra/llcommon/lltimer.h
@@ -37,6 +37,7 @@
#include <string>
#include <list>
// units conversions
+#include "llunit.h"
#ifndef USEC_PER_SEC
const U32 USEC_PER_SEC = 1000000;
#endif
@@ -55,7 +56,7 @@ public:
protected:
U64 mLastClockCount;
U64 mExpirationTicks;
- BOOL mStarted;
+ bool mStarted;
public:
LLTimer();
@@ -66,16 +67,16 @@ public:
// Return a high precision number of seconds since the start of
// this application instance.
- static F64 getElapsedSeconds()
+ static LLUnitImplicit<LLUnits::Seconds, F64> getElapsedSeconds()
{
return sTimer->getElapsedTimeF64();
}
// Return a high precision usec since epoch
- static U64 getTotalTime();
+ static LLUnitImplicit<LLUnits::Microseconds, U64> getTotalTime();
// Return a high precision seconds since epoch
- static F64 getTotalSeconds();
+ static LLUnitImplicit<LLUnits::Seconds, F64> getTotalSeconds();
// MANIPULATORS
@@ -86,18 +87,18 @@ public:
void setTimerExpirySec(F32 expiration);
BOOL checkExpirationAndReset(F32 expiration);
BOOL hasExpired() const;
- F32 getElapsedTimeAndResetF32(); // Returns elapsed time in seconds with reset
- F64 getElapsedTimeAndResetF64();
+ LLUnitImplicit<LLUnits::Seconds, F32> getElapsedTimeAndResetF32(); // Returns elapsed time in seconds with reset
+ LLUnitImplicit<LLUnits::Seconds, F64> getElapsedTimeAndResetF64();
- F32 getRemainingTimeF32() const;
+ LLUnitImplicit<LLUnits::Seconds, F32> getRemainingTimeF32() const;
static BOOL knownBadTimer();
// ACCESSORS
- F32 getElapsedTimeF32() const; // Returns elapsed time in seconds
- F64 getElapsedTimeF64() const; // Returns elapsed time in seconds
+ LLUnitImplicit<LLUnits::Seconds, F32> getElapsedTimeF32() const; // Returns elapsed time in seconds
+ LLUnitImplicit<LLUnits::Seconds, F64> getElapsedTimeF64() const; // Returns elapsed time in seconds
- BOOL getStarted() const { return mStarted; }
+ bool getStarted() const { return mStarted; }
static U64 getCurrentClockCount(); // Returns the raw clockticks
diff --git a/indra/llcommon/lltrace.cpp b/indra/llcommon/lltrace.cpp
new file mode 100644
index 0000000000..c831a1548d
--- /dev/null
+++ b/indra/llcommon/lltrace.cpp
@@ -0,0 +1,115 @@
+/**
+ * @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"
+
+static S32 sInitializationCount = 0;
+
+namespace LLTrace
+{
+
+static MasterThreadRecorder* gUIThreadRecorder = NULL;
+
+void init()
+{
+ if (sInitializationCount++ == 0)
+ {
+ gUIThreadRecorder = new MasterThreadRecorder();
+ }
+}
+
+bool isInitialized()
+{
+ return sInitializationCount > 0;
+}
+
+void cleanup()
+{
+ if (--sInitializationCount == 0)
+ {
+ delete gUIThreadRecorder;
+ gUIThreadRecorder = NULL;
+ }
+}
+
+MasterThreadRecorder& getUIThreadRecorder()
+{
+ llassert(gUIThreadRecorder != NULL);
+ return *gUIThreadRecorder;
+}
+
+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;
+}
+
+
+TimeBlockTreeNode::TimeBlockTreeNode()
+: mBlock(NULL),
+ mParent(NULL),
+ mNeedsSorting(false)
+{}
+
+void TimeBlockTreeNode::setParent( TimeBlock* 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<TimeBlock*>& children = mParent->getChildren();
+ std::vector<TimeBlock*>::iterator found_it = std::find(children.begin(), children.end(), mBlock);
+ if (found_it != children.end())
+ {
+ children.erase(found_it);
+ }
+ }
+
+ mParent = parent;
+ mBlock->getPrimaryAccumulator()->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..343e1b16e8
--- /dev/null
+++ b/indra/llcommon/lltrace.h
@@ -0,0 +1,1083 @@
+/**
+ * @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 "llunit.h"
+#include "llthreadlocalstorage.h"
+#include "lltimer.h"
+
+#include <list>
+
+#define LL_RECORD_BLOCK_TIME(block_timer) LLTrace::TimeBlock::Recorder LL_GLUE_TOKENS(block_time_recorder, __COUNTER__)(block_timer);
+
+namespace LLTrace
+{
+class Recording;
+
+typedef LLUnit<LLUnits::Bytes, F64> Bytes;
+typedef LLUnit<LLUnits::Kibibytes, F64> Kibibytes;
+typedef LLUnit<LLUnits::Mibibytes, F64> Mibibytes;
+typedef LLUnit<LLUnits::Gibibytes, F64> Gibibytes;
+typedef LLUnit<LLUnits::Bits, F64> Bits;
+typedef LLUnit<LLUnits::Kibibits, F64> Kibibits;
+typedef LLUnit<LLUnits::Mibibits, F64> Mibibits;
+typedef LLUnit<LLUnits::Gibibits, F64> Gibibits;
+
+typedef LLUnit<LLUnits::Seconds, F64> Seconds;
+typedef LLUnit<LLUnits::Milliseconds, F64> Milliseconds;
+typedef LLUnit<LLUnits::Minutes, F64> Minutes;
+typedef LLUnit<LLUnits::Hours, F64> Hours;
+typedef LLUnit<LLUnits::Milliseconds, F64> Milliseconds;
+typedef LLUnit<LLUnits::Microseconds, F64> Microseconds;
+typedef LLUnit<LLUnits::Nanoseconds, F64> Nanoseconds;
+
+typedef LLUnit<LLUnits::Meters, F64> Meters;
+typedef LLUnit<LLUnits::Kilometers, F64> Kilometers;
+typedef LLUnit<LLUnits::Centimeters, F64> Centimeters;
+typedef LLUnit<LLUnits::Millimeters, F64> Millimeters;
+
+void init();
+void cleanup();
+bool isInitialized();
+
+const LLThreadLocalPointer<class ThreadRecorder>& get_thread_recorder();
+void set_thread_recorder(class ThreadRecorder*);
+
+class MasterThreadRecorder& getUIThreadRecorder();
+
+template<typename ACCUMULATOR>
+class AccumulatorBuffer : public LLRefCount
+{
+ typedef AccumulatorBuffer<ACCUMULATOR> self_t;
+ static const U32 DEFAULT_ACCUMULATOR_BUFFER_SIZE = 64;
+private:
+ struct StaticAllocationMarker { };
+
+ AccumulatorBuffer(StaticAllocationMarker m)
+ : mStorageSize(0),
+ mStorage(NULL)
+ {}
+
+public:
+
+ AccumulatorBuffer(const AccumulatorBuffer& other = *getDefaultBuffer())
+ : mStorageSize(0),
+ mStorage(NULL)
+ {
+ resize(other.mStorageSize);
+ for (S32 i = 0; i < sNextStorageSlot; i++)
+ {
+ mStorage[i] = other.mStorage[i];
+ }
+ }
+
+ ~AccumulatorBuffer()
+ {
+ if (isPrimary())
+ {
+ 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, bool append = true)
+ {
+ llassert(mStorageSize >= sNextStorageSlot && other.mStorageSize > sNextStorageSlot);
+ for (size_t i = 0; i < sNextStorageSlot; i++)
+ {
+ mStorage[i].addSamples(other.mStorage[i], append);
+ }
+ }
+
+ 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 flush()
+ {
+ llassert(mStorageSize >= sNextStorageSlot);
+ for (size_t i = 0; i < sNextStorageSlot; i++)
+ {
+ mStorage[i].flush();
+ }
+ }
+
+ void makePrimary()
+ {
+ LLThreadLocalSingletonPointer<ACCUMULATOR>::setInstance(mStorage);
+ }
+
+ bool isPrimary() const
+ {
+ return LLThreadLocalSingletonPointer<ACCUMULATOR>::getInstance() == mStorage;
+ }
+
+ LL_FORCE_INLINE static ACCUMULATOR* getPrimaryStorage()
+ {
+ ACCUMULATOR* accumulator = LLThreadLocalSingletonPointer<ACCUMULATOR>::getInstance();
+ return accumulator ? accumulator : sDefaultBuffer->mStorage;
+ }
+
+ // 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()
+ {
+#ifndef LL_RELEASE_FOR_DOWNLOAD
+ if (LLTrace::isInitialized())
+ {
+ llerrs << "Attempting to declare trace object after program initialization. Trace objects should be statically initialized." << llendl;
+ }
+#endif
+ size_t next_slot = sNextStorageSlot++;
+ if (next_slot >= mStorageSize)
+ {
+ 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 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;
+
+template<typename ACCUMULATOR>
+class TraceType
+: public LLInstanceTracker<TraceType<ACCUMULATOR>, std::string>
+{
+public:
+ TraceType(const char* name, const char* description = NULL)
+ : LLInstanceTracker<TraceType<ACCUMULATOR>, std::string>(name),
+ mName(name),
+ mDescription(description ? description : ""),
+ mAccumulatorIndex(AccumulatorBuffer<ACCUMULATOR>::getDefaultBuffer()->reserveSlot())
+ {}
+
+ LL_FORCE_INLINE ACCUMULATOR* getPrimaryAccumulator() const
+ {
+ ACCUMULATOR* accumulator_storage = AccumulatorBuffer<ACCUMULATOR>::getPrimaryStorage();
+ return &accumulator_storage[mAccumulatorIndex];
+ }
+
+ size_t getIndex() const { return mAccumulatorIndex; }
+
+ virtual const char* getUnitLabel() { return ""; }
+
+ const std::string& getName() const { return mName; }
+
+protected:
+ const std::string mName;
+ const std::string mDescription;
+ const size_t mAccumulatorIndex;
+};
+
+class EventAccumulator
+{
+public:
+ typedef F64 value_t;
+ typedef F64 mean_t;
+
+ EventAccumulator()
+ : mSum(0),
+ mMin((std::numeric_limits<F64>::max)()),
+ mMax((std::numeric_limits<F64>::min)()),
+ mMean(0),
+ mVarianceSum(0),
+ mNumSamples(0),
+ mLastValue(0)
+ {}
+
+ void record(F64 value)
+ {
+ mNumSamples++;
+ mSum += value;
+ // NOTE: both conditions will hold on first pass through
+ if (value < mMin)
+ {
+ mMin = value;
+ }
+ if (value > mMax)
+ {
+ mMax = value;
+ }
+ F64 old_mean = mMean;
+ mMean += (value - old_mean) / (F64)mNumSamples;
+ mVarianceSum += (value - old_mean) * (value - mMean);
+ mLastValue = value;
+ }
+
+ void addSamples(const EventAccumulator& other, bool append)
+ {
+ if (other.mNumSamples)
+ {
+ 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; }
+
+ // 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 = (F64)mNumSamples,
+ n_2 = (F64)other.mNumSamples;
+ F64 m_1 = mMean,
+ m_2 = other.mMean;
+ F64 v_1 = mVarianceSum / mNumSamples,
+ v_2 = other.mVarianceSum / other.mNumSamples;
+ if (n_1 == 0)
+ {
+ mVarianceSum = other.mVarianceSum;
+ }
+ else if (n_2 == 0)
+ {
+ // don't touch variance
+ // mVarianceSum = mVarianceSum;
+ }
+ else
+ {
+ mVarianceSum = (F64)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));
+ }
+
+ F64 weight = (F64)mNumSamples / (F64)(mNumSamples + other.mNumSamples);
+ mNumSamples += other.mNumSamples;
+ mMean = mMean * weight + other.mMean * (1.f - weight);
+ if (append) mLastValue = other.mLastValue;
+ }
+ }
+
+ void reset(const EventAccumulator* other)
+ {
+ mNumSamples = 0;
+ mSum = 0;
+ mMin = std::numeric_limits<F64>::max();
+ mMax = std::numeric_limits<F64>::min();
+ mMean = 0;
+ mVarianceSum = 0;
+ mLastValue = other ? other->mLastValue : 0;
+ }
+
+ void flush() {}
+
+ F64 getSum() const { return mSum; }
+ F64 getMin() const { return mMin; }
+ F64 getMax() const { return mMax; }
+ F64 getLastValue() const { return mLastValue; }
+ F64 getMean() const { return mMean; }
+ F64 getStandardDeviation() const { return sqrtf(mVarianceSum / mNumSamples); }
+ U32 getSampleCount() const { return mNumSamples; }
+
+private:
+ F64 mSum,
+ mMin,
+ mMax,
+ mLastValue;
+
+ F64 mMean,
+ mVarianceSum;
+
+ U32 mNumSamples;
+};
+
+
+class SampleAccumulator
+{
+public:
+ typedef F64 value_t;
+ typedef F64 mean_t;
+
+ SampleAccumulator()
+ : mSum(0),
+ mMin((std::numeric_limits<F64>::max)()),
+ mMax((std::numeric_limits<F64>::min)()),
+ mMean(0),
+ mVarianceSum(0),
+ mLastSampleTimeStamp(LLTimer::getTotalSeconds()),
+ mTotalSamplingTime(0),
+ mNumSamples(0),
+ mLastValue(0),
+ mHasValue(false)
+ {}
+
+ void sample(F64 value)
+ {
+ LLUnitImplicit<LLUnits::Seconds, F64> time_stamp = LLTimer::getTotalSeconds();
+ LLUnitImplicit<LLUnits::Seconds, F64> delta_time = time_stamp - mLastSampleTimeStamp;
+ mLastSampleTimeStamp = time_stamp;
+
+ if (mHasValue)
+ {
+ mTotalSamplingTime += delta_time;
+ mSum += mLastValue * delta_time;
+
+ // NOTE: both conditions will hold first time through
+ if (value < mMin) { mMin = value; }
+ if (value > mMax) { mMax = value; }
+
+ F64 old_mean = mMean;
+ mMean += (delta_time / mTotalSamplingTime) * (mLastValue - old_mean);
+ mVarianceSum += delta_time * (mLastValue - old_mean) * (mLastValue - mMean);
+ }
+
+ mLastValue = value;
+ mNumSamples++;
+ mHasValue = true;
+ }
+
+ void addSamples(const SampleAccumulator& other, bool append)
+ {
+ if (other.mTotalSamplingTime)
+ {
+ 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; }
+
+ // 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 = mTotalSamplingTime,
+ n_2 = other.mTotalSamplingTime;
+ F64 m_1 = mMean,
+ m_2 = other.mMean;
+ F64 v_1 = mVarianceSum / mTotalSamplingTime,
+ v_2 = other.mVarianceSum / other.mTotalSamplingTime;
+ if (n_1 == 0)
+ {
+ mVarianceSum = other.mVarianceSum;
+ }
+ else if (n_2 == 0)
+ {
+ // variance is unchanged
+ // mVarianceSum = mVarianceSum;
+ }
+ else
+ {
+ mVarianceSum = mTotalSamplingTime
+ * ((((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));
+ }
+
+ llassert(other.mTotalSamplingTime > 0);
+ F64 weight = mTotalSamplingTime / (mTotalSamplingTime + other.mTotalSamplingTime);
+ mNumSamples += other.mNumSamples;
+ mTotalSamplingTime += other.mTotalSamplingTime;
+ mMean = (mMean * weight) + (other.mMean * (1.0 - weight));
+ if (append)
+ {
+ mLastValue = other.mLastValue;
+ mLastSampleTimeStamp = other.mLastSampleTimeStamp;
+ mHasValue |= other.mHasValue;
+ }
+ }
+ }
+
+ void reset(const SampleAccumulator* other)
+ {
+ mNumSamples = 0;
+ mSum = 0;
+ mMin = std::numeric_limits<F64>::max();
+ mMax = std::numeric_limits<F64>::min();
+ mMean = other ? other->mLastValue : 0;
+ mVarianceSum = 0;
+ mLastSampleTimeStamp = LLTimer::getTotalSeconds();
+ mTotalSamplingTime = 0;
+ mLastValue = other ? other->mLastValue : 0;
+ mHasValue = other ? other->mHasValue : false;
+ }
+
+ void flush()
+ {
+ LLUnitImplicit<LLUnits::Seconds, F64> time_stamp = LLTimer::getTotalSeconds();
+ LLUnitImplicit<LLUnits::Seconds, F64> delta_time = time_stamp - mLastSampleTimeStamp;
+
+ if (mHasValue)
+ {
+ mSum += mLastValue * delta_time;
+ mTotalSamplingTime += delta_time;
+ }
+ mLastSampleTimeStamp = time_stamp;
+ }
+
+ F64 getSum() const { return mSum; }
+ F64 getMin() const { return mMin; }
+ F64 getMax() const { return mMax; }
+ F64 getLastValue() const { return mLastValue; }
+ F64 getMean() const { return mMean; }
+ F64 getStandardDeviation() const { return sqrtf(mVarianceSum / mTotalSamplingTime); }
+ U32 getSampleCount() const { return mNumSamples; }
+
+private:
+ F64 mSum,
+ mMin,
+ mMax,
+ mLastValue;
+
+ bool mHasValue;
+
+ F64 mMean,
+ mVarianceSum;
+
+ LLUnitImplicit<LLUnits::Seconds, F64> mLastSampleTimeStamp,
+ mTotalSamplingTime;
+
+ U32 mNumSamples;
+};
+
+class CountAccumulator
+{
+public:
+ typedef F64 value_t;
+ typedef F64 mean_t;
+
+ CountAccumulator()
+ : mSum(0),
+ mNumSamples(0)
+ {}
+
+ void add(F64 value)
+ {
+ mNumSamples++;
+ mSum += value;
+ }
+
+ void addSamples(const CountAccumulator& other, bool /*append*/)
+ {
+ mSum += other.mSum;
+ mNumSamples += other.mNumSamples;
+ }
+
+ void reset(const CountAccumulator* other)
+ {
+ mNumSamples = 0;
+ mSum = 0;
+ }
+
+ void flush() {}
+
+ F64 getSum() const { return mSum; }
+
+ U32 getSampleCount() const { return mNumSamples; }
+
+private:
+ F64 mSum;
+
+ U32 mNumSamples;
+};
+
+class TimeBlockAccumulator
+{
+public:
+ typedef LLUnit<LLUnits::Seconds, F64> value_t;
+ typedef LLUnit<LLUnits::Seconds, F64> mean_t;
+ typedef TimeBlockAccumulator self_t;
+
+ // fake classes that allows us to view different facets of underlying statistic
+ struct CallCountFacet
+ {
+ typedef U32 value_t;
+ typedef F32 mean_t;
+ };
+
+ struct SelfTimeFacet
+ {
+ typedef LLUnit<LLUnits::Seconds, F64> value_t;
+ typedef LLUnit<LLUnits::Seconds, F64> mean_t;
+ };
+
+ TimeBlockAccumulator();
+ void addSamples(const self_t& other, bool /*append*/);
+ void reset(const self_t* other);
+ void flush() {}
+
+ //
+ // members
+ //
+ U64 mStartTotalTimeCounter,
+ mTotalTimeCounter,
+ mSelfTimeCounter;
+ U32 mCalls;
+ class TimeBlock* mParent; // last acknowledged parent of this time block
+ class TimeBlock* 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
+
+};
+
+template<>
+class TraceType<TimeBlockAccumulator::CallCountFacet>
+: public TraceType<TimeBlockAccumulator>
+{
+public:
+
+ TraceType(const char* name, const char* description = "")
+ : TraceType<TimeBlockAccumulator>(name, description)
+ {}
+};
+
+template<>
+class TraceType<TimeBlockAccumulator::SelfTimeFacet>
+ : public TraceType<TimeBlockAccumulator>
+{
+public:
+
+ TraceType(const char* name, const char* description = "")
+ : TraceType<TimeBlockAccumulator>(name, description)
+ {}
+};
+
+class TimeBlock;
+class TimeBlockTreeNode
+{
+public:
+ TimeBlockTreeNode();
+
+ void setParent(TimeBlock* parent);
+ TimeBlock* getParent() { return mParent; }
+
+ TimeBlock* mBlock;
+ TimeBlock* mParent;
+ std::vector<TimeBlock*> mChildren;
+ bool mNeedsSorting;
+};
+
+
+template <typename T = F64>
+class EventStatHandle
+: public TraceType<EventAccumulator>
+{
+public:
+ typedef typename F64 storage_t;
+ typedef TraceType<EventAccumulator> trace_t;
+
+ EventStatHandle(const char* name, const char* description = NULL)
+ : trace_t(name, description)
+ {}
+
+ /*virtual*/ const char* getUnitLabel() { return LLGetUnitLabel<T>::getUnitLabel(); }
+
+};
+
+template<typename T, typename VALUE_T>
+void record(EventStatHandle<T>& measurement, VALUE_T value)
+{
+ T converted_value(value);
+ measurement.getPrimaryAccumulator()->record(LLUnits::rawValue(converted_value));
+}
+
+template <typename T = F64>
+class SampleStatHandle
+: public TraceType<SampleAccumulator>
+{
+public:
+ typedef F64 storage_t;
+ typedef TraceType<SampleAccumulator> trace_t;
+
+ SampleStatHandle(const char* name, const char* description = NULL)
+ : trace_t(name, description)
+ {}
+
+ /*virtual*/ const char* getUnitLabel() { return LLGetUnitLabel<T>::getUnitLabel(); }
+};
+
+template<typename T, typename VALUE_T>
+void sample(SampleStatHandle<T>& measurement, VALUE_T value)
+{
+ T converted_value(value);
+ measurement.getPrimaryAccumulator()->sample(LLUnits::rawValue(converted_value));
+}
+
+template <typename T = F64>
+class CountStatHandle
+: public TraceType<CountAccumulator>
+{
+public:
+ typedef typename F64 storage_t;
+ typedef TraceType<CountAccumulator> trace_t;
+
+ CountStatHandle(const char* name, const char* description = NULL)
+ : trace_t(name)
+ {}
+
+ /*virtual*/ const char* getUnitLabel() { return LLGetUnitLabel<T>::getUnitLabel(); }
+};
+
+template<typename T, typename VALUE_T>
+void add(CountStatHandle<T>& count, VALUE_T value)
+{
+ T converted_value(value);
+ count.getPrimaryAccumulator()->add(LLUnits::rawValue(converted_value));
+}
+
+
+struct MemStatAccumulator
+{
+ typedef MemStatAccumulator self_t;
+
+ // fake classes that allows us to view different facets of underlying statistic
+ struct AllocationCountFacet
+ {
+ typedef U32 value_t;
+ typedef F32 mean_t;
+ };
+
+ struct DeallocationCountFacet
+ {
+ typedef U32 value_t;
+ typedef F32 mean_t;
+ };
+
+ struct ChildMemFacet
+ {
+ typedef LLUnit<LLUnits::Bytes, F64> value_t;
+ typedef LLUnit<LLUnits::Bytes, F64> mean_t;
+ };
+
+ MemStatAccumulator()
+ : mAllocatedCount(0),
+ mDeallocatedCount(0)
+ {}
+
+ void addSamples(const MemStatAccumulator& other, bool append)
+ {
+ mSize.addSamples(other.mSize, append);
+ mChildSize.addSamples(other.mChildSize, append);
+ mAllocatedCount += other.mAllocatedCount;
+ mDeallocatedCount += other.mDeallocatedCount;
+ }
+
+ void reset(const MemStatAccumulator* other)
+ {
+ mSize.reset(other ? &other->mSize : NULL);
+ mChildSize.reset(other ? &other->mChildSize : NULL);
+ mAllocatedCount = 0;
+ mDeallocatedCount = 0;
+ }
+
+ void flush()
+ {
+ mSize.flush();
+ mChildSize.flush();
+ }
+
+ SampleAccumulator mSize,
+ mChildSize;
+ int mAllocatedCount,
+ mDeallocatedCount;
+};
+
+
+template<>
+class TraceType<MemStatAccumulator::AllocationCountFacet>
+: public TraceType<MemStatAccumulator>
+{
+public:
+
+ TraceType(const char* name, const char* description = "")
+ : TraceType<MemStatAccumulator>(name, description)
+ {}
+};
+
+template<>
+class TraceType<MemStatAccumulator::DeallocationCountFacet>
+: public TraceType<MemStatAccumulator>
+{
+public:
+
+ TraceType(const char* name, const char* description = "")
+ : TraceType<MemStatAccumulator>(name, description)
+ {}
+};
+
+template<>
+class TraceType<MemStatAccumulator::ChildMemFacet>
+ : public TraceType<MemStatAccumulator>
+{
+public:
+
+ TraceType(const char* name, const char* description = "")
+ : TraceType<MemStatAccumulator>(name, description)
+ {}
+};
+
+class MemStatHandle : public TraceType<MemStatAccumulator>
+{
+public:
+ typedef TraceType<MemStatAccumulator> trace_t;
+ MemStatHandle(const char* name)
+ : trace_t(name)
+ {}
+
+ /*virtual*/ const char* getUnitLabel() { return "B"; }
+
+ TraceType<MemStatAccumulator::AllocationCountFacet>& allocationCount()
+ {
+ return static_cast<TraceType<MemStatAccumulator::AllocationCountFacet>&>(*(TraceType<MemStatAccumulator>*)this);
+ }
+
+ TraceType<MemStatAccumulator::DeallocationCountFacet>& deallocationCount()
+ {
+ return static_cast<TraceType<MemStatAccumulator::DeallocationCountFacet>&>(*(TraceType<MemStatAccumulator>*)this);
+ }
+
+ TraceType<MemStatAccumulator::ChildMemFacet>& childMem()
+ {
+ return static_cast<TraceType<MemStatAccumulator::ChildMemFacet>&>(*(TraceType<MemStatAccumulator>*)this);
+ }
+};
+
+// measures effective memory footprint of specified type
+// specialize to cover different types
+
+template<typename T>
+struct MemFootprint
+{
+ static size_t measure(const T& value)
+ {
+ return sizeof(T);
+ }
+
+ static size_t measure()
+ {
+ return sizeof(T);
+ }
+};
+
+template<typename T>
+struct MemFootprint<T*>
+{
+ static size_t measure(const T* value)
+ {
+ if (!value)
+ {
+ return 0;
+ }
+ return MemFootprint<T>::measure(*value);
+ }
+
+ static size_t measure()
+ {
+ return MemFootprint<T>::measure();
+ }
+};
+
+template<typename T>
+struct MemFootprint<std::basic_string<T> >
+{
+ static size_t measure(const std::basic_string<T>& value)
+ {
+ return value.capacity() * sizeof(T);
+ }
+
+ static size_t measure()
+ {
+ return sizeof(std::basic_string<T>);
+ }
+};
+
+template<typename T>
+struct MemFootprint<std::vector<T> >
+{
+ static size_t measure(const std::vector<T>& value)
+ {
+ return value.capacity() * MemFootprint<T>::measure();
+ }
+
+ static size_t measure()
+ {
+ return sizeof(std::vector<T>);
+ }
+};
+
+template<typename T>
+struct MemFootprint<std::list<T> >
+{
+ static size_t measure(const std::list<T>& value)
+ {
+ return value.size() * (MemFootprint<T>::measure() + sizeof(void*) * 2);
+ }
+
+ static size_t measure()
+ {
+ return sizeof(std::list<T>);
+ }
+};
+
+template<typename DERIVED, size_t ALIGNMENT = LL_DEFAULT_HEAP_ALIGN>
+class MemTrackable
+{
+ template<typename TRACKED, typename TRACKED_IS_TRACKER>
+ struct TrackMemImpl;
+
+ typedef MemTrackable<DERIVED> mem_trackable_t;
+
+public:
+ typedef void mem_trackable_tag_t;
+
+ virtual ~MemTrackable()
+ {
+ memDisclaim(mMemFootprint);
+ }
+
+ void* operator new(size_t size)
+ {
+ MemStatAccumulator* accumulator = DERIVED::sMemStat.getPrimaryAccumulator();
+ if (accumulator)
+ {
+ accumulator->mSize.sample(accumulator->mSize.getLastValue() + (F64)size);
+ accumulator->mAllocatedCount++;
+ }
+
+ return ::operator new(size);
+ }
+
+ void operator delete(void* ptr, size_t size)
+ {
+ MemStatAccumulator* accumulator = DERIVED::sMemStat.getPrimaryAccumulator();
+ if (accumulator)
+ {
+ accumulator->mSize.sample(accumulator->mSize.getLastValue() - (F64)size);
+ accumulator->mAllocatedCount--;
+ accumulator->mDeallocatedCount++;
+ }
+ ::operator delete(ptr);
+ }
+
+ void *operator new [](size_t size)
+ {
+ MemStatAccumulator* accumulator = DERIVED::sMemStat.getPrimaryAccumulator();
+ if (accumulator)
+ {
+ accumulator->mSize.sample(accumulator->mSize.getLastValue() + (F64)size);
+ accumulator->mAllocatedCount++;
+ }
+
+ return ::operator new[](size);
+ }
+
+ void operator delete[](void* ptr, size_t size)
+ {
+ MemStatAccumulator* accumulator = DERIVED::sMemStat.getPrimaryAccumulator();
+ if (accumulator)
+ {
+ accumulator->mSize.sample(accumulator->mSize.getLastValue() - (F64)size);
+ accumulator->mAllocatedCount--;
+ accumulator->mDeallocatedCount++;
+ }
+ ::operator delete[](ptr);
+ }
+
+ // claim memory associated with other objects/data as our own, adding to our calculated footprint
+ template<typename CLAIM_T>
+ CLAIM_T& memClaim(CLAIM_T& value)
+ {
+ TrackMemImpl<CLAIM_T>::claim(*this, value);
+ return value;
+ }
+
+ template<typename CLAIM_T>
+ const CLAIM_T& memClaim(const CLAIM_T& value)
+ {
+ TrackMemImpl<CLAIM_T>::claim(*this, value);
+ return value;
+ }
+
+
+ void memClaimAmount(size_t size)
+ {
+ MemStatAccumulator* accumulator = DERIVED::sMemStat.getPrimaryAccumulator();
+ mMemFootprint += size;
+ if (accumulator)
+ {
+ accumulator->mSize.sample(accumulator->mSize.getLastValue() + (F64)size);
+ }
+ }
+
+ // remove memory we had claimed from our calculated footprint
+ template<typename CLAIM_T>
+ CLAIM_T& memDisclaim(CLAIM_T& value)
+ {
+ TrackMemImpl<CLAIM_T>::disclaim(*this, value);
+ return value;
+ }
+
+ template<typename CLAIM_T>
+ const CLAIM_T& memDisclaim(const CLAIM_T& value)
+ {
+ TrackMemImpl<CLAIM_T>::disclaim(*this, value);
+ return value;
+ }
+
+ void memDisclaimAmount(size_t size)
+ {
+ MemStatAccumulator* accumulator = DERIVED::sMemStat.getPrimaryAccumulator();
+ if (accumulator)
+ {
+ accumulator->mSize.sample(accumulator->mSize.getLastValue() - (F64)size);
+ }
+ }
+
+private:
+ size_t mMemFootprint;
+
+ template<typename TRACKED, typename TRACKED_IS_TRACKER = void>
+ struct TrackMemImpl
+ {
+ static void claim(mem_trackable_t& tracker, const TRACKED& tracked)
+ {
+ MemStatAccumulator* accumulator = DERIVED::sMemStat.getPrimaryAccumulator();
+ if (accumulator)
+ {
+ size_t footprint = MemFootprint<TRACKED>::measure(tracked);
+ accumulator->mSize.sample(accumulator->mSize.getLastValue() + (F64)footprint);
+ tracker.mMemFootprint += footprint;
+ }
+ }
+
+ static void disclaim(mem_trackable_t& tracker, const TRACKED& tracked)
+ {
+ MemStatAccumulator* accumulator = DERIVED::sMemStat.getPrimaryAccumulator();
+ if (accumulator)
+ {
+ size_t footprint = MemFootprint<TRACKED>::measure(tracked);
+ accumulator->mSize.sample(accumulator->mSize.getLastValue() - (F64)footprint);
+ tracker.mMemFootprint -= footprint;
+ }
+ }
+ };
+
+ template<typename TRACKED>
+ struct TrackMemImpl<TRACKED, typename TRACKED::mem_trackable_tag_t>
+ {
+ static void claim(mem_trackable_t& tracker, TRACKED& tracked)
+ {
+ MemStatAccumulator* accumulator = DERIVED::sMemStat.getPrimaryAccumulator();
+ if (accumulator)
+ {
+ accumulator->mChildSize.sample(accumulator->mChildSize.getLastValue() + (F64)MemFootprint<TRACKED>::measure(tracked));
+ }
+ }
+
+ static void disclaim(mem_trackable_t& tracker, TRACKED& tracked)
+ {
+ MemStatAccumulator* accumulator = DERIVED::sMemStat.getPrimaryAccumulator();
+ if (accumulator)
+ {
+ accumulator->mChildSize.sample(accumulator->mChildSize.getLastValue() - (F64)MemFootprint<TRACKED>::measure(tracked));
+ }
+ }
+ };
+};
+
+}
+#endif // LL_LLTRACE_H
diff --git a/indra/llcommon/lltracerecording.cpp b/indra/llcommon/lltracerecording.cpp
new file mode 100644
index 0000000000..d32504b014
--- /dev/null
+++ b/indra/llcommon/lltracerecording.cpp
@@ -0,0 +1,944 @@
+/**
+ * @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 "lltrace.h"
+#include "llfasttimer.h"
+#include "lltracerecording.h"
+#include "lltracethreadrecorder.h"
+#include "llthread.h"
+
+namespace LLTrace
+{
+
+
+///////////////////////////////////////////////////////////////////////
+// RecordingBuffers
+///////////////////////////////////////////////////////////////////////
+
+RecordingBuffers::RecordingBuffers()
+{}
+
+void RecordingBuffers::handOffTo(RecordingBuffers& other)
+{
+ other.mCounts.reset(&mCounts);
+ other.mSamples.reset(&mSamples);
+ other.mEvents.reset(&mEvents);
+ other.mStackTimers.reset(&mStackTimers);
+ other.mMemStats.reset(&mMemStats);
+}
+
+void RecordingBuffers::makePrimary()
+{
+ mCounts.makePrimary();
+ mSamples.makePrimary();
+ mEvents.makePrimary();
+ mStackTimers.makePrimary();
+ mMemStats.makePrimary();
+
+ 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;
+ }
+ }
+}
+
+bool RecordingBuffers::isPrimary() const
+{
+ return mCounts.isPrimary();
+}
+
+void RecordingBuffers::append( const RecordingBuffers& other )
+{
+ mCounts.addSamples(other.mCounts);
+ mSamples.addSamples(other.mSamples);
+ mEvents.addSamples(other.mEvents);
+ mMemStats.addSamples(other.mMemStats);
+ mStackTimers.addSamples(other.mStackTimers);
+}
+
+void RecordingBuffers::merge( const RecordingBuffers& other)
+{
+ mCounts.addSamples(other.mCounts, false);
+ mSamples.addSamples(other.mSamples, false);
+ mEvents.addSamples(other.mEvents, false);
+ mMemStats.addSamples(other.mMemStats, false);
+ // for now, hold out timers from merge, need to be displayed per thread
+ //mStackTimers.addSamples(other.mStackTimers, false);
+}
+
+void RecordingBuffers::reset(RecordingBuffers* 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 RecordingBuffers::flush()
+{
+ mSamples.flush();
+}
+
+///////////////////////////////////////////////////////////////////////
+// Recording
+///////////////////////////////////////////////////////////////////////
+
+Recording::Recording()
+: mElapsedSeconds(0)
+{
+ mBuffers = new RecordingBuffers();
+}
+
+Recording::Recording( const Recording& other )
+{
+ // this will allow us to seamlessly start without affecting any data we've acquired from other
+ setPlayState(PAUSED);
+
+ Recording& mutable_other = const_cast<Recording&>(other);
+ EPlayState other_play_state = other.getPlayState();
+ mutable_other.pause();
+
+ mBuffers = other.mBuffers;
+
+ LLStopWatchControlsMixin<Recording>::setPlayState(other_play_state);
+ mutable_other.setPlayState(other_play_state);
+
+ // above call will clear mElapsedSeconds as a side effect, so copy it here
+ mElapsedSeconds = other.mElapsedSeconds;
+ mSamplingTimer = other.mSamplingTimer;
+}
+
+
+Recording::~Recording()
+{
+ if (isStarted() && LLTrace::get_thread_recorder().notNull())
+ {
+ LLTrace::get_thread_recorder()->deactivate(this);
+ }
+}
+
+void Recording::update()
+{
+ if (isStarted())
+ {
+ mBuffers.write()->flush();
+ LLTrace::get_thread_recorder()->bringUpToDate(this);
+ mSamplingTimer.reset();
+ }
+}
+
+void Recording::handleReset()
+{
+ mBuffers.write()->reset();
+
+ mElapsedSeconds = 0.0;
+ mSamplingTimer.reset();
+}
+
+void Recording::handleStart()
+{
+ mSamplingTimer.reset();
+ LLTrace::get_thread_recorder()->activate(this);
+}
+
+void Recording::handleStop()
+{
+ mElapsedSeconds += mSamplingTimer.getElapsedTimeF64();
+ mBuffers.write()->flush();
+ LLTrace::get_thread_recorder()->deactivate(this);
+}
+
+void Recording::handleSplitTo(Recording& other)
+{
+ mBuffers.write()->handOffTo(*other.mBuffers.write());
+}
+
+void Recording::appendRecording( const Recording& other )
+{
+ EPlayState play_state = getPlayState();
+ {
+ pause();
+ mBuffers.write()->append(*other.mBuffers);
+ mElapsedSeconds += other.mElapsedSeconds;
+ }
+ setPlayState(play_state);
+}
+
+void Recording::mergeRecording( const Recording& other)
+{
+ EPlayState play_state = getPlayState();
+ {
+ pause();
+ mBuffers.write()->merge(*other.mBuffers);
+ }
+ setPlayState(play_state);
+}
+
+LLUnit<LLUnits::Seconds, F64> Recording::getSum(const TraceType<TimeBlockAccumulator>& stat)
+{
+ const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()];
+ update();
+ return (F64)(accumulator.mTotalTimeCounter - accumulator.mStartTotalTimeCounter)
+ / (F64)LLTrace::TimeBlock::countsPerSecond();
+}
+
+LLUnit<LLUnits::Seconds, F64> Recording::getSum(const TraceType<TimeBlockAccumulator::SelfTimeFacet>& stat)
+{
+ const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()];
+ update();
+ return (F64)(accumulator.mSelfTimeCounter) / (F64)LLTrace::TimeBlock::countsPerSecond();
+}
+
+
+U32 Recording::getSum(const TraceType<TimeBlockAccumulator::CallCountFacet>& stat)
+{
+ update();
+ return mBuffers->mStackTimers[stat.getIndex()].mCalls;
+}
+
+LLUnit<LLUnits::Seconds, F64> Recording::getPerSec(const TraceType<TimeBlockAccumulator>& stat)
+{
+ const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()];
+
+ update();
+ return (F64)(accumulator.mTotalTimeCounter - accumulator.mStartTotalTimeCounter)
+ / ((F64)LLTrace::TimeBlock::countsPerSecond() * mElapsedSeconds);
+}
+
+LLUnit<LLUnits::Seconds, F64> Recording::getPerSec(const TraceType<TimeBlockAccumulator::SelfTimeFacet>& stat)
+{
+ const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()];
+
+ update();
+ return (F64)(accumulator.mSelfTimeCounter)
+ / ((F64)LLTrace::TimeBlock::countsPerSecond() * mElapsedSeconds);
+}
+
+F32 Recording::getPerSec(const TraceType<TimeBlockAccumulator::CallCountFacet>& stat)
+{
+ update();
+ return (F32)mBuffers->mStackTimers[stat.getIndex()].mCalls / mElapsedSeconds;
+}
+
+LLUnit<LLUnits::Bytes, F64> Recording::getMin(const TraceType<MemStatAccumulator>& stat)
+{
+ update();
+ return mBuffers->mMemStats[stat.getIndex()].mSize.getMin();
+}
+
+LLUnit<LLUnits::Bytes, F64> Recording::getMean(const TraceType<MemStatAccumulator>& stat)
+{
+ update();
+ return mBuffers->mMemStats[stat.getIndex()].mSize.getMean();
+}
+
+LLUnit<LLUnits::Bytes, F64> Recording::getMax(const TraceType<MemStatAccumulator>& stat)
+{
+ update();
+ return mBuffers->mMemStats[stat.getIndex()].mSize.getMax();
+}
+
+LLUnit<LLUnits::Bytes, F64> Recording::getStandardDeviation(const TraceType<MemStatAccumulator>& stat)
+{
+ update();
+ return mBuffers->mMemStats[stat.getIndex()].mSize.getStandardDeviation();
+}
+
+LLUnit<LLUnits::Bytes, F64> Recording::getLastValue(const TraceType<MemStatAccumulator>& stat)
+{
+ update();
+ return mBuffers->mMemStats[stat.getIndex()].mSize.getLastValue();
+}
+
+LLUnit<LLUnits::Bytes, F64> Recording::getMin(const TraceType<MemStatAccumulator::ChildMemFacet>& stat)
+{
+ update();
+ return mBuffers->mMemStats[stat.getIndex()].mChildSize.getMin();
+}
+
+LLUnit<LLUnits::Bytes, F64> Recording::getMean(const TraceType<MemStatAccumulator::ChildMemFacet>& stat)
+{
+ update();
+ return mBuffers->mMemStats[stat.getIndex()].mChildSize.getMean();
+}
+
+LLUnit<LLUnits::Bytes, F64> Recording::getMax(const TraceType<MemStatAccumulator::ChildMemFacet>& stat)
+{
+ update();
+ return mBuffers->mMemStats[stat.getIndex()].mChildSize.getMax();
+}
+
+LLUnit<LLUnits::Bytes, F64> Recording::getStandardDeviation(const TraceType<MemStatAccumulator::ChildMemFacet>& stat)
+{
+ update();
+ return mBuffers->mMemStats[stat.getIndex()].mChildSize.getStandardDeviation();
+}
+
+LLUnit<LLUnits::Bytes, F64> Recording::getLastValue(const TraceType<MemStatAccumulator::ChildMemFacet>& stat)
+{
+ update();
+ return mBuffers->mMemStats[stat.getIndex()].mChildSize.getLastValue();
+}
+
+U32 Recording::getSum(const TraceType<MemStatAccumulator::AllocationCountFacet>& stat)
+{
+ update();
+ return mBuffers->mMemStats[stat.getIndex()].mAllocatedCount;
+}
+
+U32 Recording::getSum(const TraceType<MemStatAccumulator::DeallocationCountFacet>& stat)
+{
+ update();
+ return mBuffers->mMemStats[stat.getIndex()].mAllocatedCount;
+}
+
+
+F64 Recording::getSum( const TraceType<CountAccumulator>& stat )
+{
+ update();
+ return mBuffers->mCounts[stat.getIndex()].getSum();
+}
+
+F64 Recording::getSum( const TraceType<EventAccumulator>& stat )
+{
+ update();
+ return (F64)mBuffers->mEvents[stat.getIndex()].getSum();
+}
+
+F64 Recording::getPerSec( const TraceType<CountAccumulator>& stat )
+{
+ update();
+ F64 sum = mBuffers->mCounts[stat.getIndex()].getSum();
+ return (sum != 0.0)
+ ? (sum / mElapsedSeconds)
+ : 0.0;
+}
+
+U32 Recording::getSampleCount( const TraceType<CountAccumulator>& stat )
+{
+ update();
+ return mBuffers->mCounts[stat.getIndex()].getSampleCount();
+}
+
+F64 Recording::getMin( const TraceType<SampleAccumulator>& stat )
+{
+ update();
+ return mBuffers->mSamples[stat.getIndex()].getMin();
+}
+
+F64 Recording::getMax( const TraceType<SampleAccumulator>& stat )
+{
+ update();
+ return mBuffers->mSamples[stat.getIndex()].getMax();
+}
+
+F64 Recording::getMean( const TraceType<SampleAccumulator>& stat )
+{
+ update();
+ return mBuffers->mSamples[stat.getIndex()].getMean();
+}
+
+F64 Recording::getStandardDeviation( const TraceType<SampleAccumulator>& stat )
+{
+ update();
+ return mBuffers->mSamples[stat.getIndex()].getStandardDeviation();
+}
+
+F64 Recording::getLastValue( const TraceType<SampleAccumulator>& stat )
+{
+ update();
+ return mBuffers->mSamples[stat.getIndex()].getLastValue();
+}
+
+U32 Recording::getSampleCount( const TraceType<SampleAccumulator>& stat )
+{
+ update();
+ return mBuffers->mSamples[stat.getIndex()].getSampleCount();
+}
+
+F64 Recording::getMin( const TraceType<EventAccumulator>& stat )
+{
+ update();
+ return mBuffers->mEvents[stat.getIndex()].getMin();
+}
+
+F64 Recording::getMax( const TraceType<EventAccumulator>& stat )
+{
+ update();
+ return mBuffers->mEvents[stat.getIndex()].getMax();
+}
+
+F64 Recording::getMean( const TraceType<EventAccumulator>& stat )
+{
+ update();
+ return mBuffers->mEvents[stat.getIndex()].getMean();
+}
+
+F64 Recording::getStandardDeviation( const TraceType<EventAccumulator>& stat )
+{
+ update();
+ return mBuffers->mEvents[stat.getIndex()].getStandardDeviation();
+}
+
+F64 Recording::getLastValue( const TraceType<EventAccumulator>& stat )
+{
+ update();
+ return mBuffers->mEvents[stat.getIndex()].getLastValue();
+}
+
+U32 Recording::getSampleCount( const TraceType<EventAccumulator>& stat )
+{
+ update();
+ return mBuffers->mEvents[stat.getIndex()].getSampleCount();
+}
+
+///////////////////////////////////////////////////////////////////////
+// PeriodicRecording
+///////////////////////////////////////////////////////////////////////
+
+PeriodicRecording::PeriodicRecording( U32 num_periods, EPlayState state)
+: mAutoResize(num_periods == 0),
+ mCurPeriod(0),
+ mRecordingPeriods(num_periods ? num_periods : 1)
+{
+ setPlayState(state);
+}
+
+void PeriodicRecording::nextPeriod()
+{
+ if (mAutoResize)
+ {
+ mRecordingPeriods.push_back(Recording());
+ }
+
+ Recording& old_recording = getCurRecording();
+
+ mCurPeriod = (mCurPeriod + 1) % mRecordingPeriods.size();
+ old_recording.splitTo(getCurRecording());
+}
+
+
+void PeriodicRecording::appendPeriodicRecording( PeriodicRecording& other )
+{
+ if (other.mRecordingPeriods.empty()) return;
+
+ EPlayState play_state = getPlayState();
+ pause();
+
+ EPlayState other_play_state = other.getPlayState();
+ other.pause();
+
+ U32 other_recording_count = other.mRecordingPeriods.size();
+
+ Recording& other_oldest_recording = other.mRecordingPeriods[(other.mCurPeriod + 1) % other.mRecordingPeriods.size()];
+
+ // if I have a recording of any length, then close it off and start a fresh one
+ if (getCurRecording().getDuration().value())
+ {
+ nextPeriod();
+ }
+ getCurRecording().appendRecording(other_oldest_recording);
+
+ if (other_recording_count > 1)
+ {
+ if (mAutoResize)
+ {
+ for (S32 other_index = (other.mCurPeriod + 2) % other_recording_count,
+ end_index = (other.mCurPeriod + 1) % other_recording_count;
+ other_index != end_index;
+ other_index = (other_index + 1) % other_recording_count)
+ {
+ llassert(other.mRecordingPeriods[other_index].getDuration() != 0.f
+ && (mRecordingPeriods.empty()
+ || other.mRecordingPeriods[other_index].getDuration() != mRecordingPeriods.back().getDuration()));
+ mRecordingPeriods.push_back(other.mRecordingPeriods[other_index]);
+ }
+
+ mCurPeriod = mRecordingPeriods.size() - 1;
+ }
+ else
+ {
+ size_t num_to_copy = llmin( mRecordingPeriods.size(), other.mRecordingPeriods.size() - 1);
+ std::vector<Recording>::iterator src_it = other.mRecordingPeriods.begin()
+ + ( (other.mCurPeriod + 1 // oldest period
+ + (other.mRecordingPeriods.size() - num_to_copy)) // minus room for copy
+ % other.mRecordingPeriods.size());
+ std::vector<Recording>::iterator dest_it = mRecordingPeriods.begin() + ((mCurPeriod + 1) % mRecordingPeriods.size());
+
+ for(S32 i = 0; 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();
+ }
+ }
+
+ mCurPeriod = (mCurPeriod + num_to_copy) % mRecordingPeriods.size();
+ }
+ }
+
+ nextPeriod();
+
+ setPlayState(play_state);
+ other.setPlayState(other_play_state);
+}
+
+LLUnit<LLUnits::Seconds, F64> PeriodicRecording::getDuration() const
+{
+ LLUnit<LLUnits::Seconds, F64> duration;
+ size_t num_periods = mRecordingPeriods.size();
+ for (size_t i = 1; i <= num_periods; i++)
+ {
+ size_t 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( U32 offset )
+{
+ U32 num_periods = mRecordingPeriods.size();
+ offset = llclamp(offset, 0u, num_periods - 1);
+ return mRecordingPeriods[(mCurPeriod + num_periods - offset) % num_periods];
+}
+
+const Recording& PeriodicRecording::getPrevRecording( U32 offset ) const
+{
+ U32 num_periods = mRecordingPeriods.size();
+ offset = llclamp(offset, 0u, num_periods - 1);
+ return mRecordingPeriods[(mCurPeriod + num_periods - offset) % num_periods];
+}
+
+void PeriodicRecording::handleStart()
+{
+ getCurRecording().start();
+}
+
+void PeriodicRecording::handleStop()
+{
+ getCurRecording().pause();
+}
+
+void PeriodicRecording::handleReset()
+{
+ 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;
+ getCurRecording().setPlayState(getPlayState());
+}
+
+void PeriodicRecording::handleSplitTo(PeriodicRecording& other)
+{
+ getCurRecording().splitTo(other.getCurRecording());
+}
+
+
+F64 PeriodicRecording::getPeriodMean( const TraceType<EventAccumulator>& stat, size_t num_periods /*= U32_MAX*/ )
+{
+ size_t total_periods = mRecordingPeriods.size();
+ num_periods = llmin(num_periods, total_periods);
+
+ F64 mean = 0;
+ if (num_periods <= 0) { return mean; }
+
+ S32 total_sample_count = 0;
+
+ for (S32 i = 1; i <= num_periods; i++)
+ {
+ S32 index = (mCurPeriod + total_periods - i) % total_periods;
+ if (mRecordingPeriods[index].getDuration() > 0.f)
+ {
+ S32 period_sample_count = mRecordingPeriods[index].getSampleCount(stat);
+ mean += mRecordingPeriods[index].getMean(stat) * period_sample_count;
+ total_sample_count += period_sample_count;
+ }
+ }
+
+ if (total_sample_count)
+ {
+ mean = mean / total_sample_count;
+ }
+ return mean;
+}
+
+F64 PeriodicRecording::getPeriodMin( const TraceType<EventAccumulator>& stat, size_t num_periods /*= U32_MAX*/ )
+{
+ size_t total_periods = mRecordingPeriods.size();
+ num_periods = llmin(num_periods, total_periods);
+
+ F64 min_val = std::numeric_limits<F64>::max();
+ for (S32 i = 1; i <= num_periods; i++)
+ {
+ S32 index = (mCurPeriod + total_periods - i) % total_periods;
+ min_val = llmin(min_val, mRecordingPeriods[index].getMin(stat));
+ }
+ return min_val;
+}
+
+F64 PeriodicRecording::getPeriodMax( const TraceType<EventAccumulator>& stat, size_t num_periods /*= U32_MAX*/ )
+{
+ size_t total_periods = mRecordingPeriods.size();
+ num_periods = llmin(num_periods, total_periods);
+
+ F64 max_val = std::numeric_limits<F64>::min();
+ for (S32 i = 1; i <= num_periods; i++)
+ {
+ S32 index = (mCurPeriod + total_periods - i) % total_periods;
+ max_val = llmax(max_val, mRecordingPeriods[index].getMax(stat));
+ }
+ return max_val;
+}
+
+F64 PeriodicRecording::getPeriodMin( const TraceType<SampleAccumulator>& stat, size_t num_periods /*= U32_MAX*/ )
+{
+ size_t total_periods = mRecordingPeriods.size();
+ num_periods = llmin(num_periods, total_periods);
+
+ F64 min_val = std::numeric_limits<F64>::max();
+ for (S32 i = 1; i <= num_periods; i++)
+ {
+ S32 index = (mCurPeriod + total_periods - i) % total_periods;
+ min_val = llmin(min_val, mRecordingPeriods[index].getMin(stat));
+ }
+ return min_val;
+}
+
+F64 PeriodicRecording::getPeriodMax(const TraceType<SampleAccumulator>& stat, size_t num_periods /*= U32_MAX*/)
+{
+ size_t total_periods = mRecordingPeriods.size();
+ num_periods = llmin(num_periods, total_periods);
+
+ F64 max_val = std::numeric_limits<F64>::min();
+ for (S32 i = 1; i <= num_periods; i++)
+ {
+ S32 index = (mCurPeriod + total_periods - i) % total_periods;
+ max_val = llmax(max_val, mRecordingPeriods[index].getMax(stat));
+ }
+ return max_val;
+}
+
+
+F64 PeriodicRecording::getPeriodMean( const TraceType<SampleAccumulator>& stat, size_t num_periods /*= U32_MAX*/ )
+{
+ size_t total_periods = mRecordingPeriods.size();
+ num_periods = llmin(num_periods, total_periods);
+
+ LLUnit<LLUnits::Seconds, F64> total_duration = 0.f;
+
+ F64 mean = 0;
+ if (num_periods <= 0) { return mean; }
+
+ for (S32 i = 1; i <= num_periods; i++)
+ {
+ S32 index = (mCurPeriod + total_periods - i) % total_periods;
+ if (mRecordingPeriods[index].getDuration() > 0.f)
+ {
+ LLUnit<LLUnits::Seconds, F64> recording_duration = mRecordingPeriods[index].getDuration();
+ mean += mRecordingPeriods[index].getMean(stat) * recording_duration.value();
+ total_duration += recording_duration;
+ }
+ }
+
+ if (total_duration.value())
+ {
+ mean = mean / total_duration;
+ }
+ return mean;
+}
+
+
+
+///////////////////////////////////////////////////////////////////////
+// ExtendableRecording
+///////////////////////////////////////////////////////////////////////
+
+void ExtendableRecording::extend()
+{
+ // stop recording to get latest data
+ mPotentialRecording.stop();
+ // push the data back to accepted recording
+ mAcceptedRecording.appendRecording(mPotentialRecording);
+ // flush data, so we can start from scratch
+ mPotentialRecording.reset();
+ // go back to play state we were in initially
+ mPotentialRecording.setPlayState(getPlayState());
+}
+
+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()
+{
+ llassert(mPotentialRecording.getPlayState() == getPlayState());
+ // stop recording to get latest data
+ mPotentialRecording.pause();
+ // push the data back to accepted recording
+ mAcceptedRecording.appendPeriodicRecording(mPotentialRecording);
+ // flush data, so we can start from scratch
+ mPotentialRecording.reset();
+ // go back to play state we were in initially
+ mPotentialRecording.setPlayState(getPlayState());
+}
+
+
+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(1000, PeriodicRecording::STARTED));
+ return *sRecording;
+}
+
+}
+
+void LLStopWatchControlsMixinCommon::start()
+{
+ switch (mPlayState)
+ {
+ case STOPPED:
+ handleReset();
+ handleStart();
+ break;
+ case PAUSED:
+ handleStart();
+ break;
+ case STARTED:
+ handleReset();
+ break;
+ default:
+ llassert(false);
+ break;
+ }
+ mPlayState = STARTED;
+}
+
+void LLStopWatchControlsMixinCommon::stop()
+{
+ switch (mPlayState)
+ {
+ case STOPPED:
+ break;
+ case PAUSED:
+ break;
+ case STARTED:
+ handleStop();
+ break;
+ default:
+ llassert(false);
+ break;
+ }
+ mPlayState = STOPPED;
+}
+
+void LLStopWatchControlsMixinCommon::pause()
+{
+ switch (mPlayState)
+ {
+ case STOPPED:
+ break;
+ case PAUSED:
+ break;
+ case STARTED:
+ handleStop();
+ break;
+ default:
+ llassert(false);
+ break;
+ }
+ mPlayState = PAUSED;
+}
+
+void LLStopWatchControlsMixinCommon::resume()
+{
+ switch (mPlayState)
+ {
+ case STOPPED:
+ handleStart();
+ break;
+ case PAUSED:
+ handleStart();
+ break;
+ case STARTED:
+ break;
+ default:
+ llassert(false);
+ break;
+ }
+ mPlayState = STARTED;
+}
+
+void LLStopWatchControlsMixinCommon::restart()
+{
+ switch (mPlayState)
+ {
+ case STOPPED:
+ handleReset();
+ handleStart();
+ break;
+ case PAUSED:
+ handleReset();
+ handleStart();
+ break;
+ case STARTED:
+ handleReset();
+ break;
+ default:
+ llassert(false);
+ break;
+ }
+ mPlayState = STARTED;
+}
+
+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..4651bfcb61
--- /dev/null
+++ b/indra/llcommon/lltracerecording.h
@@ -0,0 +1,527 @@
+/**
+ * @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 "llpointer.h"
+#include "lltimer.h"
+#include "lltrace.h"
+
+class LLStopWatchControlsMixinCommon
+{
+public:
+ virtual ~LLStopWatchControlsMixinCommon() {}
+
+ enum EPlayState
+ {
+ STOPPED,
+ PAUSED,
+ STARTED
+ };
+
+ void start();
+ void stop();
+ void pause();
+ void resume();
+ void restart();
+ void reset();
+
+ 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:
+ // trigger active behavior (without reset)
+ virtual void handleStart() = 0;
+ // stop active behavior
+ virtual void handleStop() = 0;
+ // clear accumulated state, can 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:
+ // 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
+{
+ struct RecordingBuffers : public LLRefCount
+ {
+ RecordingBuffers();
+
+ void handOffTo(RecordingBuffers& other);
+ void makePrimary();
+ bool isPrimary() const;
+
+ void append(const RecordingBuffers& other);
+ void merge(const RecordingBuffers& other);
+ void reset(RecordingBuffers* other = NULL);
+ void flush();
+
+ AccumulatorBuffer<CountAccumulator> mCounts;
+ AccumulatorBuffer<SampleAccumulator> mSamples;
+ AccumulatorBuffer<EventAccumulator> mEvents;
+ AccumulatorBuffer<TimeBlockAccumulator> mStackTimers;
+ AccumulatorBuffer<MemStatAccumulator> mMemStats;
+ };
+
+ class Recording
+ : public LLStopWatchControlsMixin<Recording>
+ {
+ public:
+ Recording();
+
+ Recording(const Recording& other);
+ ~Recording();
+
+ // accumulate data from subsequent, non-overlapping recording
+ void appendRecording(const Recording& other);
+
+ // gather data from recording, ignoring time relationship (for example, pulling data from slave threads)
+ void mergeRecording(const Recording& other);
+
+ // grab latest recorded data
+ void update();
+
+ // ensure that buffers are exclusively owned by this recording
+ void makeUnique() { mBuffers.makeUnique(); }
+
+ // Timer accessors
+ LLUnit<LLUnits::Seconds, F64> getSum(const TraceType<TimeBlockAccumulator>& stat);
+ LLUnit<LLUnits::Seconds, F64> getSum(const TraceType<TimeBlockAccumulator::SelfTimeFacet>& stat);
+ U32 getSum(const TraceType<TimeBlockAccumulator::CallCountFacet>& stat);
+
+ LLUnit<LLUnits::Seconds, F64> getPerSec(const TraceType<TimeBlockAccumulator>& stat);
+ LLUnit<LLUnits::Seconds, F64> getPerSec(const TraceType<TimeBlockAccumulator::SelfTimeFacet>& stat);
+ F32 getPerSec(const TraceType<TimeBlockAccumulator::CallCountFacet>& stat);
+
+ // Memory accessors
+ LLUnit<LLUnits::Bytes, F64> getMin(const TraceType<MemStatAccumulator>& stat);
+ LLUnit<LLUnits::Bytes, F64> getMean(const TraceType<MemStatAccumulator>& stat);
+ LLUnit<LLUnits::Bytes, F64> getMax(const TraceType<MemStatAccumulator>& stat);
+ LLUnit<LLUnits::Bytes, F64> getStandardDeviation(const TraceType<MemStatAccumulator>& stat);
+ LLUnit<LLUnits::Bytes, F64> getLastValue(const TraceType<MemStatAccumulator>& stat);
+
+ LLUnit<LLUnits::Bytes, F64> getMin(const TraceType<MemStatAccumulator::ChildMemFacet>& stat);
+ LLUnit<LLUnits::Bytes, F64> getMean(const TraceType<MemStatAccumulator::ChildMemFacet>& stat);
+ LLUnit<LLUnits::Bytes, F64> getMax(const TraceType<MemStatAccumulator::ChildMemFacet>& stat);
+ LLUnit<LLUnits::Bytes, F64> getStandardDeviation(const TraceType<MemStatAccumulator::ChildMemFacet>& stat);
+ LLUnit<LLUnits::Bytes, F64> getLastValue(const TraceType<MemStatAccumulator::ChildMemFacet>& stat);
+
+ U32 getSum(const TraceType<MemStatAccumulator::AllocationCountFacet>& stat);
+ U32 getSum(const TraceType<MemStatAccumulator::DeallocationCountFacet>& stat);
+
+ // CountStatHandle accessors
+ F64 getSum(const TraceType<CountAccumulator>& stat);
+ template <typename T>
+ T getSum(const CountStatHandle<T>& stat)
+ {
+ return (T)getSum(static_cast<const TraceType<CountAccumulator>&> (stat));
+ }
+
+ F64 getPerSec(const TraceType<CountAccumulator>& stat);
+ template <typename T>
+ T getPerSec(const CountStatHandle<T>& stat)
+ {
+ return (T)getPerSec(static_cast<const TraceType<CountAccumulator>&> (stat));
+ }
+
+ U32 getSampleCount(const TraceType<CountAccumulator>& stat);
+
+
+ // SampleStatHandle accessors
+ F64 getMin(const TraceType<SampleAccumulator>& stat);
+ template <typename T>
+ T getMin(const SampleStatHandle<T>& stat)
+ {
+ return (T)getMin(static_cast<const TraceType<SampleAccumulator>&> (stat));
+ }
+
+ F64 getMean(const TraceType<SampleAccumulator>& stat);
+ template <typename T>
+ T getMean(SampleStatHandle<T>& stat)
+ {
+ return (T)getMean(static_cast<const TraceType<SampleAccumulator>&> (stat));
+ }
+
+ F64 getMax(const TraceType<SampleAccumulator>& stat);
+ template <typename T>
+ T getMax(const SampleStatHandle<T>& stat)
+ {
+ return (T)getMax(static_cast<const TraceType<SampleAccumulator>&> (stat));
+ }
+
+ F64 getStandardDeviation(const TraceType<SampleAccumulator>& stat);
+ template <typename T>
+ T getStandardDeviation(const SampleStatHandle<T>& stat)
+ {
+ return (T)getStandardDeviation(static_cast<const TraceType<SampleAccumulator>&> (stat));
+ }
+
+ F64 getLastValue(const TraceType<SampleAccumulator>& stat);
+ template <typename T>
+ T getLastValue(const SampleStatHandle<T>& stat)
+ {
+ return (T)getLastValue(static_cast<const TraceType<SampleAccumulator>&> (stat));
+ }
+
+ U32 getSampleCount(const TraceType<SampleAccumulator>& stat);
+
+ // EventStatHandle accessors
+ F64 getSum(const TraceType<EventAccumulator>& stat);
+ template <typename T>
+ T getSum(const EventStatHandle<T>& stat)
+ {
+ return (T)getSum(static_cast<const TraceType<EventAccumulator>&> (stat));
+ }
+
+ F64 getMin(const TraceType<EventAccumulator>& stat);
+ template <typename T>
+ T getMin(const EventStatHandle<T>& stat)
+ {
+ return (T)getMin(static_cast<const TraceType<EventAccumulator>&> (stat));
+ }
+
+ F64 getMax(const TraceType<EventAccumulator>& stat);
+ template <typename T>
+ T getMax(const EventStatHandle<T>& stat)
+ {
+ return (T)getMax(static_cast<const TraceType<EventAccumulator>&> (stat));
+ }
+
+ F64 getMean(const TraceType<EventAccumulator>& stat);
+ template <typename T>
+ T getMean(EventStatHandle<T>& stat)
+ {
+ return (T)getMean(static_cast<const TraceType<EventAccumulator>&> (stat));
+ }
+
+ F64 getStandardDeviation(const TraceType<EventAccumulator>& stat);
+ template <typename T>
+ T getStandardDeviation(const EventStatHandle<T>& stat)
+ {
+ return (T)getStandardDeviation(static_cast<const TraceType<EventAccumulator>&> (stat));
+ }
+
+ F64 getLastValue(const TraceType<EventAccumulator>& stat);
+ template <typename T>
+ T getLastValue(const EventStatHandle<T>& stat)
+ {
+ return (T)getLastValue(static_cast<const TraceType<EventAccumulator>&> (stat));
+ }
+
+ U32 getSampleCount(const TraceType<EventAccumulator>& stat);
+
+ LLUnit<LLUnits::Seconds, F64> getDuration() const { return LLUnit<LLUnits::Seconds, F64>(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;
+ F64 mElapsedSeconds;
+ LLCopyOnWritePointer<RecordingBuffers> mBuffers;
+ };
+
+ class LL_COMMON_API PeriodicRecording
+ : public LLStopWatchControlsMixin<PeriodicRecording>
+ {
+ public:
+ PeriodicRecording(U32 num_periods, EPlayState state = STOPPED);
+
+ void nextPeriod();
+ U32 getNumPeriods() { return mRecordingPeriods.size(); }
+
+ LLUnit<LLUnits::Seconds, F64> getDuration() const;
+
+ void appendPeriodicRecording(PeriodicRecording& other);
+ Recording& getLastRecording();
+ const Recording& getLastRecording() const;
+ Recording& getCurRecording();
+ const Recording& getCurRecording() const;
+ Recording& getPrevRecording(U32 offset);
+ const Recording& getPrevRecording(U32 offset) const;
+ Recording snapshotCurRecording() const;
+
+ // catch all for stats that have a defined sum
+ template <typename T>
+ typename T::value_t getPeriodMin(const TraceType<T>& stat, size_t num_periods = U32_MAX)
+ {
+ size_t total_periods = mRecordingPeriods.size();
+ num_periods = llmin(num_periods, total_periods);
+
+ typename T::value_t min_val = std::numeric_limits<typename T::value_t>::max();
+ for (S32 i = 1; i <= num_periods; i++)
+ {
+ S32 index = (mCurPeriod + total_periods - i) % total_periods;
+ min_val = llmin(min_val, mRecordingPeriods[index].getSum(stat));
+ }
+ return min_val;
+ }
+
+ F64 getPeriodMin(const TraceType<SampleAccumulator>& stat, size_t num_periods = U32_MAX);
+ template<typename T>
+ T getPeriodMin(const SampleStatHandle<T>& stat, size_t num_periods = U32_MAX)
+ {
+ return T(getPeriodMin(static_cast<const TraceType<SampleAccumulator>&>(stat), num_periods));
+ }
+
+ F64 getPeriodMin(const TraceType<EventAccumulator>& stat, size_t num_periods = U32_MAX);
+ template<typename T>
+ T getPeriodMin(const EventStatHandle<T>& stat, size_t num_periods = U32_MAX)
+ {
+ return T(getPeriodMin(static_cast<const TraceType<EventAccumulator>&>(stat), num_periods));
+ }
+
+ template <typename T>
+ F64 getPeriodMinPerSec(const TraceType<T>& stat, size_t num_periods = U32_MAX)
+ {
+ size_t total_periods = mRecordingPeriods.size();
+ num_periods = llmin(num_periods, total_periods);
+
+ F64 min_val = std::numeric_limits<F64>::max();
+ for (S32 i = 1; i <= num_periods; i++)
+ {
+ S32 index = (mCurPeriod + total_periods - i) % total_periods;
+ min_val = llmin(min_val, mRecordingPeriods[index].getPerSec(stat));
+ }
+ return min_val;
+ }
+
+ // catch all for stats that have a defined sum
+ template <typename T>
+ typename T::value_t getPeriodMax(const TraceType<T>& stat, size_t num_periods = U32_MAX)
+ {
+ size_t total_periods = mRecordingPeriods.size();
+ num_periods = llmin(num_periods, total_periods);
+
+ typename T::value_t max_val = std::numeric_limits<typename T::value_t>::min();
+ for (S32 i = 1; i <= num_periods; i++)
+ {
+ S32 index = (mCurPeriod + total_periods - i) % total_periods;
+ max_val = llmax(max_val, mRecordingPeriods[index].getSum(stat));
+ }
+ return max_val;
+ }
+
+ F64 getPeriodMax(const TraceType<SampleAccumulator>& stat, size_t num_periods = U32_MAX);
+ template<typename T>
+ T getPeriodMax(const SampleStatHandle<T>& stat, size_t num_periods = U32_MAX)
+ {
+ return T(getPeriodMax(static_cast<const TraceType<SampleAccumulator>&>(stat), num_periods));
+ }
+
+ F64 getPeriodMax(const TraceType<EventAccumulator>& stat, size_t num_periods = U32_MAX);
+ template<typename T>
+ T getPeriodMax(const EventStatHandle<T>& stat, size_t num_periods = U32_MAX)
+ {
+ return T(getPeriodMax(static_cast<const TraceType<EventAccumulator>&>(stat), num_periods));
+ }
+
+ template <typename T>
+ F64 getPeriodMaxPerSec(const TraceType<T>& stat, size_t num_periods = U32_MAX)
+ {
+ size_t total_periods = mRecordingPeriods.size();
+ num_periods = llmin(num_periods, total_periods);
+
+ F64 max_val = std::numeric_limits<F64>::min();
+ for (S32 i = 1; i <= num_periods; i++)
+ {
+ S32 index = (mCurPeriod + total_periods - i) % total_periods;
+ max_val = llmax(max_val, mRecordingPeriods[index].getPerSec(stat));
+ }
+ return max_val;
+ }
+
+ // catch all for stats that have a defined sum
+ template <typename T>
+ typename T::mean_t getPeriodMean(const TraceType<T >& stat, size_t num_periods = U32_MAX)
+ {
+ size_t total_periods = mRecordingPeriods.size();
+ num_periods = llmin(num_periods, total_periods);
+
+ typename T::mean_t mean = 0;
+ if (num_periods <= 0) { return mean; }
+
+ for (S32 i = 1; i <= num_periods; i++)
+ {
+ S32 index = (mCurPeriod + total_periods - i) % total_periods;
+ if (mRecordingPeriods[index].getDuration() > 0.f)
+ {
+ mean += mRecordingPeriods[index].getSum(stat);
+ }
+ }
+ mean = mean / num_periods;
+ return mean;
+ }
+
+ F64 getPeriodMean(const TraceType<SampleAccumulator>& stat, size_t num_periods = U32_MAX);
+ template<typename T>
+ T getPeriodMean(const SampleStatHandle<T>& stat, size_t num_periods = U32_MAX)
+ {
+ return T(getPeriodMean(static_cast<const TraceType<SampleAccumulator>&>(stat), num_periods));
+ }
+
+ F64 getPeriodMean(const TraceType<EventAccumulator>& stat, size_t num_periods = U32_MAX);
+ template<typename T>
+ T getPeriodMean(const EventStatHandle<T>& stat, size_t num_periods = U32_MAX)
+ {
+ return T(getPeriodMean(static_cast<const TraceType<EventAccumulator>&>(stat), num_periods));
+ }
+
+ template <typename T>
+ typename T::mean_t getPeriodMeanPerSec(const TraceType<T>& stat, size_t num_periods = U32_MAX)
+ {
+ size_t total_periods = mRecordingPeriods.size();
+ num_periods = llmin(num_periods, total_periods);
+
+ typename T::mean_t mean = 0;
+ if (num_periods <= 0) { return mean; }
+
+ for (S32 i = 1; i <= num_periods; i++)
+ {
+ S32 index = (mCurPeriod + total_periods - i) % total_periods;
+ if (mRecordingPeriods[index].getDuration() > 0.f)
+ {
+ mean += mRecordingPeriods[index].getPerSec(stat);
+ }
+ }
+ mean = mean / num_periods;
+ return mean;
+ }
+
+ 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;
+ };
+
+ 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& getAcceptedRecording() { return mAcceptedRecording; }
+ const PeriodicRecording& getAcceptedRecording() const {return mAcceptedRecording;}
+
+ PeriodicRecording& getPotentialRecording() { return mPotentialRecording; }
+ const PeriodicRecording& getPotentialRecording() const {return mPotentialRecording;}
+
+ 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..c1a0700eff
--- /dev/null
+++ b/indra/llcommon/lltracethreadrecorder.cpp
@@ -0,0 +1,291 @@
+/**
+ * @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"
+
+namespace LLTrace
+{
+
+
+///////////////////////////////////////////////////////////////////////
+// ThreadRecorder
+///////////////////////////////////////////////////////////////////////
+
+ThreadRecorder::ThreadRecorder()
+{
+ //NB: the ordering of initialization in this function is very fragile due to a large number of implicit dependencies
+ set_thread_recorder(this);
+ TimeBlock& root_time_block = TimeBlock::getRootTimeBlock();
+
+ ThreadTimerStack* timer_stack = ThreadTimerStack::getInstance();
+ timer_stack->mTimeBlock = &root_time_block;
+ timer_stack->mActiveTimer = NULL;
+
+ mNumTimeBlockTreeNodes = AccumulatorBuffer<TimeBlockAccumulator>::getDefaultBuffer()->size();
+ mTimeBlockTreeNodes = new TimeBlockTreeNode[mNumTimeBlockTreeNodes];
+
+ mThreadRecording.start();
+
+ // initialize time block parent pointers
+ for (LLInstanceTracker<TimeBlock>::instance_iter it = LLInstanceTracker<TimeBlock>::beginInstances(), end_it = LLInstanceTracker<TimeBlock>::endInstances();
+ it != end_it;
+ ++it)
+ {
+ TimeBlock& time_block = *it;
+ TimeBlockTreeNode& tree_node = mTimeBlockTreeNodes[it->getIndex()];
+ tree_node.mBlock = &time_block;
+ tree_node.mParent = &root_time_block;
+
+ it->getPrimaryAccumulator()->mParent = &root_time_block;
+ }
+
+ mRootTimer = new BlockTimer(root_time_block);
+ timer_stack->mActiveTimer = mRootTimer;
+
+ TimeBlock::getRootTimeBlock().getPrimaryAccumulator()->mActiveCount = 1;
+}
+
+ThreadRecorder::~ThreadRecorder()
+{
+ delete mRootTimer;
+
+ if (!mActiveRecordings.empty())
+ {
+ std::for_each(mActiveRecordings.begin(), mActiveRecordings.end(), DeletePointer());
+ mActiveRecordings.clear();
+ }
+
+ set_thread_recorder(NULL);
+ delete[] mTimeBlockTreeNodes;
+}
+
+TimeBlockTreeNode* ThreadRecorder::getTimeBlockTreeNode(S32 index)
+{
+ if (0 <= index && index < mNumTimeBlockTreeNodes)
+ {
+ return &mTimeBlockTreeNodes[index];
+ }
+ return NULL;
+}
+
+
+void ThreadRecorder::activate( Recording* recording )
+{
+ ActiveRecording* active_recording = new ActiveRecording(recording);
+ if (!mActiveRecordings.empty())
+ {
+ mActiveRecordings.back()->mPartialRecording.handOffTo(active_recording->mPartialRecording);
+ }
+ mActiveRecordings.push_back(active_recording);
+
+ mActiveRecordings.back()->mPartialRecording.makePrimary();
+}
+
+ThreadRecorder::active_recording_list_t::reverse_iterator ThreadRecorder::bringUpToDate( Recording* recording )
+{
+ if (mActiveRecordings.empty()) return mActiveRecordings.rend();
+
+ mActiveRecordings.back()->mPartialRecording.flush();
+
+ 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)
+ {
+ llwarns << "Recording not active on this thread" << llendl;
+ }
+
+ return it;
+}
+
+void ThreadRecorder::deactivate( Recording* recording )
+{
+ active_recording_list_t::reverse_iterator it = bringUpToDate(recording);
+ if (it != mActiveRecordings.rend())
+ {
+ // and if we've found the recording we wanted to update
+ active_recording_list_t::reverse_iterator next_it = it;
+ ++next_it;
+ if (next_it != mActiveRecordings.rend())
+ {
+ (*next_it)->mPartialRecording.makePrimary();
+ }
+
+ active_recording_list_t::iterator recording_to_remove = (++it).base();
+ llassert((*recording_to_remove)->mTargetRecording == recording);
+ delete *recording_to_remove;
+ mActiveRecordings.erase(recording_to_remove);
+ }
+}
+
+ThreadRecorder::ActiveRecording::ActiveRecording( Recording* target )
+: mTargetRecording(target)
+{
+}
+
+void ThreadRecorder::ActiveRecording::movePartialToTarget()
+{
+ mTargetRecording->mBuffers.write()->append(mPartialRecording);
+ // reset based on self to keep history
+ mPartialRecording.reset(&mPartialRecording);
+}
+
+
+///////////////////////////////////////////////////////////////////////
+// SlaveThreadRecorder
+///////////////////////////////////////////////////////////////////////
+
+SlaveThreadRecorder::SlaveThreadRecorder(MasterThreadRecorder& master)
+: mMasterRecorder(master)
+{
+ mMasterRecorder.addSlaveThread(this);
+}
+
+SlaveThreadRecorder::~SlaveThreadRecorder()
+{
+ mMasterRecorder.removeSlaveThread(this);
+}
+
+void SlaveThreadRecorder::pushToMaster()
+{
+ mThreadRecording.stop();
+ {
+ LLMutexLock(mMasterRecorder.getSlaveListMutex());
+ mSharedData.appendFrom(mThreadRecording);
+ }
+ mThreadRecording.start();
+}
+
+void SlaveThreadRecorder::SharedData::appendFrom( const Recording& source )
+{
+ LLMutexLock lock(&mRecordingMutex);
+ appendRecording(source);
+}
+
+void SlaveThreadRecorder::SharedData::appendTo( Recording& sink )
+{
+ LLMutexLock lock(&mRecordingMutex);
+ sink.appendRecording(*this);
+}
+
+void SlaveThreadRecorder::SharedData::mergeFrom( const RecordingBuffers& source )
+{
+ LLMutexLock lock(&mRecordingMutex);
+ mBuffers.write()->merge(source);
+}
+
+void SlaveThreadRecorder::SharedData::mergeTo( RecordingBuffers& sink )
+{
+ LLMutexLock lock(&mRecordingMutex);
+ sink.merge(*mBuffers);
+}
+
+void SlaveThreadRecorder::SharedData::reset()
+{
+ LLMutexLock lock(&mRecordingMutex);
+ Recording::reset();
+}
+
+
+///////////////////////////////////////////////////////////////////////
+// MasterThreadRecorder
+///////////////////////////////////////////////////////////////////////
+
+static LLFastTimer::DeclareTimer FTM_PULL_TRACE_DATA_FROM_SLAVES("Pull slave trace data");
+void MasterThreadRecorder::pullFromSlaveThreads()
+{
+ LLFastTimer _(FTM_PULL_TRACE_DATA_FROM_SLAVES);
+ if (mActiveRecordings.empty()) return;
+
+ LLMutexLock lock(&mSlaveListMutex);
+
+ RecordingBuffers& target_recording_buffers = mActiveRecordings.back()->mPartialRecording;
+ for (slave_thread_recorder_list_t::iterator it = mSlaveThreadRecorders.begin(), end_it = mSlaveThreadRecorders.end();
+ it != end_it;
+ ++it)
+ {
+ // ignore block timing info for now
+ (*it)->mSharedData.mergeTo(target_recording_buffers);
+ (*it)->mSharedData.reset();
+ }
+}
+
+void MasterThreadRecorder::addSlaveThread( class SlaveThreadRecorder* child )
+{
+ LLMutexLock lock(&mSlaveListMutex);
+
+ mSlaveThreadRecorders.push_back(child);
+}
+
+void MasterThreadRecorder::removeSlaveThread( class SlaveThreadRecorder* child )
+{
+ LLMutexLock lock(&mSlaveListMutex);
+
+ for (slave_thread_recorder_list_t::iterator it = mSlaveThreadRecorders.begin(), end_it = mSlaveThreadRecorders.end();
+ it != end_it;
+ ++it)
+ {
+ if ((*it) == child)
+ {
+ mSlaveThreadRecorders.erase(it);
+ break;
+ }
+ }
+}
+
+void MasterThreadRecorder::pushToMaster()
+{}
+
+MasterThreadRecorder::MasterThreadRecorder()
+{}
+
+}
diff --git a/indra/llcommon/lltracethreadrecorder.h b/indra/llcommon/lltracethreadrecorder.h
new file mode 100644
index 0000000000..bf3701304f
--- /dev/null
+++ b/indra/llcommon/lltracethreadrecorder.h
@@ -0,0 +1,126 @@
+/**
+ * @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 "lltracerecording.h"
+
+namespace LLTrace
+{
+ class LL_COMMON_API ThreadRecorder
+ {
+ protected:
+ struct ActiveRecording;
+ typedef std::vector<ActiveRecording*> active_recording_list_t;
+ public:
+ ThreadRecorder();
+
+ virtual ~ThreadRecorder();
+
+ void activate(Recording* recording);
+ void deactivate(Recording* recording);
+ active_recording_list_t::reverse_iterator bringUpToDate(Recording* recording);
+
+ virtual void pushToMaster() = 0;
+
+ TimeBlockTreeNode* getTimeBlockTreeNode(S32 index);
+
+ protected:
+ struct ActiveRecording
+ {
+ ActiveRecording(Recording* target);
+
+ Recording* mTargetRecording;
+ RecordingBuffers mPartialRecording;
+
+ void movePartialToTarget();
+ };
+ Recording mThreadRecording;
+
+ active_recording_list_t mActiveRecordings;
+
+ class BlockTimer* mRootTimer;
+ TimeBlockTreeNode* mTimeBlockTreeNodes;
+ size_t mNumTimeBlockTreeNodes;
+ };
+
+ class LL_COMMON_API MasterThreadRecorder : public ThreadRecorder
+ {
+ public:
+ MasterThreadRecorder();
+
+ void addSlaveThread(class SlaveThreadRecorder* child);
+ void removeSlaveThread(class SlaveThreadRecorder* child);
+
+ /*virtual */ void pushToMaster();
+
+ // call this periodically to gather stats data from slave threads
+ void pullFromSlaveThreads();
+
+ LLMutex* getSlaveListMutex() { return &mSlaveListMutex; }
+
+
+ private:
+
+ typedef std::list<class SlaveThreadRecorder*> slave_thread_recorder_list_t;
+
+ slave_thread_recorder_list_t mSlaveThreadRecorders; // list of slave thread recorders associated with this master
+ LLMutex mSlaveListMutex; // protects access to slave list
+ };
+
+ class LL_COMMON_API SlaveThreadRecorder : public ThreadRecorder
+ {
+ public:
+ SlaveThreadRecorder(MasterThreadRecorder& master);
+ ~SlaveThreadRecorder();
+
+ // call this periodically to gather stats data for master thread to consume
+ /*virtual*/ void pushToMaster();
+
+ MasterThreadRecorder* mMaster;
+
+ class SharedData : public Recording
+ {
+ public:
+ void appendFrom(const Recording& source);
+ void appendTo(Recording& sink);
+ void mergeFrom(const RecordingBuffers& source);
+ void mergeTo(RecordingBuffers& sink);
+ void reset();
+ private:
+ LLMutex mRecordingMutex;
+ };
+ SharedData mSharedData;
+ MasterThreadRecorder& mMasterRecorder;
+ };
+}
+
+#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/llunit.h b/indra/llcommon/llunit.h
new file mode 100644
index 0000000000..a5406fb3f0
--- /dev/null
+++ b/indra/llcommon/llunit.h
@@ -0,0 +1,481 @@
+/**
+ * @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_LLUNIT_H
+#define LL_LLUNIT_H
+
+#include "stdtypes.h"
+#include "llpreprocessor.h"
+#include "llerrorlegacy.h"
+
+namespace LLUnits
+{
+
+template<typename DERIVED_UNITS_TAG, typename BASE_UNITS_TAG, typename VALUE_TYPE>
+struct ConversionFactor
+{
+ static F64 get()
+ {
+ // spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template
+ llstatic_assert_template(DERIVED_UNITS_TAG, false, "Cannot convert between types.");
+ }
+};
+
+template<typename BASE_UNITS_TAG, typename VALUE_TYPE>
+struct ConversionFactor<BASE_UNITS_TAG, BASE_UNITS_TAG, VALUE_TYPE>
+{
+ static F64 get()
+ {
+ return 1;
+ }
+};
+
+}
+
+template<typename UNIT_TYPE, typename STORAGE_TYPE>
+struct LLUnit
+{
+ typedef LLUnit<UNIT_TYPE, STORAGE_TYPE> self_t;
+ typedef STORAGE_TYPE storage_t;
+
+ // value initialization
+ LLUnit(storage_t value = storage_t())
+ : mValue(value)
+ {}
+
+ // unit initialization and conversion
+ template<typename OTHER_UNIT, typename OTHER_STORAGE>
+ LLUnit(LLUnit<OTHER_UNIT, OTHER_STORAGE> other)
+ : mValue(convert(other))
+ {}
+
+ // value assignment
+ self_t& operator = (storage_t value)
+ {
+ mValue = value;
+ return *this;
+ }
+
+ // unit assignment
+ template<typename OTHER_UNIT, typename OTHER_STORAGE>
+ self_t& operator = (LLUnit<OTHER_UNIT, OTHER_STORAGE> other)
+ {
+ mValue = convert(other);
+ return *this;
+ }
+
+ storage_t value() const
+ {
+ return mValue;
+ }
+
+ template<typename NEW_UNIT_TYPE> LLUnit<NEW_UNIT_TYPE, STORAGE_TYPE> as()
+ {
+ return LLUnit<NEW_UNIT_TYPE, STORAGE_TYPE>(*this);
+ }
+
+
+ void operator += (storage_t value)
+ {
+ mValue += value;
+ }
+
+ template<typename OTHER_UNIT, typename OTHER_STORAGE>
+ void operator += (LLUnit<OTHER_UNIT, OTHER_STORAGE> other)
+ {
+ mValue += convert(other);
+ }
+
+ void operator -= (storage_t value)
+ {
+ mValue -= value;
+ }
+
+ template<typename OTHER_UNIT, typename OTHER_STORAGE>
+ void operator -= (LLUnit<OTHER_UNIT, OTHER_STORAGE> other)
+ {
+ mValue -= convert(other);
+ }
+
+ void operator *= (storage_t multiplicand)
+ {
+ mValue *= multiplicand;
+ }
+
+ template<typename OTHER_UNIT, typename OTHER_STORAGE>
+ void operator *= (LLUnit<OTHER_UNIT, OTHER_STORAGE> multiplicand)
+ {
+ // spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template
+ llstatic_assert_template(OTHER_UNIT, false, "Multiplication of unit types not supported.");
+ }
+
+ void operator /= (storage_t divisor)
+ {
+ mValue /= divisor;
+ }
+
+ template<typename OTHER_UNIT, typename OTHER_STORAGE>
+ void operator /= (LLUnit<OTHER_UNIT, OTHER_STORAGE> divisor)
+ {
+ // spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template
+ llstatic_assert_template(OTHER_UNIT, false, "Illegal in-place division of unit types.");
+ }
+
+ template<typename SOURCE_UNITS, typename SOURCE_STORAGE>
+ static storage_t convert(LLUnit<SOURCE_UNITS, SOURCE_STORAGE> v)
+ {
+ return (storage_t)(v.value()
+ * LLUnits::ConversionFactor<SOURCE_UNITS, typename UNIT_TYPE::base_unit_t, SOURCE_STORAGE>::get()
+ * LLUnits::ConversionFactor<typename UNIT_TYPE::base_unit_t, UNIT_TYPE, STORAGE_TYPE>::get());
+ }
+
+protected:
+ storage_t mValue;
+};
+
+template<typename UNIT_TYPE, typename STORAGE_TYPE>
+struct LLUnitImplicit : public LLUnit<UNIT_TYPE, STORAGE_TYPE>
+{
+ typedef LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> self_t;
+ typedef typename LLUnit<UNIT_TYPE, STORAGE_TYPE>::storage_t storage_t;
+ typedef LLUnit<UNIT_TYPE, STORAGE_TYPE> base_t;
+
+ LLUnitImplicit(storage_t value = storage_t())
+ : base_t(value)
+ {}
+
+ template<typename OTHER_UNIT, typename OTHER_STORAGE>
+ LLUnitImplicit(LLUnit<OTHER_UNIT, OTHER_STORAGE> other)
+ : base_t(convert(other))
+ {}
+
+ // unlike LLUnit, LLUnitImplicit is *implicitly* convertable to a POD scalar (F32, S32, etc)
+ // this allows for interoperability with legacy code
+ operator storage_t() const
+ {
+ return base_t::value();
+ }
+};
+
+//
+// operator +
+//
+template<typename UNIT_TYPE1, typename STORAGE_TYPE1, typename UNIT_TYPE2, typename STORAGE_TYPE2>
+LLUnit<UNIT_TYPE1, STORAGE_TYPE1> operator + (LLUnit<UNIT_TYPE1, STORAGE_TYPE1> first, LLUnit<UNIT_TYPE2, STORAGE_TYPE2> second)
+{
+ LLUnit<UNIT_TYPE1, STORAGE_TYPE1> result(first);
+ result += second;
+ return result;
+}
+
+template<typename UNIT_TYPE, typename STORAGE_TYPE, typename SCALAR_TYPE>
+LLUnit<UNIT_TYPE, STORAGE_TYPE> operator + (LLUnit<UNIT_TYPE, STORAGE_TYPE> first, SCALAR_TYPE second)
+{
+ LLUnit<UNIT_TYPE, STORAGE_TYPE> result(first);
+ result += second;
+ return result;
+}
+
+template<typename UNIT_TYPE, typename STORAGE_TYPE, typename SCALAR_TYPE>
+LLUnit<UNIT_TYPE, STORAGE_TYPE> operator + (SCALAR_TYPE first, LLUnit<UNIT_TYPE, STORAGE_TYPE> second)
+{
+ LLUnit<UNIT_TYPE, STORAGE_TYPE> result(first);
+ result += second;
+ return result;
+}
+
+template<typename UNIT_TYPE1, typename STORAGE_TYPE1, typename UNIT_TYPE2, typename STORAGE_TYPE2>
+LLUnitImplicit<UNIT_TYPE1, STORAGE_TYPE1> operator + (LLUnitImplicit<UNIT_TYPE1, STORAGE_TYPE1> first, LLUnit<UNIT_TYPE2, STORAGE_TYPE2> second)
+{
+ LLUnitImplicit<UNIT_TYPE1, STORAGE_TYPE1> result(first);
+ result += second;
+ return result;
+}
+
+template<typename UNIT_TYPE, typename STORAGE_TYPE, typename SCALAR_TYPE>
+LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> operator + (LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> first, SCALAR_TYPE second)
+{
+ LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> result(first);
+ result += second;
+ return result;
+}
+
+template<typename UNIT_TYPE1, typename STORAGE_TYPE1, typename UNIT_TYPE2, typename STORAGE_TYPE2>
+LLUnitImplicit<UNIT_TYPE1, STORAGE_TYPE1> operator + (LLUnitImplicit<UNIT_TYPE1, STORAGE_TYPE1> first, LLUnitImplicit<UNIT_TYPE2, STORAGE_TYPE2> second)
+{
+ LLUnitImplicit<UNIT_TYPE1, STORAGE_TYPE1> result(first);
+ result += second;
+ return result;
+}
+
+//
+// operator -
+//
+template<typename UNIT_TYPE1, typename STORAGE_TYPE1, typename UNIT_TYPE2, typename STORAGE_TYPE2>
+LLUnit<UNIT_TYPE1, STORAGE_TYPE1> operator - (LLUnit<UNIT_TYPE1, STORAGE_TYPE1> first, LLUnit<UNIT_TYPE2, STORAGE_TYPE2> second)
+{
+ LLUnit<UNIT_TYPE1, STORAGE_TYPE1> result(first);
+ result -= second;
+ return result;
+}
+
+template<typename UNIT_TYPE, typename STORAGE_TYPE, typename SCALAR_TYPE>
+LLUnit<UNIT_TYPE, STORAGE_TYPE> operator - (LLUnit<UNIT_TYPE, STORAGE_TYPE> first, SCALAR_TYPE second)
+{
+ LLUnit<UNIT_TYPE, STORAGE_TYPE> result(first);
+ result -= second;
+ return result;
+}
+
+template<typename UNIT_TYPE, typename STORAGE_TYPE, typename SCALAR_TYPE>
+LLUnit<UNIT_TYPE, STORAGE_TYPE> operator - (SCALAR_TYPE first, LLUnit<UNIT_TYPE, STORAGE_TYPE> second)
+{
+ LLUnit<UNIT_TYPE, STORAGE_TYPE> result(first);
+ result -= second;
+ return result;
+}
+
+template<typename UNIT_TYPE1, typename STORAGE_TYPE1, typename UNIT_TYPE2, typename STORAGE_TYPE2>
+LLUnitImplicit<UNIT_TYPE1, STORAGE_TYPE1> operator - (LLUnitImplicit<UNIT_TYPE1, STORAGE_TYPE1> first, LLUnitImplicit<UNIT_TYPE2, STORAGE_TYPE2> second)
+{
+ LLUnitImplicit<UNIT_TYPE1, STORAGE_TYPE1> result(first);
+ result -= second;
+ return result;
+}
+
+template<typename UNIT_TYPE, typename STORAGE_TYPE, typename SCALAR_TYPE>
+LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> operator - (LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> first, SCALAR_TYPE second)
+{
+ LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> result(first);
+ result -= second;
+ return result;
+}
+
+template<typename UNIT_TYPE, typename STORAGE_TYPE, typename SCALAR_TYPE>
+LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> operator - (SCALAR_TYPE first, LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> second)
+{
+ LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> result(first);
+ result -= second;
+ return result;
+}
+
+//
+// operator *
+//
+template<typename UNIT_TYPE, typename STORAGE_TYPE, typename SCALAR_TYPE>
+LLUnit<UNIT_TYPE, STORAGE_TYPE> operator * (SCALAR_TYPE first, LLUnit<UNIT_TYPE, STORAGE_TYPE> second)
+{
+ return LLUnit<UNIT_TYPE, STORAGE_TYPE>((STORAGE_TYPE)(first * second.value()));
+}
+
+template<typename UNIT_TYPE, typename STORAGE_TYPE, typename SCALAR_TYPE>
+LLUnit<UNIT_TYPE, STORAGE_TYPE> operator * (LLUnit<UNIT_TYPE, STORAGE_TYPE> first, SCALAR_TYPE second)
+{
+ return LLUnit<UNIT_TYPE, STORAGE_TYPE>((STORAGE_TYPE)(first.value() * second));
+}
+
+template<typename UNIT_TYPE1, typename STORAGE_TYPE1, typename UNIT_TYPE2, typename STORAGE_TYPE2>
+LLUnit<UNIT_TYPE1, STORAGE_TYPE1> operator * (LLUnit<UNIT_TYPE1, STORAGE_TYPE1>, LLUnit<UNIT_TYPE2, STORAGE_TYPE2>)
+{
+ // spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template
+ llstatic_assert_template(STORAGE_TYPE1, false, "Multiplication of unit types results in new unit type - not supported.");
+ return LLUnit<UNIT_TYPE1, STORAGE_TYPE1>();
+}
+
+template<typename UNIT_TYPE, typename STORAGE_TYPE, typename SCALAR_TYPE>
+LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> operator * (SCALAR_TYPE first, LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> second)
+{
+ return LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE>(first * second.value());
+}
+
+template<typename UNIT_TYPE, typename STORAGE_TYPE, typename SCALAR_TYPE>
+LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> operator * (LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> first, SCALAR_TYPE second)
+{
+ return LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE>(first.value() * second);
+}
+
+template<typename UNIT_TYPE1, typename STORAGE_TYPE1, typename UNIT_TYPE2, typename STORAGE_TYPE2>
+LLUnitImplicit<UNIT_TYPE1, STORAGE_TYPE1> operator * (LLUnitImplicit<UNIT_TYPE1, STORAGE_TYPE1>, LLUnitImplicit<UNIT_TYPE2, STORAGE_TYPE2>)
+{
+ // spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template
+ llstatic_assert_template(STORAGE_TYPE1, false, "Multiplication of unit types results in new unit type - not supported.");
+ return LLUnitImplicit<UNIT_TYPE1, STORAGE_TYPE1>();
+}
+
+//
+// operator /
+//
+template<typename UNIT_TYPE, typename STORAGE_TYPE, typename SCALAR_TYPE>
+SCALAR_TYPE operator / (SCALAR_TYPE first, LLUnit<UNIT_TYPE, STORAGE_TYPE> second)
+{
+ return SCALAR_TYPE(first / second.value());
+}
+
+template<typename UNIT_TYPE, typename STORAGE_TYPE, typename SCALAR_TYPE>
+LLUnit<UNIT_TYPE, STORAGE_TYPE> operator / (LLUnit<UNIT_TYPE, STORAGE_TYPE> first, SCALAR_TYPE second)
+{
+ return LLUnit<UNIT_TYPE, STORAGE_TYPE>((STORAGE_TYPE)(first.value() / second));
+}
+
+template<typename UNIT_TYPE1, typename STORAGE_TYPE1, typename UNIT_TYPE2, typename STORAGE_TYPE2>
+STORAGE_TYPE1 operator / (LLUnit<UNIT_TYPE1, STORAGE_TYPE1> first, LLUnit<UNIT_TYPE2, STORAGE_TYPE2> second)
+{
+ // spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template
+ return STORAGE_TYPE1(first.value() / second.value());
+}
+
+template<typename UNIT_TYPE, typename STORAGE_TYPE, typename SCALAR_TYPE>
+LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> operator / (LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> first, SCALAR_TYPE second)
+{
+ return LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE>((STORAGE_TYPE)(first.value() / second));
+}
+
+template<typename UNIT_TYPE1, typename STORAGE_TYPE1, typename UNIT_TYPE2, typename STORAGE_TYPE2>
+STORAGE_TYPE1 operator / (LLUnitImplicit<UNIT_TYPE1, STORAGE_TYPE1> first, LLUnitImplicit<UNIT_TYPE2, STORAGE_TYPE2> second)
+{
+ // spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template
+ return STORAGE_TYPE1(first.value() / second.value());
+}
+
+#define COMPARISON_OPERATORS(op) \
+template<typename UNIT_TYPE, typename STORAGE_TYPE, typename SCALAR_TYPE> \
+bool operator op (SCALAR_TYPE first, LLUnit<UNIT_TYPE, STORAGE_TYPE> second) \
+{ \
+ return first op second.value(); \
+} \
+ \
+template<typename UNIT_TYPE, typename STORAGE_TYPE, typename SCALAR_TYPE> \
+bool operator op (LLUnit<UNIT_TYPE, STORAGE_TYPE> first, SCALAR_TYPE second) \
+{ \
+ return first.value() op second; \
+} \
+ \
+template<typename UNIT_TYPE1, typename STORAGE_TYPE1, typename UNIT_TYPE2, typename STORAGE_TYPE2> \
+bool operator op (LLUnitImplicit<UNIT_TYPE1, STORAGE_TYPE1> first, LLUnitImplicit<UNIT_TYPE2, STORAGE_TYPE2> second) \
+{ \
+ return first.value() op first.convert(second); \
+} \
+ \
+template<typename UNIT_TYPE1, typename STORAGE_TYPE1, typename UNIT_TYPE2, typename STORAGE_TYPE2> \
+ bool operator op (LLUnit<UNIT_TYPE1, STORAGE_TYPE1> first, LLUnit<UNIT_TYPE2, STORAGE_TYPE2> second) \
+{ \
+ return first.value() op first.convert(second); \
+}
+
+COMPARISON_OPERATORS(<)
+COMPARISON_OPERATORS(<=)
+COMPARISON_OPERATORS(>)
+COMPARISON_OPERATORS(>=)
+COMPARISON_OPERATORS(==)
+COMPARISON_OPERATORS(!=)
+
+
+template<typename T>
+struct LLGetUnitLabel
+{
+ static const char* getUnitLabel() { return ""; }
+};
+
+template<typename T, typename STORAGE_T>
+struct LLGetUnitLabel<LLUnit<T, STORAGE_T> >
+{
+ static const char* getUnitLabel() { return T::getUnitLabel(); }
+};
+
+//
+// Unit declarations
+//
+namespace LLUnits
+{
+template<typename T>
+T rawValue(T val) { return val; }
+
+template<typename UNIT_TYPE, typename STORAGE_TYPE>
+STORAGE_TYPE rawValue(LLUnit<UNIT_TYPE, STORAGE_TYPE> val) { return val.value(); }
+
+template<typename UNIT_TYPE, typename STORAGE_TYPE>
+STORAGE_TYPE rawValue(LLUnitImplicit<UNIT_TYPE, STORAGE_TYPE> val) { return val.value(); }
+
+#define LL_DECLARE_DERIVED_UNIT(conversion_factor, base_unit_name, unit_name, unit_label) \
+struct unit_name \
+{ \
+ typedef base_unit_name base_unit_t; \
+ static const char* getUnitLabel() { return unit_label; } \
+}; \
+template<typename STORAGE_TYPE> \
+struct ConversionFactor<unit_name, base_unit_name, STORAGE_TYPE> \
+{ \
+ static F64 get() \
+ { \
+ return (F64)conversion_factor; \
+ } \
+}; \
+ \
+template<typename STORAGE_TYPE> \
+struct ConversionFactor<base_unit_name, unit_name, STORAGE_TYPE> \
+{ \
+ static F64 get() \
+ { \
+ return (F64)(1.0 / (conversion_factor)); \
+ } \
+}
+
+#define LL_DECLARE_BASE_UNIT(base_unit_name, unit_label) \
+struct base_unit_name { typedef base_unit_name base_unit_t; static const char* getUnitLabel() { return unit_label; }}
+
+LL_DECLARE_BASE_UNIT(Bytes, "B");
+LL_DECLARE_DERIVED_UNIT(1024, Bytes, Kibibytes, "KiB");
+LL_DECLARE_DERIVED_UNIT(1024 * 1024, Bytes, Mibibytes, "MiB");
+LL_DECLARE_DERIVED_UNIT(1024 * 1024 * 1024, Bytes, Gibibytes, "GiB");
+LL_DECLARE_DERIVED_UNIT(1.0 / 8.0, Bytes, Bits, "b");
+LL_DECLARE_DERIVED_UNIT(1024 / 8, Bytes, Kibibits, "Kib");
+LL_DECLARE_DERIVED_UNIT(1024 / 8, Bytes, Mibibits, "Mib");
+LL_DECLARE_DERIVED_UNIT(1024 * 1024 * 1024 / 8, Bytes, Gibibits, "Gib");
+
+LL_DECLARE_BASE_UNIT(Seconds, "s");
+LL_DECLARE_DERIVED_UNIT(60, Seconds, Minutes, "min");
+LL_DECLARE_DERIVED_UNIT(60 * 60, Seconds, Hours, "h");
+LL_DECLARE_DERIVED_UNIT(1.0 / 1000.0, Seconds, Milliseconds, "ms");
+LL_DECLARE_DERIVED_UNIT(1.0 / 1000000.0, Seconds, Microseconds, "\x09\x3cs");
+LL_DECLARE_DERIVED_UNIT(1.0 / 1000000000.0, Seconds, Nanoseconds, "ns");
+
+LL_DECLARE_BASE_UNIT(Meters, "m");
+LL_DECLARE_DERIVED_UNIT(1000, Meters, Kilometers, "km");
+LL_DECLARE_DERIVED_UNIT(1.0 / 100.0, Meters, Centimeters, "cm");
+LL_DECLARE_DERIVED_UNIT(1.0 / 1000.0, Meters, Millimeters, "mm");
+
+LL_DECLARE_BASE_UNIT(Hertz, "Hz");
+LL_DECLARE_DERIVED_UNIT(1000, Hertz, Kilohertz, "KHz");
+LL_DECLARE_DERIVED_UNIT(1000 * 1000, Hertz, Megahertz, "MHz");
+LL_DECLARE_DERIVED_UNIT(1000 * 1000 * 1000, Hertz, Gigahertz, "GHz");
+
+LL_DECLARE_BASE_UNIT(Radians, "rad");
+LL_DECLARE_DERIVED_UNIT(DEG_TO_RAD, Radians, Degrees, "deg");
+
+
+} // namespace LLUnits
+
+#endif // LL_LLUNIT_H
diff --git a/indra/llcommon/lluuid.cpp b/indra/llcommon/lluuid.cpp
index 0aaa50d231..ba4b670b9a 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>
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/reflective.cpp b/indra/llcommon/llwin32headers.h
index 2cc0e7e1f2..cf85067d95 100755..100644
--- a/indra/llcommon/reflective.cpp
+++ b/indra/llcommon/llwin32headers.h
@@ -1,10 +1,8 @@
/**
- * @file reflective.cpp
- * @author Babbage
- * @date 2006-05-15
- * @brief Implementation of LLReflective.
+ * @file llwindows.h
+ * @brief sanitized include of windows header files
*
- * $LicenseInfo:firstyear=2006&license=viewerlgpl$
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
* Second Life Viewer Source Code
* Copyright (C) 2010, Linden Research, Inc.
*
@@ -26,15 +24,19 @@
* $/LicenseInfo$
*/
-#include "linden_common.h"
-
-#include "reflective.h"
+#ifndef LL_LLWINDOWS_H
+#define LL_LLWINDOWS_H
-LLReflective::LLReflective()
-{
-}
+#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
-//virtual
-LLReflective::~LLReflective()
-{
-}
+#endif
diff --git a/indra/llcommon/lldarrayptr.h b/indra/llcommon/llwin32headerslean.h
index c9a0b204d1..f7e71301a8 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 llwindows.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.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.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/tests/llunits_test.cpp b/indra/llcommon/tests/llunits_test.cpp
new file mode 100644
index 0000000000..2a941e8229
--- /dev/null
+++ b/indra/llcommon/tests/llunits_test.cpp
@@ -0,0 +1,208 @@
+/**
+ * @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 "llunit.h"
+#include "../test/lltut.h"
+
+namespace LLUnits
+{
+ // using powers of 2 to allow strict floating point equality
+ struct Quatloos { typedef Quatloos base_unit_t; };
+ LL_DECLARE_DERIVED_UNIT(4, Quatloos, Latinum);
+ LL_DECLARE_DERIVED_UNIT((1.0 / 4.0), Quatloos, Solari);
+}
+
+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<Quatloos, F32> float_quatloos;
+ ensure(float_quatloos.value() == 0.f);
+
+ LLUnit<Quatloos, S32> int_quatloos;
+ ensure(int_quatloos.value() == 0);
+
+ int_quatloos = 42;
+ ensure(int_quatloos.value() == 42);
+ float_quatloos = int_quatloos;
+ ensure(float_quatloos.value() == 42.f);
+
+ int_quatloos = float_quatloos;
+ ensure(int_quatloos.value() == 42);
+
+ float_quatloos = 42.1f;
+ ensure(float_quatloos.value() == 42.1f);
+ int_quatloos = float_quatloos;
+ ensure(int_quatloos.value() == 42);
+ LLUnit<Quatloos, U32> unsigned_int_quatloos(float_quatloos);
+ ensure(unsigned_int_quatloos.value() == 42);
+ }
+
+ // conversions to/from base unit
+ template<> template<>
+ void units_object_t::test<2>()
+ {
+ LLUnit<Quatloos, F32> quatloos(1.f);
+ ensure(quatloos.value() == 1.f);
+ LLUnit<Latinum, F32> latinum_bars(quatloos);
+ ensure(latinum_bars.value() == 1.f / 4.f);
+
+ latinum_bars = 256;
+ quatloos = latinum_bars;
+ ensure(quatloos.value() == 1024);
+
+ LLUnit<Solari, F32> solari(quatloos);
+ ensure(solari.value() == 4096);
+ }
+
+ // conversions across non-base units
+ template<> template<>
+ void units_object_t::test<3>()
+ {
+ LLUnit<Solari, F32> solari = 4.f;
+ LLUnit<Latinum, F32> latinum_bars = solari;
+ ensure(latinum_bars.value() == 0.25f);
+ }
+
+ // math operations
+ template<> template<>
+ void units_object_t::test<4>()
+ {
+ LLUnit<Quatloos, F32> quatloos = 1.f;
+ quatloos *= 4.f;
+ ensure(quatloos.value() == 4);
+ quatloos = quatloos * 2;
+ ensure(quatloos.value() == 8);
+ quatloos = 2.f * quatloos;
+ ensure(quatloos.value() == 16);
+
+ quatloos += 4.f;
+ ensure(quatloos.value() == 20);
+ quatloos += 4;
+ ensure(quatloos.value() == 24);
+ quatloos = quatloos + 4;
+ ensure(quatloos.value() == 28);
+ quatloos = 4 + quatloos;
+ ensure(quatloos.value() == 32);
+ quatloos += quatloos * 3;
+ ensure(quatloos.value() == 128);
+
+ quatloos -= quatloos / 4 * 3;
+ ensure(quatloos.value() == 32);
+ quatloos = quatloos - 8;
+ ensure(quatloos.value() == 24);
+ quatloos -= 4;
+ ensure(quatloos.value() == 20);
+ quatloos -= 4.f;
+ ensure(quatloos.value() == 16);
+
+ quatloos *= 2.f;
+ ensure(quatloos.value() == 32);
+ quatloos = quatloos * 2.f;
+ ensure(quatloos.value() == 64);
+ quatloos = 0.5f * quatloos;
+ ensure(quatloos.value() == 32);
+
+ quatloos /= 2.f;
+ ensure(quatloos.value() == 16);
+ quatloos = quatloos / 4;
+ ensure(quatloos.value() == 4);
+
+ F32 ratio = quatloos / LLUnit<Quatloos, F32>(4.f);
+ ensure(ratio == 1);
+
+ quatloos += LLUnit<Solari, F32>(4.f);
+ ensure(quatloos.value() == 5);
+ quatloos -= LLUnit<Latinum, F32>(1.f);
+ ensure(quatloos.value() == 1);
+ }
+
+ // implicit units
+ template<> template<>
+ void units_object_t::test<5>()
+ {
+ // 0-initialized
+ LLUnit<Quatloos, F32> quatloos(0);
+ // initialize implicit unit from explicit
+ LLUnitImplicit<Quatloos, F32> quatloos_implicit = quatloos + 1;
+ ensure(quatloos_implicit.value() == 1);
+
+ // assign implicit to explicit, or perform math operations
+ quatloos = quatloos_implicit;
+ ensure(quatloos.value() == 1);
+ quatloos += quatloos_implicit;
+ ensure(quatloos.value() == 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(float_val == 16);
+
+ S32 int_val = quatloos_implicit;
+ ensure(int_val == 16);
+ }
+}
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());
-
- }
-}