Merge branch 'future'
This commit is contained in:
@@ -31,10 +31,10 @@ if (WINDOWS)
|
||||
# Don't build DLLs.
|
||||
set(BUILD_SHARED_LIBS OFF)
|
||||
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /Od /Zi /MDd"
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /Od /Zi /MDd /arch:SSE2"
|
||||
CACHE STRING "C++ compiler debug options" FORCE)
|
||||
set(CMAKE_CXX_FLAGS_RELWITHDEBINFO
|
||||
"${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /Od /Zi /MD /MP"
|
||||
"${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /Od /Zi /MD /MP /arch:SSE2"
|
||||
CACHE STRING "C++ compiler release-with-debug options" FORCE)
|
||||
set(CMAKE_CXX_FLAGS_RELEASE
|
||||
"${CMAKE_CXX_FLAGS_RELEASE} ${LL_CXX_FLAGS} /O2 /Zi /MD /MP /arch:SSE /fp:fast"
|
||||
@@ -295,6 +295,7 @@ endif (STANDALONE)
|
||||
|
||||
if(1 EQUAL 1)
|
||||
add_definitions(-DOPENSIM_RULES=1)
|
||||
add_definitions(-DMESH_ENABLED=1)
|
||||
endif(1 EQUAL 1)
|
||||
|
||||
if(SERVER)
|
||||
|
||||
@@ -19,3 +19,8 @@ set(LLCOMMON_INCLUDE_DIRS
|
||||
)
|
||||
|
||||
set(LLCOMMON_LIBRARIES llcommon)
|
||||
|
||||
set(LLCOMMON_LINK_SHARED ON CACHE BOOL "Build the llcommon target as a shared library.")
|
||||
if(LLCOMMON_LINK_SHARED)
|
||||
add_definitions(-DLL_COMMON_LINK_SHARED=1)
|
||||
endif(LLCOMMON_LINK_SHARED)
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
include(Prebuilt)
|
||||
|
||||
if (NOT STANDALONE)
|
||||
use_prebuilt_binary(GL)
|
||||
use_prebuilt_binary(glext)
|
||||
# possible glh_linear should have its own .cmake file instead
|
||||
#use_prebuilt_binary(glh_linear)
|
||||
# actually... not any longer, it's now in git -SG
|
||||
set(GLEXT_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/${LL_ARCH_DIR}/include)
|
||||
set(GLEXT_INCLUDE_DIR ${LIBS_PREBUILT_DIR}/include)
|
||||
endif (NOT STANDALONE)
|
||||
|
||||
@@ -89,7 +89,7 @@ S32 check_for_invalid_wav_formats(const std::string& in_fname, std::string& erro
|
||||
|
||||
//********************************
|
||||
LLAPRFile infile ;
|
||||
infile.open(in_fname,LL_APR_RB, LLAPRFile::global);
|
||||
infile.open(in_fname,LL_APR_RB);
|
||||
//********************************
|
||||
if (!infile.getFileHandle())
|
||||
{
|
||||
@@ -240,7 +240,7 @@ S32 encode_vorbis_file(const std::string& in_fname, const std::string& out_fname
|
||||
S32 data_left = 0;
|
||||
|
||||
LLAPRFile infile ;
|
||||
infile.open(in_fname,LL_APR_RB, LLAPRFile::global);
|
||||
infile.open(in_fname,LL_APR_RB);
|
||||
if (!infile.getFileHandle())
|
||||
{
|
||||
llwarns << "Couldn't open temporary ogg file for writing: " << in_fname
|
||||
@@ -249,7 +249,7 @@ S32 encode_vorbis_file(const std::string& in_fname, const std::string& out_fname
|
||||
}
|
||||
|
||||
LLAPRFile outfile ;
|
||||
outfile.open(out_fname,LL_APR_WPB, LLAPRFile::global);
|
||||
outfile.open(out_fname,LL_APR_WPB);
|
||||
if (!outfile.getFileHandle())
|
||||
{
|
||||
llwarns << "Couldn't open upload sound file for reading: " << in_fname
|
||||
|
||||
@@ -225,8 +225,7 @@ ELoadStatus LLBVHLoader::loadTranslationTable(const char *fileName)
|
||||
//--------------------------------------------------------------------
|
||||
std::string path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,fileName);
|
||||
|
||||
LLAPRFile infile ;
|
||||
infile.open(path, LL_APR_R, LLAPRFile::global);
|
||||
LLAPRFile infile(path, LL_APR_R);
|
||||
apr_file_t *fp = infile.getFileHandle();
|
||||
if (!fp)
|
||||
return E_ST_NO_XLT_FILE;
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
LLStringTable LLCharacter::sVisualParamNames(1024);
|
||||
|
||||
std::vector< LLCharacter* > LLCharacter::sInstances;
|
||||
|
||||
BOOL LLCharacter::sAllowInstancesChange = TRUE ;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// LLCharacter()
|
||||
@@ -59,8 +59,10 @@ LLCharacter::LLCharacter()
|
||||
mSkeletonSerialNum( 0 ),
|
||||
mInAppearance( false )
|
||||
{
|
||||
mMotionController.setCharacter( this );
|
||||
llassert_always(sAllowInstancesChange) ;
|
||||
sInstances.push_back(this);
|
||||
|
||||
mMotionController.setCharacter( this );
|
||||
mPauseRequest = new LLPauseRequestHandle();
|
||||
}
|
||||
|
||||
@@ -77,11 +79,22 @@ LLCharacter::~LLCharacter()
|
||||
{
|
||||
delete param;
|
||||
}
|
||||
std::vector<LLCharacter*>::iterator iter = std::find(sInstances.begin(), sInstances.end(), this);
|
||||
if (iter != sInstances.end())
|
||||
|
||||
U32 i ;
|
||||
U32 size = sInstances.size() ;
|
||||
for(i = 0 ; i < size ; i++)
|
||||
{
|
||||
sInstances.erase(iter);
|
||||
if(sInstances[i] == this)
|
||||
{
|
||||
break ;
|
||||
}
|
||||
}
|
||||
|
||||
llassert_always(i < size) ;
|
||||
|
||||
llassert_always(sAllowInstancesChange) ;
|
||||
sInstances[i] = sInstances[size - 1] ;
|
||||
sInstances.pop_back() ;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
#include "llmotioncontroller.h"
|
||||
#include "llvisualparam.h"
|
||||
#include "string_table.h"
|
||||
#include "llmemory.h"
|
||||
#include "llpointer.h"
|
||||
#include "llthread.h"
|
||||
|
||||
class LLPolyMesh;
|
||||
@@ -279,6 +279,7 @@ public:
|
||||
void setSkeletonSerialNum( U32 num ) { mSkeletonSerialNum = num; }
|
||||
|
||||
static std::vector< LLCharacter* > sInstances;
|
||||
static BOOL sAllowInstancesChange ; //debug use
|
||||
|
||||
protected:
|
||||
LLMotionController mMotionController;
|
||||
|
||||
@@ -56,6 +56,9 @@ LLJoint::LLJoint()
|
||||
mUpdateXform = TRUE;
|
||||
mJointNum = -1;
|
||||
touch();
|
||||
#if MESH_ENABLED
|
||||
mResetAfterRestoreOldXform = false;
|
||||
#endif //MESH_ENABLED
|
||||
}
|
||||
|
||||
|
||||
@@ -239,6 +242,43 @@ void LLJoint::setPosition( const LLVector3& pos )
|
||||
}
|
||||
}
|
||||
|
||||
#if MESH_ENABLED
|
||||
//--------------------------------------------------------------------
|
||||
// setPosition()
|
||||
//--------------------------------------------------------------------
|
||||
void LLJoint::setDefaultFromCurrentXform( void )
|
||||
{
|
||||
mDefaultXform = mXform;
|
||||
touch(MATRIX_DIRTY | POSITION_DIRTY);
|
||||
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// storeCurrentXform()
|
||||
//--------------------------------------------------------------------
|
||||
void LLJoint::storeCurrentXform( const LLVector3& pos )
|
||||
{
|
||||
mOldXform = mXform;
|
||||
mResetAfterRestoreOldXform = true;
|
||||
setPosition( pos );
|
||||
}
|
||||
//--------------------------------------------------------------------
|
||||
// restoreOldXform()
|
||||
//--------------------------------------------------------------------
|
||||
void LLJoint::restoreOldXform( void )
|
||||
{
|
||||
mResetAfterRestoreOldXform = false;
|
||||
mXform = mOldXform;
|
||||
}
|
||||
//--------------------------------------------------------------------
|
||||
// restoreOldXform()
|
||||
//--------------------------------------------------------------------
|
||||
void LLJoint::restoreToDefaultXform( void )
|
||||
{
|
||||
mXform = mDefaultXform;
|
||||
setPosition( mXform.getPosition() );
|
||||
}
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// getWorldPosition()
|
||||
|
||||
@@ -86,10 +86,19 @@ protected:
|
||||
|
||||
// explicit transformation members
|
||||
LLXformMatrix mXform;
|
||||
#if MESH_ENABLED
|
||||
LLXformMatrix mOldXform;
|
||||
LLXformMatrix mDefaultXform;
|
||||
|
||||
LLUUID mId;
|
||||
#endif //MESH_ENABLED
|
||||
public:
|
||||
U32 mDirtyFlags;
|
||||
BOOL mUpdateXform;
|
||||
|
||||
#if MESH_ENABLED
|
||||
BOOL mResetAfterRestoreOldXform;
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
// describes the skin binding pose
|
||||
LLVector3 mSkinOffset;
|
||||
@@ -179,6 +188,24 @@ public:
|
||||
S32 getJointNum() const { return mJointNum; }
|
||||
void setJointNum(S32 joint_num) { mJointNum = joint_num; }
|
||||
|
||||
#if MESH_ENABLED
|
||||
|
||||
void restoreOldXform( void );
|
||||
void restoreToDefaultXform( void );
|
||||
void setDefaultFromCurrentXform( void );
|
||||
void storeCurrentXform( const LLVector3& pos );
|
||||
|
||||
//Accessor for the joint id
|
||||
LLUUID getId( void ) { return mId; }
|
||||
//Setter for the joints id
|
||||
void setId( const LLUUID& id ) { mId = id;}
|
||||
|
||||
//If the old transform flag has been set, then the reset logic in avatar needs to be aware(test) of it
|
||||
const BOOL doesJointNeedToBeReset( void ) const { return mResetAfterRestoreOldXform; }
|
||||
//Setter for joint reset flag
|
||||
void setJointToBeReset( BOOL val ) { mResetAfterRestoreOldXform = val; }
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
// <edit>
|
||||
std::string exportString(U32 tabs = 0);
|
||||
// </edit>
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
// Header Files
|
||||
//-----------------------------------------------------------------------------
|
||||
#include "lljoint.h"
|
||||
#include "llmemory.h"
|
||||
#include "llrefcount.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// class LLJointState
|
||||
|
||||
@@ -838,7 +838,11 @@ void LLKeyframeMotion::initializeConstraint(JointConstraint* constraint)
|
||||
S32 joint_num;
|
||||
LLVector3 source_pos = mCharacter->getVolumePos(shared_data->mSourceConstraintVolume, shared_data->mSourceConstraintOffset);
|
||||
LLJoint* cur_joint = getJoint(shared_data->mJointStateIndices[0]);
|
||||
|
||||
if ( !cur_joint )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
F32 source_pos_offset = dist_vec(source_pos, cur_joint->getWorldPosition());
|
||||
|
||||
constraint->mTotalLength = constraint->mJointLengths[0] = dist_vec(cur_joint->getParent()->getWorldPosition(), source_pos);
|
||||
@@ -889,6 +893,10 @@ void LLKeyframeMotion::activateConstraint(JointConstraint* constraint)
|
||||
for (joint_num = 1; joint_num < shared_data->mChainLength; joint_num++)
|
||||
{
|
||||
LLJoint* cur_joint = getJoint(shared_data->mJointStateIndices[joint_num]);
|
||||
if ( !cur_joint )
|
||||
{
|
||||
return;
|
||||
}
|
||||
constraint->mPositions[joint_num] = (cur_joint->getWorldPosition() - mPelvisp->getWorldPosition()) * ~mPelvisp->getWorldRotation();
|
||||
}
|
||||
|
||||
@@ -949,6 +957,10 @@ void LLKeyframeMotion::applyConstraint(JointConstraint* constraint, F32 time, U8
|
||||
}
|
||||
|
||||
LLJoint* root_joint = getJoint(shared_data->mJointStateIndices[shared_data->mChainLength]);
|
||||
if (! root_joint)
|
||||
{
|
||||
return;
|
||||
}
|
||||
LLVector3 root_pos = root_joint->getWorldPosition();
|
||||
// LLQuaternion root_rot =
|
||||
root_joint->getParent()->getWorldRotation();
|
||||
@@ -960,6 +972,11 @@ void LLKeyframeMotion::applyConstraint(JointConstraint* constraint, F32 time, U8
|
||||
for (joint_num = 0; joint_num <= shared_data->mChainLength; joint_num++)
|
||||
{
|
||||
LLJoint* cur_joint = getJoint(shared_data->mJointStateIndices[joint_num]);
|
||||
if (!cur_joint)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (joint_mask[cur_joint->getJointNum()] >= (0xff >> (7 - getPriority())))
|
||||
{
|
||||
// skip constraint
|
||||
@@ -1050,7 +1067,14 @@ void LLKeyframeMotion::applyConstraint(JointConstraint* constraint, F32 time, U8
|
||||
|
||||
if (shared_data->mChainLength)
|
||||
{
|
||||
LLQuaternion end_rot = getJoint(shared_data->mJointStateIndices[0])->getWorldRotation();
|
||||
LLJoint* end_joint = getJoint(shared_data->mJointStateIndices[0]);
|
||||
|
||||
if (!end_joint)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
LLQuaternion end_rot = end_joint->getWorldRotation();
|
||||
|
||||
// slam start and end of chain to the proper positions (rest of chain stays put)
|
||||
positions[0] = lerp(keyframe_source_pos, target_pos, weight);
|
||||
@@ -1059,7 +1083,14 @@ void LLKeyframeMotion::applyConstraint(JointConstraint* constraint, F32 time, U8
|
||||
// grab keyframe-specified positions of joints
|
||||
for (joint_num = 1; joint_num < shared_data->mChainLength; joint_num++)
|
||||
{
|
||||
LLVector3 kinematic_position = getJoint(shared_data->mJointStateIndices[joint_num])->getWorldPosition() +
|
||||
LLJoint* cur_joint = getJoint(shared_data->mJointStateIndices[joint_num]);
|
||||
|
||||
if (!cur_joint)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
LLVector3 kinematic_position = cur_joint->getWorldPosition() +
|
||||
(source_to_target * constraint->mJointLengthFractions[joint_num]);
|
||||
|
||||
// convert intermediate joint positions to world coordinates
|
||||
@@ -1105,7 +1136,17 @@ void LLKeyframeMotion::applyConstraint(JointConstraint* constraint, F32 time, U8
|
||||
for (joint_num = shared_data->mChainLength; joint_num > 0; joint_num--)
|
||||
{
|
||||
LLJoint* cur_joint = getJoint(shared_data->mJointStateIndices[joint_num]);
|
||||
|
||||
if (!cur_joint)
|
||||
{
|
||||
return;
|
||||
}
|
||||
LLJoint* child_joint = getJoint(shared_data->mJointStateIndices[joint_num - 1]);
|
||||
if (!child_joint)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
LLQuaternion parent_rot = cur_joint->getParent()->getWorldRotation();
|
||||
|
||||
LLQuaternion cur_rot = cur_joint->getWorldRotation();
|
||||
@@ -1139,7 +1180,6 @@ void LLKeyframeMotion::applyConstraint(JointConstraint* constraint, F32 time, U8
|
||||
cur_joint->setRotation(target_rot);
|
||||
}
|
||||
|
||||
LLJoint* end_joint = getJoint(shared_data->mJointStateIndices[0]);
|
||||
LLQuaternion end_local_rot = end_rot * ~end_joint->getParent()->getWorldRotation();
|
||||
|
||||
if (weight == 1.f)
|
||||
@@ -1162,12 +1202,18 @@ void LLKeyframeMotion::applyConstraint(JointConstraint* constraint, F32 time, U8
|
||||
constraint->mPositions[joint_num] = new_pos;
|
||||
}
|
||||
constraint->mFixupDistanceRMS *= 1.f / (constraint->mTotalLength * (F32)(shared_data->mChainLength - 1));
|
||||
constraint->mFixupDistanceRMS = fsqrtf(constraint->mFixupDistanceRMS);
|
||||
constraint->mFixupDistanceRMS = (F32) sqrt(constraint->mFixupDistanceRMS);
|
||||
|
||||
//reset old joint rots
|
||||
for (joint_num = 0; joint_num <= shared_data->mChainLength; joint_num++)
|
||||
{
|
||||
getJoint(shared_data->mJointStateIndices[joint_num])->setRotation(old_rots[joint_num]);
|
||||
LLJoint* cur_joint = getJoint(shared_data->mJointStateIndices[joint_num]);
|
||||
if (!cur_joint)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
cur_joint->setRotation(old_rots[joint_num]);
|
||||
}
|
||||
}
|
||||
// simple positional constraint (pelvis only)
|
||||
@@ -1816,7 +1862,15 @@ BOOL LLKeyframeMotion::deserialize(LLDataPacker& dp)
|
||||
constraintp->mJointStateIndices[i] = -1;
|
||||
for (U32 j = 0; j < mJointMotionList->getNumJointMotions(); j++)
|
||||
{
|
||||
if(getJoint(j) == joint)
|
||||
LLJoint* constraint_joint = getJoint(j);
|
||||
|
||||
if ( !constraint_joint )
|
||||
{
|
||||
llwarns << "Invalid joint " << j << llendl;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if(constraint_joint == joint)
|
||||
{
|
||||
constraintp->mJointStateIndices[i] = (S32)j;
|
||||
break;
|
||||
|
||||
@@ -357,8 +357,7 @@ BOOL LLKeyframeMotionParam::loadMotions()
|
||||
// open the file
|
||||
//-------------------------------------------------------------------------
|
||||
S32 fileSize = 0;
|
||||
LLAPRFile infile ;
|
||||
infile.open(path, LL_APR_R, LLAPRFile::global, &fileSize);
|
||||
LLAPRFile infile(path, LL_APR_R, &fileSize);
|
||||
apr_file_t* fp = infile.getFileHandle() ;
|
||||
if (!fp || fileSize == 0)
|
||||
{
|
||||
|
||||
@@ -89,6 +89,7 @@ LLJointState *LLPose::getNextJointState()
|
||||
//-----------------------------------------------------------------------------
|
||||
BOOL LLPose::addJointState(const LLPointer<LLJointState>& jointState)
|
||||
{
|
||||
llassert_always(jointState.notNull());
|
||||
if (mJointMap.find(jointState->getJoint()->getName()) == mJointMap.end())
|
||||
{
|
||||
mJointMap[jointState->getJoint()->getName()] = jointState;
|
||||
@@ -161,6 +162,7 @@ void LLPose::setWeight(F32 weight)
|
||||
// <edit>
|
||||
// there was a crash here
|
||||
// </edit>
|
||||
llassert_always(iter->second.notNull());
|
||||
iter->second->setWeight(weight);
|
||||
}
|
||||
mWeight = weight;
|
||||
|
||||
@@ -40,6 +40,8 @@
|
||||
#include "lljointstate.h"
|
||||
#include "lljoint.h"
|
||||
#include "llmap.h"
|
||||
#include "llpointer.h"
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
|
||||
@@ -210,8 +210,7 @@ LLFSMState* LLStateDiagram::getState(U32 state_id)
|
||||
|
||||
BOOL LLStateDiagram::saveDotFile(const std::string& filename)
|
||||
{
|
||||
LLAPRFile outfile ;
|
||||
outfile.open(filename, LL_APR_W, LLAPRFile::global);
|
||||
LLAPRFile outfile(filename, LL_APR_W);
|
||||
apr_file_t* dot_file = outfile.getFileHandle() ;
|
||||
|
||||
if (!dot_file)
|
||||
|
||||
@@ -15,11 +15,11 @@ include_directories(
|
||||
)
|
||||
|
||||
set(llcommon_SOURCE_FILES
|
||||
aiaprpool.cpp
|
||||
imageids.cpp
|
||||
indra_constants.cpp
|
||||
llapp.cpp
|
||||
llapr.cpp
|
||||
llaprpool.cpp
|
||||
llassettype.cpp
|
||||
llavatarname.cpp
|
||||
llbase32.cpp
|
||||
@@ -39,6 +39,7 @@ set(llcommon_SOURCE_FILES
|
||||
llfile.cpp
|
||||
llfindlocale.cpp
|
||||
llfixedbuffer.cpp
|
||||
llfoldertype.cpp
|
||||
llformat.cpp
|
||||
llframetimer.cpp
|
||||
llheartbeat.cpp
|
||||
@@ -57,12 +58,15 @@ set(llcommon_SOURCE_FILES
|
||||
llprocessor.cpp
|
||||
llqueuedthread.cpp
|
||||
llrand.cpp
|
||||
llrefcount.cpp
|
||||
llrun.cpp
|
||||
llscopedvolatileaprpool.h
|
||||
llsd.cpp
|
||||
llsdserialize.cpp
|
||||
llsdserialize_xml.cpp
|
||||
llsdutil.cpp
|
||||
llsecondlifeurls.cpp
|
||||
llsingleton.cpp
|
||||
llstat.cpp
|
||||
llstacktrace.cpp
|
||||
llstreamtools.cpp
|
||||
@@ -70,6 +74,7 @@ set(llcommon_SOURCE_FILES
|
||||
llstringtable.cpp
|
||||
llsys.cpp
|
||||
llthread.cpp
|
||||
llthreadsafequeue.cpp
|
||||
lltimer.cpp
|
||||
lluri.cpp
|
||||
lluuid.cpp
|
||||
@@ -84,7 +89,6 @@ set(llcommon_SOURCE_FILES
|
||||
set(llcommon_HEADER_FILES
|
||||
CMakeLists.txt
|
||||
|
||||
aiaprpool.h
|
||||
aithreadsafe.h
|
||||
bitpack.h
|
||||
ctype_workaround.h
|
||||
@@ -93,10 +97,12 @@ set(llcommon_HEADER_FILES
|
||||
indra_constants.h
|
||||
linden_common.h
|
||||
linked_lists.h
|
||||
llaccountingcost.h
|
||||
llagentconstants.h
|
||||
llavatarname.h
|
||||
llapp.h
|
||||
llapr.h
|
||||
llaprpool.h
|
||||
llassettype.h
|
||||
llassoclist.h
|
||||
llavatarconstants.h
|
||||
@@ -133,6 +139,7 @@ set(llcommon_HEADER_FILES
|
||||
llfile.h
|
||||
llfindlocale.h
|
||||
llfixedbuffer.h
|
||||
llfoldertype.h
|
||||
llformat.h
|
||||
llframetimer.h
|
||||
llhash.h
|
||||
@@ -157,6 +164,7 @@ set(llcommon_HEADER_FILES
|
||||
llmortician.h
|
||||
llnametable.h
|
||||
lloptioninterface.h
|
||||
llpointer.h
|
||||
llpreprocessor.h
|
||||
llpriqueuemap.h
|
||||
llprocesslauncher.h
|
||||
@@ -165,14 +173,17 @@ set(llcommon_HEADER_FILES
|
||||
llptrskipmap.h
|
||||
llqueuedthread.h
|
||||
llrand.h
|
||||
llrefcount.h
|
||||
llrun.h
|
||||
llscopedvolatileaprpool.h
|
||||
llrefcount.h
|
||||
llsafehandle.h
|
||||
llsd.h
|
||||
llsdserialize.h
|
||||
llsdserialize_xml.h
|
||||
llsdutil.h
|
||||
llsecondlifeurls.h
|
||||
llsimplehash.h
|
||||
llsingleton.h
|
||||
llskiplist.h
|
||||
llskipmap.h
|
||||
llstack.h
|
||||
@@ -186,7 +197,9 @@ set(llcommon_HEADER_FILES
|
||||
llstringtable.h
|
||||
llsys.h
|
||||
llthread.h
|
||||
llthreadsafequeue.h
|
||||
lltimer.h
|
||||
lltreeiterators.h
|
||||
lluri.h
|
||||
lluuid.h
|
||||
lluuidhashmap.h
|
||||
@@ -203,6 +216,7 @@ set(llcommon_HEADER_FILES
|
||||
stdenums.h
|
||||
stdtypes.h
|
||||
string_table.h
|
||||
stringize.h
|
||||
timer.h
|
||||
timing.h
|
||||
u64.h
|
||||
@@ -222,6 +236,7 @@ target_link_libraries(
|
||||
${EXPAT_LIBRARIES}
|
||||
${ZLIB_LIBRARIES}
|
||||
${WINDOWS_LIBRARIES}
|
||||
${BOOST_REGEX_LIBRARY}
|
||||
${CWDEBUG_LIBRARIES}
|
||||
${CORESERVICES_LIBRARY}
|
||||
)
|
||||
|
||||
@@ -175,7 +175,7 @@ protected:
|
||||
|
||||
// For use by AIThreadSafeDC
|
||||
AIThreadSafe(void) { }
|
||||
AIThreadSafe(AIAPRPool& parent) : mRWLock(parent) { }
|
||||
AIThreadSafe(LLAPRPool& parent) : mRWLock(parent) { }
|
||||
|
||||
public:
|
||||
// Only for use by AITHREADSAFE, see below.
|
||||
@@ -406,7 +406,7 @@ protected:
|
||||
friend struct AIRegisteredStateMachinesList;
|
||||
// For use by AIThreadSafeSimpleDC and AIRegisteredStateMachinesList.
|
||||
AIThreadSafeSimple(void) { }
|
||||
AIThreadSafeSimple(AIAPRPool& parent) : mMutex(parent) { }
|
||||
AIThreadSafeSimple(LLAPRPool& parent) : mMutex(parent) { }
|
||||
|
||||
public:
|
||||
// Only for use by AITHREADSAFESIMPLE, see below.
|
||||
@@ -471,7 +471,7 @@ public:
|
||||
|
||||
protected:
|
||||
// For use by AIThreadSafeSimpleDCRootPool
|
||||
AIThreadSafeSimpleDC(AIAPRPool& parent) : AIThreadSafeSimple<T>(parent) { new (AIThreadSafeSimple<T>::ptr()) T; }
|
||||
AIThreadSafeSimpleDC(LLAPRPool& parent) : AIThreadSafeSimple<T>(parent) { new (AIThreadSafeSimple<T>::ptr()) T; }
|
||||
};
|
||||
|
||||
// Helper class for AIThreadSafeSimpleDCRootPool to assure initialization of
|
||||
@@ -479,7 +479,7 @@ protected:
|
||||
class AIThreadSafeSimpleDCRootPool_pbase
|
||||
{
|
||||
protected:
|
||||
AIAPRRootPool mRootPool;
|
||||
LLAPRRootPool mRootPool;
|
||||
|
||||
private:
|
||||
template<typename T> friend class AIThreadSafeSimpleDCRootPool;
|
||||
@@ -489,7 +489,7 @@ private:
|
||||
/**
|
||||
* @brief A wrapper class for objects that need to be accessed by more than one thread.
|
||||
*
|
||||
* The same as AIThreadSafeSimpleDC except that this class creates its own AIAPRRootPool
|
||||
* The same as AIThreadSafeSimpleDC except that this class creates its own LLAPRRootPool
|
||||
* for the internally used mutexes and condition, instead of using the current threads
|
||||
* root pool. The advantage of this is that it can be used for objects that need to
|
||||
* be accessed from the destructors of global objects (after main). The disadvantage
|
||||
|
||||
@@ -324,6 +324,14 @@ const F32 CHAT_SHOUT_RADIUS = 100.f;
|
||||
const F32 CHAT_MAX_RADIUS = CHAT_SHOUT_RADIUS;
|
||||
const F32 CHAT_MAX_RADIUS_BY_TWO = CHAT_MAX_RADIUS / 2.f;
|
||||
|
||||
// squared editions of the above for distance checks
|
||||
const F32 CHAT_WHISPER_RADIUS_SQUARED = CHAT_WHISPER_RADIUS * CHAT_WHISPER_RADIUS;
|
||||
const F32 CHAT_NORMAL_RADIUS_SQUARED = CHAT_NORMAL_RADIUS * CHAT_NORMAL_RADIUS;
|
||||
const F32 CHAT_SHOUT_RADIUS_SQUARED = CHAT_SHOUT_RADIUS * CHAT_SHOUT_RADIUS;
|
||||
const F32 CHAT_MAX_RADIUS_SQUARED = CHAT_SHOUT_RADIUS_SQUARED;
|
||||
const F32 CHAT_MAX_RADIUS_BY_TWO_SQUARED = CHAT_MAX_RADIUS_BY_TWO * CHAT_MAX_RADIUS_BY_TWO;
|
||||
|
||||
|
||||
// this times above gives barely audible radius
|
||||
const F32 CHAT_BARELY_AUDIBLE_FACTOR = 2.0f;
|
||||
|
||||
|
||||
86
indra/llcommon/llaccountingcost.h
Normal file
86
indra/llcommon/llaccountingcost.h
Normal file
@@ -0,0 +1,86 @@
|
||||
/**
|
||||
* @file llaccountingcost.h
|
||||
* @
|
||||
*
|
||||
* $LicenseInfo:firstyear=2001&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2011, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_ACCOUNTINGQUOTA_H
|
||||
#define LL_ACCOUNTINGQUOTA_H
|
||||
|
||||
struct ParcelQuota
|
||||
{
|
||||
ParcelQuota( F32 ownerRenderCost, F32 ownerPhysicsCost, F32 ownerNetworkCost, F32 ownerSimulationCost,
|
||||
F32 groupRenderCost, F32 groupPhysicsCost, F32 groupNetworkCost, F32 groupSimulationCost,
|
||||
F32 otherRenderCost, F32 otherPhysicsCost, F32 otherNetworkCost, F32 otherSimulationCost,
|
||||
F32 tempRenderCost, F32 tempPhysicsCost, F32 tempNetworkCost, F32 tempSimulationCost,
|
||||
F32 selectedRenderCost, F32 selectedPhysicsCost, F32 selectedNetworkCost, F32 selectedSimulationCost,
|
||||
F32 parcelCapacity )
|
||||
: mOwnerRenderCost( ownerRenderCost ), mOwnerPhysicsCost( ownerPhysicsCost )
|
||||
, mOwnerNetworkCost( ownerNetworkCost ), mOwnerSimulationCost( ownerSimulationCost )
|
||||
, mGroupRenderCost( groupRenderCost ), mGroupPhysicsCost( groupPhysicsCost )
|
||||
, mGroupNetworkCost( groupNetworkCost ), mGroupSimulationCost( groupSimulationCost )
|
||||
, mOtherRenderCost( otherRenderCost ), mOtherPhysicsCost( otherPhysicsCost )
|
||||
, mOtherNetworkCost( otherNetworkCost ), mOtherSimulationCost( otherSimulationCost )
|
||||
, mTempRenderCost( tempRenderCost ), mTempPhysicsCost( tempPhysicsCost )
|
||||
, mTempNetworkCost( tempNetworkCost ), mTempSimulationCost( tempSimulationCost )
|
||||
, mSelectedRenderCost( tempRenderCost ), mSelectedPhysicsCost( tempPhysicsCost )
|
||||
, mSelectedNetworkCost( tempNetworkCost ), mSelectedSimulationCost( selectedSimulationCost )
|
||||
, mParcelCapacity( parcelCapacity )
|
||||
{
|
||||
}
|
||||
|
||||
ParcelQuota(){}
|
||||
F32 mOwnerRenderCost, mOwnerPhysicsCost, mOwnerNetworkCost, mOwnerSimulationCost;
|
||||
F32 mGroupRenderCost, mGroupPhysicsCost, mGroupNetworkCost, mGroupSimulationCost;
|
||||
F32 mOtherRenderCost, mOtherPhysicsCost, mOtherNetworkCost, mOtherSimulationCost;
|
||||
F32 mTempRenderCost, mTempPhysicsCost, mTempNetworkCost, mTempSimulationCost;
|
||||
F32 mSelectedRenderCost, mSelectedPhysicsCost, mSelectedNetworkCost, mSelectedSimulationCost;
|
||||
F32 mParcelCapacity;
|
||||
};
|
||||
|
||||
//SelectionQuota atm does not require a id
|
||||
struct SelectionCost
|
||||
{
|
||||
SelectionCost( /*LLTransactionID transactionId, */ F32 physicsCost, F32 networkCost, F32 simulationCost )
|
||||
//: mTransactionId( transactionId)
|
||||
: mPhysicsCost( physicsCost )
|
||||
, mNetworkCost( networkCost )
|
||||
, mSimulationCost( simulationCost )
|
||||
{
|
||||
}
|
||||
SelectionCost()
|
||||
: mPhysicsCost( 0.0f )
|
||||
, mNetworkCost( 0.0f )
|
||||
, mSimulationCost( 0.0f )
|
||||
{}
|
||||
|
||||
F32 mPhysicsCost, mNetworkCost, mSimulationCost;
|
||||
//LLTransactionID mTransactionId;
|
||||
};
|
||||
|
||||
typedef enum { Roots = 0 , Prims } eSelectionType;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
@@ -288,10 +288,13 @@ void LLApp::startErrorThread()
|
||||
// Start the error handling thread, which is responsible for taking action
|
||||
// when the app goes into the APP_STATUS_ERROR state
|
||||
//
|
||||
llinfos << "Starting error thread" << llendl;
|
||||
mThreadErrorp = new LLErrorThread();
|
||||
mThreadErrorp->setUserData((void *) this);
|
||||
mThreadErrorp->start();
|
||||
if(!mThreadErrorp)
|
||||
{
|
||||
llinfos << "Starting error thread" << llendl;
|
||||
mThreadErrorp = new LLErrorThread();
|
||||
mThreadErrorp->setUserData((void *) this);
|
||||
mThreadErrorp->start();
|
||||
}
|
||||
}
|
||||
|
||||
void LLApp::setErrorHandler(LLAppErrorHandler handler)
|
||||
|
||||
@@ -102,12 +102,12 @@ LLAPRFile::LLAPRFile()
|
||||
{
|
||||
}
|
||||
|
||||
LLAPRFile::LLAPRFile(const std::string& filename, apr_int32_t flags, access_t access_type)
|
||||
LLAPRFile::LLAPRFile(const std::string& filename, apr_int32_t flags, S32* sizep, access_t access_type)
|
||||
: mFile(NULL),
|
||||
mVolatileFilePoolp(NULL),
|
||||
mRegularFilePoolp(NULL)
|
||||
{
|
||||
open(filename, flags, access_type);
|
||||
open(filename, flags, access_type, sizep);
|
||||
}
|
||||
|
||||
LLAPRFile::~LLAPRFile()
|
||||
@@ -147,18 +147,19 @@ apr_status_t LLAPRFile::open(std::string const& filename, apr_int32_t flags, acc
|
||||
apr_status_t status;
|
||||
{
|
||||
apr_pool_t* apr_file_open_pool;
|
||||
if (access_type == local)
|
||||
// This is a temporary variable for a pool that is passed directly to apr_file_open below.
|
||||
if (access_type == short_lived)
|
||||
{
|
||||
// Use a "volatile" thread-local pool.
|
||||
mVolatileFilePoolp = &AIThreadLocalData::tldata().mVolatileAPRPool;
|
||||
mVolatileFilePoolp = &LLThreadLocalData::tldata().mVolatileAPRPool;
|
||||
// Access the pool and increment it's reference count.
|
||||
// The reference count of AIVolatileAPRPool objects will be decremented
|
||||
// The reference count of LLVolatileAPRPool objects will be decremented
|
||||
// again in LLAPRFile::close by calling mVolatileFilePoolp->clearVolatileAPRPool().
|
||||
apr_file_open_pool = mVolatileFilePoolp->getVolatileAPRPool();
|
||||
}
|
||||
else
|
||||
{
|
||||
mRegularFilePoolp = new AIAPRPool(AIThreadLocalData::tldata().mRootPool);
|
||||
mRegularFilePoolp = new LLAPRPool(LLThreadLocalData::tldata().mRootPool);
|
||||
apr_file_open_pool = (*mRegularFilePoolp)();
|
||||
}
|
||||
status = apr_file_open(&mFile, filename.c_str(), flags, APR_OS_DEFAULT, apr_file_open_pool);
|
||||
@@ -191,6 +192,10 @@ apr_status_t LLAPRFile::open(std::string const& filename, apr_int32_t flags, acc
|
||||
return status;
|
||||
}
|
||||
|
||||
apr_status_t LLAPRFile::open(const std::string& filename, apr_int32_t flags, BOOL use_global_pool)
|
||||
{
|
||||
return open(filename, flags, use_global_pool ? LLAPRFile::long_lived : LLAPRFile::short_lived);
|
||||
}
|
||||
// File I/O
|
||||
S32 LLAPRFile::read(void *buf, S32 nbytes)
|
||||
{
|
||||
|
||||
@@ -48,8 +48,8 @@
|
||||
#include "apr_atomic.h"
|
||||
#include "llstring.h"
|
||||
|
||||
class AIAPRPool;
|
||||
class AIVolatileAPRPool;
|
||||
class LLAPRPool;
|
||||
class LLVolatileAPRPool;
|
||||
|
||||
/**
|
||||
* @class LLScopedLock
|
||||
@@ -140,20 +140,21 @@ class LL_COMMON_API LLAPRFile : boost::noncopyable
|
||||
// make this non copyable since a copy closes the file
|
||||
private:
|
||||
apr_file_t* mFile ;
|
||||
AIVolatileAPRPool* mVolatileFilePoolp; // (Thread local) APR pool currently in use.
|
||||
AIAPRPool* mRegularFilePoolp; // ...or a regular pool.
|
||||
LLVolatileAPRPool* mVolatileFilePoolp; // (Thread local) APR pool currently in use.
|
||||
LLAPRPool* mRegularFilePoolp; // ...or a regular pool.
|
||||
|
||||
public:
|
||||
enum access_t {
|
||||
global, // Use a global pool for long-lived file accesses. This should really only happen from the main thread.
|
||||
local // Use a thread-local volatile pool for short file accesses.
|
||||
long_lived, // Use a global pool for long-lived file accesses.
|
||||
short_lived // Use a volatile pool for short-lived file accesses.
|
||||
};
|
||||
|
||||
LLAPRFile() ;
|
||||
LLAPRFile(const std::string& filename, apr_int32_t flags, access_t access_type);
|
||||
LLAPRFile(const std::string& filename, apr_int32_t flags, S32* sizep = NULL, access_t access_type = short_lived);
|
||||
~LLAPRFile() ;
|
||||
|
||||
apr_status_t open(const std::string& filename, apr_int32_t flags, access_t access_type, S32* sizep = NULL);
|
||||
apr_status_t open(const std::string& filename, apr_int32_t flags, access_t access_type = short_lived, S32* sizep = NULL);
|
||||
apr_status_t open(const std::string& filename, apr_int32_t flags, BOOL use_global_pool); //use global pool.
|
||||
apr_status_t close() ;
|
||||
|
||||
// Returns actual offset, -1 if seek fails
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* @file aiaprpool.cpp
|
||||
* @file LLAPRPool.cpp
|
||||
*
|
||||
* Copyright (c) 2010, Aleric Inglewood.
|
||||
*
|
||||
@@ -36,18 +36,18 @@
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "llerror.h"
|
||||
#include "aiaprpool.h"
|
||||
#include "llaprpool.h"
|
||||
#include "llthread.h"
|
||||
|
||||
// Create a subpool from parent.
|
||||
void AIAPRPool::create(AIAPRPool& parent)
|
||||
void LLAPRPool::create(LLAPRPool& parent)
|
||||
{
|
||||
llassert(!mPool); // Must be non-initialized.
|
||||
mParent = &parent;
|
||||
if (!mParent) // Using the default parameter?
|
||||
{
|
||||
// By default use the root pool of the current thread.
|
||||
mParent = &AIThreadLocalData::tldata().mRootPool;
|
||||
mParent = &LLThreadLocalData::tldata().mRootPool;
|
||||
}
|
||||
llassert(mParent->mPool); // Parent must be initialized.
|
||||
#if APR_HAS_THREADS
|
||||
@@ -72,7 +72,7 @@ void AIAPRPool::create(AIAPRPool& parent)
|
||||
}
|
||||
|
||||
// Destroy the (sub)pool, if any.
|
||||
void AIAPRPool::destroy(void)
|
||||
void LLAPRPool::destroy(void)
|
||||
{
|
||||
// Only do anything if we are not already (being) destroyed.
|
||||
if (mPool)
|
||||
@@ -92,12 +92,12 @@ void AIAPRPool::destroy(void)
|
||||
}
|
||||
}
|
||||
|
||||
bool AIAPRPool::parent_is_being_destructed(void)
|
||||
bool LLAPRPool::parent_is_being_destructed(void)
|
||||
{
|
||||
return mParent && (!mParent->mPool || mParent->parent_is_being_destructed());
|
||||
}
|
||||
|
||||
AIAPRInitialization::AIAPRInitialization(void)
|
||||
LLAPRInitialization::LLAPRInitialization(void)
|
||||
{
|
||||
static bool apr_initialized = false;
|
||||
|
||||
@@ -109,13 +109,13 @@ AIAPRInitialization::AIAPRInitialization(void)
|
||||
apr_initialized = true;
|
||||
}
|
||||
|
||||
bool AIAPRRootPool::sCountInitialized = false;
|
||||
apr_uint32_t volatile AIAPRRootPool::sCount;
|
||||
bool LLAPRRootPool::sCountInitialized = false;
|
||||
apr_uint32_t volatile LLAPRRootPool::sCount;
|
||||
|
||||
extern apr_thread_mutex_t* gLogMutexp;
|
||||
extern apr_thread_mutex_t* gCallStacksLogMutexp;
|
||||
apr_thread_mutex_t* gLogMutexp;
|
||||
apr_thread_mutex_t* gCallStacksLogMutexp;
|
||||
|
||||
AIAPRRootPool::AIAPRRootPool(void) : AIAPRInitialization(), AIAPRPool(0)
|
||||
LLAPRRootPool::LLAPRRootPool(void) : LLAPRInitialization(), LLAPRPool(0)
|
||||
{
|
||||
// sCountInitialized don't need locking because when we get here there is still only a single thread.
|
||||
if (!sCountInitialized)
|
||||
@@ -130,14 +130,14 @@ AIAPRRootPool::AIAPRRootPool(void) : AIAPRInitialization(), AIAPRPool(0)
|
||||
sCountInitialized = true;
|
||||
|
||||
// Initialize thread-local APR pool support.
|
||||
// Because this recursively calls AIAPRRootPool::AIAPRRootPool(void)
|
||||
// Because this recursively calls LLAPRRootPool::LLAPRRootPool(void)
|
||||
// it must be done last, so that sCount is already initialized.
|
||||
AIThreadLocalData::init();
|
||||
LLThreadLocalData::init();
|
||||
}
|
||||
apr_atomic_inc32(&sCount);
|
||||
}
|
||||
|
||||
AIAPRRootPool::~AIAPRRootPool()
|
||||
LLAPRRootPool::~LLAPRRootPool()
|
||||
{
|
||||
if (!apr_atomic_dec32(&sCount))
|
||||
{
|
||||
@@ -161,21 +161,21 @@ AIAPRRootPool::~AIAPRRootPool()
|
||||
gCallStacksLogMutexp = NULL;
|
||||
}
|
||||
|
||||
// Must destroy ALL, and therefore this last AIAPRRootPool, before terminating APR.
|
||||
static_cast<AIAPRRootPool*>(this)->destroy();
|
||||
// Must destroy ALL, and therefore this last LLAPRRootPool, before terminating APR.
|
||||
static_cast<LLAPRRootPool*>(this)->destroy();
|
||||
|
||||
apr_terminate();
|
||||
}
|
||||
}
|
||||
|
||||
//static
|
||||
AIAPRRootPool& AIAPRRootPool::get(void)
|
||||
LLAPRRootPool& LLAPRRootPool::get(void)
|
||||
{
|
||||
static AIAPRRootPool global_APRpool(0); // This is what used to be gAPRPoolp.
|
||||
static LLAPRRootPool global_APRpool(0); // This is what used to be gAPRPoolp.
|
||||
return global_APRpool;
|
||||
}
|
||||
|
||||
void AIVolatileAPRPool::clearVolatileAPRPool()
|
||||
void LLVolatileAPRPool::clearVolatileAPRPool()
|
||||
{
|
||||
llassert_always(mNumActiveRef > 0);
|
||||
if (--mNumActiveRef == 0)
|
||||
@@ -1,6 +1,6 @@
|
||||
/**
|
||||
* @file aiaprpool.h
|
||||
* @brief Implementation of AIAPRPool.
|
||||
* @file LLAPRPool.h
|
||||
* @brief Implementation of LLAPRPool.
|
||||
*
|
||||
* Copyright (c) 2010, Aleric Inglewood.
|
||||
*
|
||||
@@ -34,11 +34,15 @@
|
||||
* of subpools by threads other than the parent pool owner.
|
||||
*/
|
||||
|
||||
#ifndef AIAPRPOOL_H
|
||||
#define AIAPRPOOL_H
|
||||
#ifndef LL_LLAPRPOOL_H
|
||||
#define LL_LLAPRPOOL_H
|
||||
|
||||
#ifdef LL_WINDOWS
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4996)
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h> // Needed before including apr_portable.h
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#include "apr_portable.h"
|
||||
@@ -53,27 +57,27 @@ extern void ll_init_apr();
|
||||
* Usage of this class should be restricted to passing it to libapr-1 function calls that need it.
|
||||
*
|
||||
*/
|
||||
class LL_COMMON_API AIAPRPool
|
||||
class LL_COMMON_API LLAPRPool
|
||||
{
|
||||
protected:
|
||||
apr_pool_t* mPool; //!< Pointer to the underlaying pool. NULL if not initialized.
|
||||
AIAPRPool* mParent; //!< Pointer to the parent pool, if any. Only valid when mPool is non-zero.
|
||||
LLAPRPool* mParent; //!< Pointer to the parent pool, if any. Only valid when mPool is non-zero.
|
||||
apr_os_thread_t mOwner; //!< The thread that owns this memory pool. Only valid when mPool is non-zero.
|
||||
|
||||
public:
|
||||
//! Construct an uninitialized (destructed) pool.
|
||||
AIAPRPool(void) : mPool(NULL) { }
|
||||
LLAPRPool(void) : mPool(NULL) { }
|
||||
|
||||
//! Construct a subpool from an existing pool.
|
||||
// This is not a copy-constructor, this class doesn't have one!
|
||||
AIAPRPool(AIAPRPool& parent) : mPool(NULL) { create(parent); }
|
||||
LLAPRPool(LLAPRPool& parent) : mPool(NULL) { create(parent); }
|
||||
|
||||
//! Destruct the memory pool (free all of it's subpools and allocated memory).
|
||||
~AIAPRPool() { destroy(); }
|
||||
~LLAPRPool() { destroy(); }
|
||||
|
||||
protected:
|
||||
// Create a pool that is allocated from the Operating System. Only used by AIAPRRootPool.
|
||||
AIAPRPool(int) : mPool(NULL), mParent(NULL), mOwner(apr_os_thread_current())
|
||||
// Create a pool that is allocated from the Operating System. Only used by LLAPRRootPool.
|
||||
LLAPRPool(int) : mPool(NULL), mParent(NULL), mOwner(apr_os_thread_current())
|
||||
{
|
||||
apr_status_t const apr_pool_create_status = apr_pool_create(&mPool, NULL);
|
||||
llassert_always(apr_pool_create_status == APR_SUCCESS);
|
||||
@@ -84,15 +88,15 @@ protected:
|
||||
public:
|
||||
//! Create a subpool from parent. May only be called for an uninitialized/destroyed pool.
|
||||
// The default parameter causes the root pool of the current thread to be used.
|
||||
void create(AIAPRPool& parent = *static_cast<AIAPRPool*>(NULL));
|
||||
void create(LLAPRPool& parent = *static_cast<LLAPRPool*>(NULL));
|
||||
|
||||
//! Destroy the (sub)pool, if any.
|
||||
void destroy(void);
|
||||
|
||||
// Use some safebool idiom (http://www.artima.com/cppsource/safebool.html) rather than operator bool.
|
||||
typedef apr_pool_t* const AIAPRPool::* const bool_type;
|
||||
//! Return true if the pool is initialized.
|
||||
operator bool_type() const { return mPool ? &AIAPRPool::mPool : 0; }
|
||||
typedef LLAPRPool* const LLAPRPool::* const bool_type;
|
||||
/// Return true if the pool is initialized.
|
||||
operator bool_type() const { return mPool ? &LLAPRPool::mParent : 0; }
|
||||
|
||||
// Painful, but we have to either provide access to this, or wrap
|
||||
// every APR function call that needs a apr_pool_t* to be passed.
|
||||
@@ -133,7 +137,7 @@ public:
|
||||
|
||||
private:
|
||||
bool parent_is_being_destructed(void);
|
||||
static apr_status_t s_plain_cleanup(void* userdata) { return static_cast<AIAPRPool*>(userdata)->plain_cleanup(); }
|
||||
static apr_status_t s_plain_cleanup(void* userdata) { return static_cast<LLAPRPool*>(userdata)->plain_cleanup(); }
|
||||
|
||||
apr_status_t plain_cleanup(void)
|
||||
{
|
||||
@@ -148,30 +152,30 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
class AIAPRInitialization
|
||||
class LLAPRInitialization
|
||||
{
|
||||
public:
|
||||
AIAPRInitialization(void);
|
||||
LLAPRInitialization(void);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Root memory pool (allocates memory from the operating system).
|
||||
*
|
||||
* This class should only be used by AIThreadLocalData and AIThreadSafeSimpleDCRootPool_pbase
|
||||
* This class should only be used by LLThreadLocalData and AIThreadSafeSimpleDCRootPool_pbase
|
||||
* (and LLMutexRootPool when APR_HAS_THREADS isn't defined).
|
||||
*/
|
||||
class LL_COMMON_API AIAPRRootPool : public AIAPRInitialization, public AIAPRPool
|
||||
class LL_COMMON_API LLAPRRootPool : public LLAPRInitialization, public LLAPRPool
|
||||
{
|
||||
private:
|
||||
friend class AIThreadLocalData;
|
||||
friend class LLThreadLocalData;
|
||||
friend class AIThreadSafeSimpleDCRootPool_pbase;
|
||||
#if !APR_HAS_THREADS
|
||||
friend class LLMutexRootPool;
|
||||
#endif
|
||||
//! Construct a root memory pool.
|
||||
// Should only be used by AIThreadLocalData and AIThreadSafeSimpleDCRootPool_pbase.
|
||||
AIAPRRootPool(void);
|
||||
~AIAPRRootPool();
|
||||
// Should only be used by LLThreadLocalData and AIThreadSafeSimpleDCRootPool_pbase.
|
||||
LLAPRRootPool(void);
|
||||
~LLAPRRootPool();
|
||||
|
||||
private:
|
||||
// Keep track of how many root pools exist and when the last one is destructed.
|
||||
@@ -179,10 +183,10 @@ private:
|
||||
static apr_uint32_t volatile sCount;
|
||||
|
||||
public:
|
||||
// Return a global root pool that is independent of AIThreadLocalData.
|
||||
// Return a global root pool that is independent of LLThreadLocalData.
|
||||
// Normally you should not use this. Only use for early initialization
|
||||
// (before main) and deinitialization (after main).
|
||||
static AIAPRRootPool& get(void);
|
||||
static LLAPRRootPool& get(void);
|
||||
|
||||
#if APR_POOL_DEBUG
|
||||
void grab_ownership(void)
|
||||
@@ -194,11 +198,11 @@ public:
|
||||
#endif
|
||||
|
||||
private:
|
||||
// Used for constructing the Special Global Root Pool (returned by AIAPRRootPool::get).
|
||||
// Used for constructing the Special Global Root Pool (returned by LLAPRRootPool::get).
|
||||
// It is the same as the default constructor but omits to increment sCount. As a result,
|
||||
// we must be sure that at least one other AIAPRRootPool is created before termination
|
||||
// of the application (which is the case: we create one AIAPRRootPool per thread).
|
||||
AIAPRRootPool(int) : AIAPRInitialization(), AIAPRPool(0) { }
|
||||
// we must be sure that at least one other LLAPRRootPool is created before termination
|
||||
// of the application (which is the case: we create one LLAPRRootPool per thread).
|
||||
LLAPRRootPool(int) : LLAPRInitialization(), LLAPRPool(0) { }
|
||||
};
|
||||
|
||||
//! Volatile memory pool
|
||||
@@ -210,29 +214,33 @@ private:
|
||||
// the system memory to be allocated more efficiently and not
|
||||
// get scattered through RAM.
|
||||
//
|
||||
class LL_COMMON_API AIVolatileAPRPool : protected AIAPRPool
|
||||
class LL_COMMON_API LLVolatileAPRPool : protected LLAPRPool
|
||||
{
|
||||
public:
|
||||
AIVolatileAPRPool(void) : mNumActiveRef(0), mNumTotalRef(0) { }
|
||||
LLVolatileAPRPool(void) : mNumActiveRef(0), mNumTotalRef(0) { }
|
||||
|
||||
apr_pool_t* getVolatileAPRPool(void)
|
||||
{
|
||||
if (!mPool) create();
|
||||
++mNumActiveRef;
|
||||
++mNumTotalRef;
|
||||
return AIAPRPool::operator()();
|
||||
}
|
||||
void clearVolatileAPRPool(void);
|
||||
|
||||
bool isOld(void) const { return mNumTotalRef > FULL_VOLATILE_APR_POOL; }
|
||||
bool isUnused() const { return mNumActiveRef == 0; }
|
||||
|
||||
private:
|
||||
friend class LLScopedVolatileAPRPool;
|
||||
friend class LLAPRFile;
|
||||
apr_pool_t* getVolatileAPRPool(void) // The use of apr_pool_t is OK here.
|
||||
{
|
||||
if (!mPool) create();
|
||||
++mNumActiveRef;
|
||||
++mNumTotalRef;
|
||||
return LLAPRPool::operator()();
|
||||
}
|
||||
|
||||
private:
|
||||
S32 mNumActiveRef; // Number of active uses of the pool.
|
||||
S32 mNumTotalRef; // Number of total uses of the pool since last creation.
|
||||
|
||||
// Maximum number of references to AIVolatileAPRPool until the pool is recreated.
|
||||
// Maximum number of references to LLVolatileAPRPool until the pool is recreated.
|
||||
static S32 const FULL_VOLATILE_APR_POOL = 1024;
|
||||
};
|
||||
|
||||
#endif // AIAPRPOOL_H
|
||||
#endif // LLAPRPool_H
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "llassettype.h"
|
||||
#include "lldictionary.h"
|
||||
#include "llmemory.h"
|
||||
#include "llsingleton.h"
|
||||
|
||||
///----------------------------------------------------------------------------
|
||||
/// Class LLAssetType
|
||||
@@ -85,26 +86,29 @@ LLAssetDictionary::LLAssetDictionary()
|
||||
addEntry(LLAssetType::AT_OBJECT, new AssetEntry("OBJECT", "object", "object", true, false, false));
|
||||
addEntry(LLAssetType::AT_NOTECARD, new AssetEntry("NOTECARD", "notecard", "note card", true, false, true));
|
||||
addEntry(LLAssetType::AT_CATEGORY, new AssetEntry("CATEGORY", "category", "folder", true, false, false));
|
||||
addEntry(LLAssetType::AT_ROOT_CATEGORY, new AssetEntry("ROOT_CATEGORY", "root", "root", false, false, false));
|
||||
//addEntry(LLAssetType::AT_ROOT_CATEGORY, new AssetEntry("ROOT_CATEGORY", "root", "root", false, false, false));
|
||||
addEntry(LLAssetType::AT_LSL_TEXT, new AssetEntry("LSL_TEXT", "lsltext", "lsl2 script", true, false, false));
|
||||
addEntry(LLAssetType::AT_LSL_BYTECODE, new AssetEntry("LSL_BYTECODE", "lslbyte", "lsl bytecode", true, false, false));
|
||||
addEntry(LLAssetType::AT_TEXTURE_TGA, new AssetEntry("TEXTURE_TGA", "txtr_tga", "tga texture", true, false, false));
|
||||
addEntry(LLAssetType::AT_BODYPART, new AssetEntry("BODYPART", "bodypart", "body part", true, true, true));
|
||||
addEntry(LLAssetType::AT_TRASH, new AssetEntry("TRASH", "trash", "trash", false, false, false));
|
||||
addEntry(LLAssetType::AT_SNAPSHOT_CATEGORY, new AssetEntry("SNAPSHOT_CATEGORY", "snapshot", "snapshot", false, false, false));
|
||||
addEntry(LLAssetType::AT_LOST_AND_FOUND, new AssetEntry("LOST_AND_FOUND", "lstndfnd", "lost and found", false, false, false));
|
||||
//addEntry(LLAssetType::AT_TRASH, new AssetEntry("TRASH", "trash", "trash", false, false, false));
|
||||
//addEntry(LLAssetType::AT_SNAPSHOT_CATEGORY, new AssetEntry("SNAPSHOT_CATEGORY", "snapshot", "snapshot", false, false, false));
|
||||
//addEntry(LLAssetType::AT_LOST_AND_FOUND, new AssetEntry("LOST_AND_FOUND", "lstndfnd", "lost and found", false, false, false));
|
||||
addEntry(LLAssetType::AT_SOUND_WAV, new AssetEntry("SOUND_WAV", "snd_wav", "sound", true, false, false));
|
||||
addEntry(LLAssetType::AT_IMAGE_TGA, new AssetEntry("IMAGE_TGA", "img_tga", "targa image", true, false, false));
|
||||
addEntry(LLAssetType::AT_IMAGE_JPEG, new AssetEntry("IMAGE_JPEG", "jpeg", "jpeg image", true, false, false));
|
||||
addEntry(LLAssetType::AT_ANIMATION, new AssetEntry("ANIMATION", "animatn", "animation", true, true, true));
|
||||
addEntry(LLAssetType::AT_GESTURE, new AssetEntry("GESTURE", "gesture", "gesture", true, true, true));
|
||||
addEntry(LLAssetType::AT_SIMSTATE, new AssetEntry("SIMSTATE", "simstate", "simstate", false, false, false));
|
||||
addEntry(LLAssetType::AT_FAVORITE, new AssetEntry("FAVORITE", "favorite", "", false, false, false));
|
||||
//addEntry(LLAssetType::AT_FAVORITE, new AssetEntry("FAVORITE", "favorite", "", false, false, false));
|
||||
addEntry(LLAssetType::AT_LINK, new AssetEntry("LINK", "link", "sym link", false, false, true));
|
||||
addEntry(LLAssetType::AT_LINK_FOLDER, new AssetEntry("FOLDER_LINK", "link_f", "sym folder link", false, false, true));
|
||||
addEntry(LLAssetType::AT_CURRENT_OUTFIT, new AssetEntry("FOLDER_LINK", "current", "current outfit", false, false, false));
|
||||
addEntry(LLAssetType::AT_OUTFIT, new AssetEntry("OUTFIT", "outfit", "outfit", false, false, false));
|
||||
addEntry(LLAssetType::AT_MY_OUTFITS, new AssetEntry("MY_OUTFITS", "my_otfts", "my outfits", false, false, false));
|
||||
//addEntry(LLAssetType::AT_CURRENT_OUTFIT, new AssetEntry("FOLDER_LINK", "current", "current outfit", false, false, false));
|
||||
//addEntry(LLAssetType::AT_OUTFIT, new AssetEntry("OUTFIT", "outfit", "outfit", false, false, false));
|
||||
//addEntry(LLAssetType::AT_MY_OUTFITS, new AssetEntry("MY_OUTFITS", "my_otfts", "my outfits", false, false, false));
|
||||
#if MESH_ENABLED
|
||||
addEntry(LLAssetType::AT_MESH, new AssetEntry("MESH", "mesh", "mesh", false, false, false));
|
||||
#endif //MESH_ENABLED
|
||||
addEntry(LLAssetType::AT_NONE, new AssetEntry("NONE", "-1", NULL, false, false, false));
|
||||
};
|
||||
|
||||
@@ -206,47 +210,7 @@ LLAssetType::EType LLAssetType::lookupHumanReadable(const std::string& readable_
|
||||
return AT_NONE;
|
||||
}
|
||||
|
||||
EDragAndDropType LLAssetType::lookupDragAndDropType( EType asset )
|
||||
{
|
||||
switch( asset )
|
||||
{
|
||||
case AT_TEXTURE: return DAD_TEXTURE;
|
||||
case AT_SOUND: return DAD_SOUND;
|
||||
case AT_CALLINGCARD: return DAD_CALLINGCARD;
|
||||
case AT_LANDMARK: return DAD_LANDMARK;
|
||||
case AT_SCRIPT: return DAD_NONE;
|
||||
case AT_CLOTHING: return DAD_CLOTHING;
|
||||
case AT_OBJECT: return DAD_OBJECT;
|
||||
case AT_NOTECARD: return DAD_NOTECARD;
|
||||
case AT_CATEGORY: return DAD_CATEGORY;
|
||||
case AT_ROOT_CATEGORY: return DAD_ROOT_CATEGORY;
|
||||
case AT_LSL_TEXT: return DAD_SCRIPT;
|
||||
case AT_BODYPART: return DAD_BODYPART;
|
||||
case AT_ANIMATION: return DAD_ANIMATION;
|
||||
case AT_GESTURE: return DAD_GESTURE;
|
||||
case AT_FAVORITE: return DAD_CATEGORY;
|
||||
case AT_LINK: return DAD_LINK;
|
||||
case AT_LINK_FOLDER: return DAD_LINK;
|
||||
case AT_CURRENT_OUTFIT: return DAD_LINK;
|
||||
case AT_OUTFIT: return DAD_LINK;
|
||||
case AT_MY_OUTFITS: return DAD_CATEGORY;
|
||||
default: return DAD_NONE;
|
||||
};
|
||||
}
|
||||
|
||||
// static. Generate a good default description
|
||||
void LLAssetType::generateDescriptionFor(LLAssetType::EType type,
|
||||
std::string& desc)
|
||||
{
|
||||
const S32 BUF_SIZE = 30;
|
||||
char time_str[BUF_SIZE]; /* Flawfinder: ignore */
|
||||
time_t now;
|
||||
time(&now);
|
||||
memset(time_str, '\0', BUF_SIZE);
|
||||
strftime(time_str, BUF_SIZE - 1, "%Y-%m-%d %H:%M:%S ", localtime(&now));
|
||||
desc.assign(time_str);
|
||||
desc.append(LLAssetType::lookupHumanReadable(type));
|
||||
}
|
||||
//NOTE: LLAssetType::lookupDragAndDropType & LLAssetType::generateDescriptionFor moved to newview/llviewerassettype.h
|
||||
|
||||
// static
|
||||
bool LLAssetType::lookupCanLink(EType asset_type)
|
||||
|
||||
@@ -84,7 +84,7 @@ public:
|
||||
// A root category is a user's root inventory category. We
|
||||
// decided to expose it visually, so it seems logical to fold
|
||||
// it into the asset types.
|
||||
AT_ROOT_CATEGORY = 9,
|
||||
//AT_ROOT_CATEGORY = 9,
|
||||
|
||||
// The LSL is the brand spanking new scripting language. We've
|
||||
// split it into a text and bytecode representation.
|
||||
@@ -101,15 +101,15 @@ public:
|
||||
// This asset type is meant to only be used as a marker for a
|
||||
// category preferred type. Using this, we can throw things in
|
||||
// the trash before completely deleting.
|
||||
AT_TRASH = 14,
|
||||
//AT_TRASH = 14,
|
||||
|
||||
// This is a marker for a folder meant for snapshots. No
|
||||
// actual assets will be snapshots, though if there were, you
|
||||
// could interpret them as textures.
|
||||
AT_SNAPSHOT_CATEGORY = 15,
|
||||
//AT_SNAPSHOT_CATEGORY = 15,
|
||||
|
||||
// This is used to stuff lost&found items into
|
||||
AT_LOST_AND_FOUND = 16,
|
||||
//AT_LOST_AND_FOUND = 16,
|
||||
|
||||
// uncompressed sound
|
||||
AT_SOUND_WAV = 17,
|
||||
@@ -131,20 +131,26 @@ public:
|
||||
// simstate file
|
||||
AT_SIMSTATE = 22,
|
||||
|
||||
AT_FAVORITE = 23,
|
||||
//AT_FAVORITE = 23,
|
||||
|
||||
// Inventory symbolic link
|
||||
AT_LINK = 24,
|
||||
|
||||
// Inventory folder link
|
||||
AT_LINK_FOLDER = 25,
|
||||
|
||||
//AT_CURRENT_OUTFIT = 46,
|
||||
|
||||
AT_CURRENT_OUTFIT = 46,
|
||||
//AT_OUTFIT = 47,
|
||||
|
||||
AT_OUTFIT = 47,
|
||||
//AT_MY_OUTFITS = 48,
|
||||
|
||||
AT_MY_OUTFITS = 48,
|
||||
#if MESH_ENABLED
|
||||
AT_MESH = 49,
|
||||
// Mesh data in our proprietary SLM format
|
||||
|
||||
AT_COUNT = 50,
|
||||
#endif //MESH_ENABLED
|
||||
// +*********************************************+
|
||||
// | TO ADD AN ELEMENT TO THIS ENUM: |
|
||||
// +*********************************************+
|
||||
@@ -154,8 +160,10 @@ public:
|
||||
// | 4. ADD TO LLAssetType::mAssetTypeHumanNames |
|
||||
// +*********************************************+
|
||||
|
||||
AT_COUNT = 49,
|
||||
|
||||
//AT_COUNT = 49,
|
||||
#if !MESH_ENABLED
|
||||
AT_COUNT = 26,
|
||||
#endif //!MESH_ENABLED
|
||||
AT_NONE = -1
|
||||
};
|
||||
|
||||
@@ -169,12 +177,7 @@ public:
|
||||
static EType lookupHumanReadable(const std::string& readable_name);
|
||||
static const char* lookupHumanReadable(EType asset_type);
|
||||
|
||||
static EDragAndDropType lookupDragAndDropType( EType );
|
||||
|
||||
// Generate a good default description. You may want to add a verb
|
||||
// or agent name after this depending on your application.
|
||||
static void generateDescriptionFor(LLAssetType::EType type,
|
||||
std::string& desc);
|
||||
//NOTE: LLAssetType::lookupDragAndDropType & LLAssetType::generateDescriptionFor moved to newview/llviewerassettype.h
|
||||
|
||||
static EType getType(const std::string& desc_name);
|
||||
static const std::string& getDesc(EType asset_type);
|
||||
|
||||
@@ -25,10 +25,6 @@
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
/*
|
||||
Ported to Phoenix by Wolfspirit Magic.
|
||||
*/
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "llavatarname.h"
|
||||
@@ -52,7 +48,7 @@ LLAvatarName::LLAvatarName()
|
||||
mLegacyFirstName(),
|
||||
mLegacyLastName(),
|
||||
mIsDisplayNameDefault(false),
|
||||
mIsDummy(false),
|
||||
mIsTemporaryName(false),
|
||||
mExpires(F64_MAX),
|
||||
mNextUpdate(0.0)
|
||||
{ }
|
||||
@@ -94,21 +90,16 @@ void LLAvatarName::fromLLSD(const LLSD& sd)
|
||||
std::string LLAvatarName::getCompleteName(bool linefeed) const
|
||||
{
|
||||
std::string name;
|
||||
if (!mUsername.empty())
|
||||
if (mUsername.empty() || mIsDisplayNameDefault)
|
||||
// If the display name feature is off
|
||||
// OR this particular display name is defaulted (i.e. based on user name),
|
||||
// then display only the easier to read instance of the person's name.
|
||||
{
|
||||
if (linefeed)
|
||||
{
|
||||
name = mDisplayName + "\n(" + mUsername + ")";
|
||||
}
|
||||
else
|
||||
{
|
||||
name = mDisplayName + " (" + mUsername + ")";
|
||||
}
|
||||
name = mDisplayName;
|
||||
}
|
||||
else
|
||||
{
|
||||
// ...display names are off, legacy name is in mDisplayName
|
||||
name = mDisplayName;
|
||||
name = mDisplayName + (linefeed ? "\n(" : "(") + mUsername + ")";
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@ public:
|
||||
// Under error conditions, we may insert "dummy" records with
|
||||
// names like "???" into caches as placeholders. These can be
|
||||
// shown in UI, but are not serialized.
|
||||
bool mIsDummy;
|
||||
bool mIsTemporaryName;
|
||||
|
||||
// Names can change, so need to keep track of when name was
|
||||
// last checked.
|
||||
|
||||
@@ -56,7 +56,8 @@ typedef enum e_chat_type
|
||||
CHAT_TYPE_STOP = 5,
|
||||
CHAT_TYPE_DEBUG_MSG = 6,
|
||||
CHAT_TYPE_REGION = 7,
|
||||
CHAT_TYPE_OWNER = 8
|
||||
CHAT_TYPE_OWNER = 8,
|
||||
CHAT_TYPE_DIRECT = 9 // From llRegionSayTo()
|
||||
} EChatType;
|
||||
|
||||
typedef enum e_chat_audible_level
|
||||
|
||||
@@ -42,5 +42,6 @@ const U8 CLICK_ACTION_PAY = 3;
|
||||
const U8 CLICK_ACTION_OPEN = 4;
|
||||
const U8 CLICK_ACTION_PLAY = 5;
|
||||
const U8 CLICK_ACTION_OPEN_MEDIA = 6;
|
||||
|
||||
const U8 CLICK_ACTION_ZOOM = 7;
|
||||
// DO NOT CHANGE THE SEQUENCE OF THIS LIST!!
|
||||
#endif
|
||||
|
||||
@@ -38,6 +38,8 @@
|
||||
#include <iosfwd>
|
||||
#include <string>
|
||||
|
||||
#include "llpreprocessor.h"
|
||||
|
||||
#include "stdtypes.h"
|
||||
|
||||
/**
|
||||
|
||||
@@ -56,9 +56,8 @@
|
||||
#include "llsdserialize.h"
|
||||
#include "llstl.h"
|
||||
#include "lltimer.h"
|
||||
#include "aithreadsafe.h"
|
||||
|
||||
extern apr_thread_mutex_t* gCallStacksLogMutexp;
|
||||
#include "aithreadsafe.h"
|
||||
|
||||
namespace {
|
||||
#if !LL_WINDOWS
|
||||
@@ -881,8 +880,8 @@ You get:
|
||||
|
||||
*/
|
||||
|
||||
apr_thread_mutex_t* gLogMutexp;
|
||||
apr_thread_mutex_t* gCallStacksLogMutexp;
|
||||
extern apr_thread_mutex_t* gLogMutexp;
|
||||
extern apr_thread_mutex_t* gCallStacksLogMutexp;
|
||||
|
||||
namespace {
|
||||
bool checkLevelMap(const LevelMap& map, const std::string& key,
|
||||
|
||||
@@ -44,63 +44,40 @@
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
//std::list<LLEventTimer*> LLEventTimer::sActiveList;
|
||||
|
||||
LLEventTimer::LLEventTimer(F32 period)
|
||||
: mEventTimer()
|
||||
{
|
||||
mPeriod = period;
|
||||
//sActiveList.push_back(this);
|
||||
}
|
||||
|
||||
LLEventTimer::LLEventTimer(const LLDate& time)
|
||||
: mEventTimer()
|
||||
{
|
||||
mPeriod = (F32)(time.secondsSinceEpoch() - LLDate::now().secondsSinceEpoch());
|
||||
//sActiveList.push_back(this);
|
||||
}
|
||||
|
||||
|
||||
LLEventTimer::~LLEventTimer()
|
||||
LLEventTimer::~LLEventTimer()
|
||||
{
|
||||
//sActiveList.remove(this);
|
||||
}
|
||||
|
||||
//static
|
||||
void LLEventTimer::updateClass()
|
||||
{
|
||||
std::list<LLEventTimer*> completed_timers;
|
||||
|
||||
/*{
|
||||
for (std::list<LLEventTimer*>::iterator iter = sActiveList.begin(); iter != sActiveList.end(); )
|
||||
{
|
||||
LLEventTimer* timer = *iter++;
|
||||
F32 et = timer->mEventTimer.getElapsedTimeF32();
|
||||
if (timer->mEventTimer.getStarted() && et > timer->mPeriod) {
|
||||
timer->mEventTimer.reset();
|
||||
if ( timer->tick() )
|
||||
{
|
||||
completed_timers.push_back( timer );
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
for (instance_iter iter = beginInstances(); iter != endInstances(); )
|
||||
{
|
||||
LLInstanceTrackerScopedGuard guard;
|
||||
for (instance_iter iter = guard.beginInstances(); iter != guard.endInstances(); )
|
||||
{
|
||||
LLEventTimer& timer = *iter++;
|
||||
F32 et = timer.mEventTimer.getElapsedTimeF32();
|
||||
if (timer.mEventTimer.getStarted() && et > timer.mPeriod) {
|
||||
timer.mEventTimer.reset();
|
||||
if ( timer.tick() )
|
||||
{
|
||||
completed_timers.push_back( &timer );
|
||||
}
|
||||
LLEventTimer& timer = *iter++;
|
||||
F32 et = timer.mEventTimer.getElapsedTimeF32();
|
||||
if (timer.mEventTimer.getStarted() && et > timer.mPeriod) {
|
||||
timer.mEventTimer.reset();
|
||||
if ( timer.tick() )
|
||||
{
|
||||
completed_timers.push_back( &timer );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if ( completed_timers.size() > 0 )
|
||||
{
|
||||
for (std::list<LLEventTimer*>::iterator completed_iter = completed_timers.begin();
|
||||
|
||||
@@ -56,11 +56,6 @@ public:
|
||||
protected:
|
||||
LLTimer mEventTimer;
|
||||
F32 mPeriod;
|
||||
|
||||
//private:
|
||||
//list of active timers
|
||||
// static std::list<LLEventTimer*> sActiveList; // TODO should this be a vector
|
||||
};
|
||||
|
||||
|
||||
#endif //LL_EVENTTIMER_H
|
||||
|
||||
@@ -72,7 +72,12 @@ public:
|
||||
FTM_UPDATE_GRASS,
|
||||
FTM_UPDATE_TREE,
|
||||
FTM_UPDATE_AVATAR,
|
||||
|
||||
#if MESH_ENABLED
|
||||
FTM_UPDATE_RIGGED_VOLUME,
|
||||
FTM_SKIN_RIGGED,
|
||||
FTM_RIGGED_OCTREE,
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
// common render components
|
||||
FTM_SHADOW_GEOMETRY,
|
||||
FTM_SHADOW_RENDER,
|
||||
@@ -131,6 +136,12 @@ public:
|
||||
FTM_STATESORT,
|
||||
FTM_STATESORT_DRAWABLE,
|
||||
FTM_STATESORT_POSTSORT,
|
||||
#if MESH_ENABLED
|
||||
FTM_MESH_UPDATE,
|
||||
FTM_MESH_LOCK1,
|
||||
FTM_MESH_LOCK2,
|
||||
FTM_LOAD_MESH_LOD,
|
||||
#endif //MESH_ENABLED
|
||||
FTM_REBUILD_VBO,
|
||||
FTM_REBUILD_VOLUME_VB,
|
||||
FTM_REBUILD_BRIDGE_VB,
|
||||
|
||||
175
indra/llcommon/llfoldertype.cpp
Normal file
175
indra/llcommon/llfoldertype.cpp
Normal file
@@ -0,0 +1,175 @@
|
||||
/**
|
||||
* @file llfoldertype.cpp
|
||||
* @brief Implementatino of LLFolderType functionality.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2001&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2001-2010, Linden Research, Inc.
|
||||
*
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlife.com/developers/opensource/gplv2
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at
|
||||
* http://secondlife.com/developers/opensource/flossexception
|
||||
*
|
||||
* By copying, modifying or distributing this software, you acknowledge
|
||||
* that you have read and understood your obligations described above,
|
||||
* and agree to abide by those obligations.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* $/LicenseInfo$
|
||||
*
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "llfoldertype.h"
|
||||
#include "lldictionary.h"
|
||||
#include "llmemory.h"
|
||||
#include "llsingleton.h"
|
||||
|
||||
///----------------------------------------------------------------------------
|
||||
/// Class LLFolderType
|
||||
///----------------------------------------------------------------------------
|
||||
struct FolderEntry : public LLDictionaryEntry
|
||||
{
|
||||
FolderEntry(const std::string &type_name, // 8 character limit!
|
||||
bool is_protected) // can the viewer change categories of this type?
|
||||
:
|
||||
LLDictionaryEntry(type_name),
|
||||
mIsProtected(is_protected)
|
||||
{
|
||||
llassert(type_name.length() <= 8);
|
||||
}
|
||||
|
||||
const bool mIsProtected;
|
||||
};
|
||||
|
||||
class LLFolderDictionary : public LLSingleton<LLFolderDictionary>,
|
||||
public LLDictionary<LLFolderType::EType, FolderEntry>
|
||||
{
|
||||
public:
|
||||
LLFolderDictionary();
|
||||
protected:
|
||||
virtual LLFolderType::EType notFound() const
|
||||
{
|
||||
return LLFolderType::FT_NONE;
|
||||
}
|
||||
};
|
||||
|
||||
LLFolderDictionary::LLFolderDictionary()
|
||||
{
|
||||
// TYPE NAME PROTECTED
|
||||
// |-----------|---------|
|
||||
addEntry(LLFolderType::FT_TEXTURE, new FolderEntry("texture", TRUE));
|
||||
addEntry(LLFolderType::FT_SOUND, new FolderEntry("sound", TRUE));
|
||||
addEntry(LLFolderType::FT_CALLINGCARD, new FolderEntry("callcard", TRUE));
|
||||
addEntry(LLFolderType::FT_LANDMARK, new FolderEntry("landmark", TRUE));
|
||||
addEntry(LLFolderType::FT_CLOTHING, new FolderEntry("clothing", TRUE));
|
||||
addEntry(LLFolderType::FT_OBJECT, new FolderEntry("object", TRUE));
|
||||
addEntry(LLFolderType::FT_NOTECARD, new FolderEntry("notecard", TRUE));
|
||||
addEntry(LLFolderType::FT_ROOT_INVENTORY, new FolderEntry("root_inv", TRUE));
|
||||
addEntry(LLFolderType::FT_LSL_TEXT, new FolderEntry("lsltext", TRUE));
|
||||
addEntry(LLFolderType::FT_BODYPART, new FolderEntry("bodypart", TRUE));
|
||||
addEntry(LLFolderType::FT_TRASH, new FolderEntry("trash", TRUE));
|
||||
addEntry(LLFolderType::FT_SNAPSHOT_CATEGORY, new FolderEntry("snapshot", TRUE));
|
||||
addEntry(LLFolderType::FT_LOST_AND_FOUND, new FolderEntry("lstndfnd", TRUE));
|
||||
addEntry(LLFolderType::FT_ANIMATION, new FolderEntry("animatn", TRUE));
|
||||
addEntry(LLFolderType::FT_GESTURE, new FolderEntry("gesture", TRUE));
|
||||
addEntry(LLFolderType::FT_FAVORITE, new FolderEntry("favorite", TRUE));
|
||||
|
||||
for (S32 ensemble_num = S32(LLFolderType::FT_ENSEMBLE_START); ensemble_num <= S32(LLFolderType::FT_ENSEMBLE_END); ensemble_num++)
|
||||
{
|
||||
addEntry(LLFolderType::EType(ensemble_num), new FolderEntry("ensemble", FALSE));
|
||||
}
|
||||
|
||||
addEntry(LLFolderType::FT_CURRENT_OUTFIT, new FolderEntry("current", TRUE));
|
||||
addEntry(LLFolderType::FT_OUTFIT, new FolderEntry("outfit", FALSE));
|
||||
addEntry(LLFolderType::FT_MY_OUTFITS, new FolderEntry("my_otfts", TRUE));
|
||||
|
||||
addEntry(LLFolderType::FT_MESH, new FolderEntry("mesh", TRUE));
|
||||
|
||||
addEntry(LLFolderType::FT_INBOX, new FolderEntry("inbox", TRUE));
|
||||
addEntry(LLFolderType::FT_OUTBOX, new FolderEntry("outbox", TRUE));
|
||||
addEntry(LLFolderType::FT_BASIC_ROOT, new FolderEntry("basic_rt", TRUE));
|
||||
|
||||
addEntry(LLFolderType::FT_NONE, new FolderEntry("-1", FALSE));
|
||||
};
|
||||
|
||||
// static
|
||||
LLFolderType::EType LLFolderType::lookup(const std::string& name)
|
||||
{
|
||||
return LLFolderDictionary::getInstance()->lookup(name);
|
||||
}
|
||||
|
||||
// static
|
||||
const std::string &LLFolderType::lookup(LLFolderType::EType folder_type)
|
||||
{
|
||||
const FolderEntry *entry = LLFolderDictionary::getInstance()->lookup(folder_type);
|
||||
if (entry)
|
||||
{
|
||||
return entry->mName;
|
||||
}
|
||||
else
|
||||
{
|
||||
return badLookup();
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
// Only ensembles and plain folders aren't protected. "Protected" means
|
||||
// you can't change certain properties such as their type.
|
||||
bool LLFolderType::lookupIsProtectedType(EType folder_type)
|
||||
{
|
||||
const LLFolderDictionary *dict = LLFolderDictionary::getInstance();
|
||||
const FolderEntry *entry = dict->lookup(folder_type);
|
||||
if (entry)
|
||||
{
|
||||
return entry->mIsProtected;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// static
|
||||
bool LLFolderType::lookupIsEnsembleType(EType folder_type)
|
||||
{
|
||||
return (folder_type >= FT_ENSEMBLE_START &&
|
||||
folder_type <= FT_ENSEMBLE_END);
|
||||
}
|
||||
|
||||
// static
|
||||
LLAssetType::EType LLFolderType::folderTypeToAssetType(LLFolderType::EType folder_type)
|
||||
{
|
||||
if (LLAssetType::lookup(LLAssetType::EType(folder_type)) == LLAssetType::badLookup())
|
||||
{
|
||||
llwarns << "Converting to unknown asset type " << folder_type << llendl;
|
||||
}
|
||||
return (LLAssetType::EType)folder_type;
|
||||
}
|
||||
|
||||
// static
|
||||
LLFolderType::EType LLFolderType::assetTypeToFolderType(LLAssetType::EType asset_type)
|
||||
{
|
||||
if (LLFolderType::lookup(LLFolderType::EType(asset_type)) == LLFolderType::badLookup())
|
||||
{
|
||||
llwarns << "Converting to unknown folder type " << asset_type << llendl;
|
||||
}
|
||||
return (LLFolderType::EType)asset_type;
|
||||
}
|
||||
|
||||
// static
|
||||
const std::string &LLFolderType::badLookup()
|
||||
{
|
||||
static const std::string sBadLookup = "llfoldertype_bad_lookup";
|
||||
return sBadLookup;
|
||||
}
|
||||
118
indra/llcommon/llfoldertype.h
Normal file
118
indra/llcommon/llfoldertype.h
Normal file
@@ -0,0 +1,118 @@
|
||||
/**
|
||||
* @file llfoldertype.h
|
||||
* @brief Declaration of LLFolderType.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2001&license=viewergpl$
|
||||
*
|
||||
* Copyright (c) 2001-2010, Linden Research, Inc.
|
||||
*
|
||||
* Second Life Viewer Source Code
|
||||
* The source code in this file ("Source Code") is provided by Linden Lab
|
||||
* to you under the terms of the GNU General Public License, version 2.0
|
||||
* ("GPL"), unless you have obtained a separate licensing agreement
|
||||
* ("Other License"), formally executed by you and Linden Lab. Terms of
|
||||
* the GPL can be found in doc/GPL-license.txt in this distribution, or
|
||||
* online at http://secondlife.com/developers/opensource/gplv2
|
||||
*
|
||||
* There are special exceptions to the terms and conditions of the GPL as
|
||||
* it is applied to this Source Code. View the full text of the exception
|
||||
* in the file doc/FLOSS-exception.txt in this software distribution, or
|
||||
* online at
|
||||
* http://secondlife.com/developers/opensource/flossexception
|
||||
*
|
||||
* By copying, modifying or distributing this software, you acknowledge
|
||||
* that you have read and understood your obligations described above,
|
||||
* and agree to abide by those obligations.
|
||||
*
|
||||
* ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
|
||||
* WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* $/LicenseInfo$
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LL_LLFOLDERTYPE_H
|
||||
#define LL_LLFOLDERTYPE_H
|
||||
|
||||
#include <string>
|
||||
#include "llassettype.h"
|
||||
|
||||
// This class handles folder types (similar to assettype, except for folders)
|
||||
// and operations on those.
|
||||
class LL_COMMON_API LLFolderType
|
||||
{
|
||||
public:
|
||||
// ! BACKWARDS COMPATIBILITY ! Folder type enums must match asset type enums.
|
||||
enum EType
|
||||
{
|
||||
FT_TEXTURE = 0,
|
||||
|
||||
FT_SOUND = 1,
|
||||
|
||||
FT_CALLINGCARD = 2,
|
||||
|
||||
FT_LANDMARK = 3,
|
||||
|
||||
FT_CLOTHING = 5,
|
||||
|
||||
FT_OBJECT = 6,
|
||||
|
||||
FT_NOTECARD = 7,
|
||||
|
||||
FT_ROOT_INVENTORY = 8,
|
||||
// We'd really like to change this to 9 since AT_CATEGORY is 8,
|
||||
// but "My Inventory" has been type 8 for a long time.
|
||||
|
||||
FT_LSL_TEXT = 10,
|
||||
|
||||
FT_BODYPART = 13,
|
||||
|
||||
FT_TRASH = 14,
|
||||
|
||||
FT_SNAPSHOT_CATEGORY = 15,
|
||||
|
||||
FT_LOST_AND_FOUND = 16,
|
||||
|
||||
FT_ANIMATION = 20,
|
||||
|
||||
FT_GESTURE = 21,
|
||||
|
||||
FT_FAVORITE = 23,
|
||||
|
||||
FT_ENSEMBLE_START = 26,
|
||||
FT_ENSEMBLE_END = 45,
|
||||
// This range is reserved for special clothing folder types.
|
||||
|
||||
FT_CURRENT_OUTFIT = 46,
|
||||
FT_OUTFIT = 47,
|
||||
FT_MY_OUTFITS = 48,
|
||||
|
||||
FT_MESH = 49,
|
||||
|
||||
FT_INBOX = 50,
|
||||
FT_OUTBOX = 51,
|
||||
|
||||
FT_BASIC_ROOT = 52,
|
||||
|
||||
FT_COUNT,
|
||||
|
||||
FT_NONE = -1
|
||||
};
|
||||
|
||||
static EType lookup(const std::string& type_name);
|
||||
static const std::string& lookup(EType folder_type);
|
||||
|
||||
static bool lookupIsProtectedType(EType folder_type);
|
||||
static bool lookupIsEnsembleType(EType folder_type);
|
||||
|
||||
static LLAssetType::EType folderTypeToAssetType(LLFolderType::EType folder_type);
|
||||
static LLFolderType::EType assetTypeToFolderType(LLAssetType::EType asset_type);
|
||||
|
||||
static const std::string& badLookup(); // error string when a lookup fails
|
||||
|
||||
protected:
|
||||
LLFolderType() {}
|
||||
~LLFolderType() {}
|
||||
};
|
||||
|
||||
#endif // LL_LLFOLDERTYPE_H
|
||||
@@ -35,13 +35,15 @@
|
||||
//static
|
||||
void * & LLInstanceTrackerBase::getInstances(std::type_info const & info)
|
||||
{
|
||||
static std::map<std::string, void *> instances;
|
||||
typedef std::map<std::string, void *> InstancesMap;
|
||||
static InstancesMap instances;
|
||||
|
||||
std::string k = info.name();
|
||||
if(instances.find(k) == instances.end())
|
||||
{
|
||||
instances[k] = NULL;
|
||||
}
|
||||
|
||||
return instances[k];
|
||||
// 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;
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#define LL_LLINSTANCETRACKER_H
|
||||
|
||||
#include <map>
|
||||
#include <typeinfo>
|
||||
|
||||
#include "string_table.h"
|
||||
#include <boost/utility.hpp>
|
||||
@@ -48,7 +49,32 @@ class LL_COMMON_API LLInstanceTrackerBase : public boost::noncopyable
|
||||
{
|
||||
protected:
|
||||
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.
|
||||
struct StaticBase
|
||||
{
|
||||
StaticBase():
|
||||
sIterationNestDepth(0)
|
||||
{}
|
||||
S32 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
|
||||
@@ -56,15 +82,89 @@ class LL_COMMON_API LLInstanceTrackerBase : public boost::noncopyable
|
||||
template<typename T, typename KEY = T*>
|
||||
class LLInstanceTracker : public LLInstanceTrackerBase
|
||||
{
|
||||
typedef typename std::map<KEY, T*> InstanceMap;
|
||||
typedef LLInstanceTracker<T, KEY> MyT;
|
||||
typedef boost::function<const KEY&(typename InstanceMap::value_type&)> KeyGetter;
|
||||
typedef boost::function<T*(typename InstanceMap::value_type&)> InstancePtrGetter;
|
||||
typedef typename std::map<KEY, T*> InstanceMap;
|
||||
struct StaticData: public StaticBase
|
||||
{
|
||||
InstanceMap sMap;
|
||||
};
|
||||
static StaticData& getStatic() { return LLInstanceTrackerBase::getStatic<StaticData, MyT>(); }
|
||||
static InstanceMap& getMap_() { return getStatic().sMap; }
|
||||
|
||||
public:
|
||||
/// Dereferencing key_iter gives you a const KEY&
|
||||
typedef boost::transform_iterator<KeyGetter, typename InstanceMap::iterator> key_iter;
|
||||
/// Dereferencing instance_iter gives you a T&
|
||||
typedef boost::indirect_iterator< boost::transform_iterator<InstancePtrGetter, typename InstanceMap::iterator> > instance_iter;
|
||||
class instance_iter : public boost::iterator_facade<instance_iter, T, boost::forward_traversal_tag>
|
||||
{
|
||||
public:
|
||||
typedef boost::iterator_facade<instance_iter, T, boost::forward_traversal_tag> super_t;
|
||||
|
||||
instance_iter(const typename InstanceMap::iterator& it)
|
||||
: mIterator(it)
|
||||
{
|
||||
++getStatic().sIterationNestDepth;
|
||||
}
|
||||
|
||||
~instance_iter()
|
||||
{
|
||||
--getStatic().sIterationNestDepth;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
friend class boost::iterator_core_access;
|
||||
|
||||
void increment() { mIterator++; }
|
||||
bool equal(instance_iter const& other) const
|
||||
{
|
||||
return mIterator == other.mIterator;
|
||||
}
|
||||
|
||||
T& dereference() const
|
||||
{
|
||||
return *(mIterator->second);
|
||||
}
|
||||
|
||||
typename InstanceMap::iterator mIterator;
|
||||
};
|
||||
|
||||
class key_iter : public boost::iterator_facade<key_iter, KEY, boost::forward_traversal_tag>
|
||||
{
|
||||
public:
|
||||
typedef boost::iterator_facade<key_iter, KEY, boost::forward_traversal_tag> super_t;
|
||||
|
||||
key_iter(typename InstanceMap::iterator it)
|
||||
: mIterator(it)
|
||||
{
|
||||
++getStatic().sIterationNestDepth;
|
||||
}
|
||||
|
||||
key_iter(const key_iter& other)
|
||||
: mIterator(other.mIterator)
|
||||
{
|
||||
++getStatic().sIterationNestDepth;
|
||||
}
|
||||
|
||||
~key_iter()
|
||||
{
|
||||
--getStatic().sIterationNestDepth;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
friend class boost::iterator_core_access;
|
||||
|
||||
void increment() { mIterator++; }
|
||||
bool equal(key_iter const& other) const
|
||||
{
|
||||
return mIterator == other.mIterator;
|
||||
}
|
||||
|
||||
KEY& dereference() const
|
||||
{
|
||||
return const_cast<KEY&>(mIterator->first);
|
||||
}
|
||||
|
||||
typename InstanceMap::iterator mIterator;
|
||||
};
|
||||
|
||||
static T* getInstance(const KEY& k)
|
||||
{
|
||||
@@ -72,57 +172,51 @@ public:
|
||||
return (found == getMap_().end()) ? NULL : found->second;
|
||||
}
|
||||
|
||||
static instance_iter beginInstances()
|
||||
{
|
||||
return instance_iter(getMap_().begin());
|
||||
}
|
||||
|
||||
static instance_iter endInstances()
|
||||
{
|
||||
return instance_iter(getMap_().end());
|
||||
}
|
||||
|
||||
static S32 instanceCount() { return getMap_().size(); }
|
||||
|
||||
static key_iter beginKeys()
|
||||
{
|
||||
return boost::make_transform_iterator(getMap_().begin(),
|
||||
boost::bind(&InstanceMap::value_type::first, _1));
|
||||
return key_iter(getMap_().begin());
|
||||
}
|
||||
static key_iter endKeys()
|
||||
{
|
||||
return boost::make_transform_iterator(getMap_().end(),
|
||||
boost::bind(&InstanceMap::value_type::first, _1));
|
||||
return key_iter(getMap_().end());
|
||||
}
|
||||
static instance_iter beginInstances()
|
||||
{
|
||||
return instance_iter(boost::make_transform_iterator(getMap_().begin(),
|
||||
boost::bind(&InstanceMap::value_type::second, _1)));
|
||||
}
|
||||
static instance_iter endInstances()
|
||||
{
|
||||
return instance_iter(boost::make_transform_iterator(getMap_().end(),
|
||||
boost::bind(&InstanceMap::value_type::second, _1)));
|
||||
}
|
||||
static S32 instanceCount() { return getMap_().size(); }
|
||||
|
||||
protected:
|
||||
LLInstanceTracker(KEY key) { add_(key); }
|
||||
virtual ~LLInstanceTracker() { remove_(); }
|
||||
virtual ~LLInstanceTracker()
|
||||
{
|
||||
// it's unsafe to delete instances of this type while all instances are being iterated over.
|
||||
llassert_always(getStatic().sIterationNestDepth == 0);
|
||||
remove_();
|
||||
}
|
||||
virtual void setKey(KEY key) { remove_(); add_(key); }
|
||||
virtual const KEY& getKey() const { return mKey; }
|
||||
virtual const KEY& getKey() const { return mInstanceKey; }
|
||||
|
||||
private:
|
||||
void add_(KEY key)
|
||||
{
|
||||
mKey = key;
|
||||
mInstanceKey = key;
|
||||
getMap_()[key] = static_cast<T*>(this);
|
||||
}
|
||||
void remove_()
|
||||
{
|
||||
getMap_().erase(mKey);
|
||||
getMap_().erase(mInstanceKey);
|
||||
}
|
||||
|
||||
static InstanceMap& getMap_()
|
||||
{
|
||||
void * & instances = getInstances(typeid(MyT));
|
||||
if (! instances)
|
||||
{
|
||||
instances = new InstanceMap;
|
||||
}
|
||||
return * static_cast<InstanceMap*>(instances);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
KEY mKey;
|
||||
KEY mInstanceKey;
|
||||
};
|
||||
|
||||
/// explicit specialization for default case where KEY is T*
|
||||
@@ -130,73 +224,78 @@ private:
|
||||
template<typename T>
|
||||
class LLInstanceTracker<T, T*> : public LLInstanceTrackerBase
|
||||
{
|
||||
typedef typename std::set<T*> InstanceSet;
|
||||
typedef LLInstanceTracker<T, T*> MyT;
|
||||
typedef typename std::set<T*> InstanceSet;
|
||||
struct StaticData: public StaticBase
|
||||
{
|
||||
InstanceSet sSet;
|
||||
};
|
||||
static StaticData& getStatic() { return LLInstanceTrackerBase::getStatic<StaticData, MyT>(); }
|
||||
static InstanceSet& getSet_() { return getStatic().sSet; }
|
||||
|
||||
public:
|
||||
/// Dereferencing key_iter gives you a T* (since T* is the key)
|
||||
typedef typename InstanceSet::iterator key_iter;
|
||||
/// Dereferencing instance_iter gives you a T&
|
||||
typedef boost::indirect_iterator<key_iter> instance_iter;
|
||||
|
||||
/// for completeness of analogy with the generic implementation
|
||||
static T* getInstance(T* k) { return k; }
|
||||
static S32 instanceCount() { return getSet_().size(); }
|
||||
|
||||
// Instantiate this to get access to iterators for this type. It's a 'guard' in the sense
|
||||
// that it treats deletes of this type as errors as long as there is an instance of
|
||||
// this class alive in scope somewhere (i.e. deleting while iterating is bad).
|
||||
class LLInstanceTrackerScopedGuard
|
||||
class instance_iter : public boost::iterator_facade<instance_iter, T, boost::forward_traversal_tag>
|
||||
{
|
||||
public:
|
||||
LLInstanceTrackerScopedGuard()
|
||||
instance_iter(const typename InstanceSet::iterator& it)
|
||||
: mIterator(it)
|
||||
{
|
||||
++sIterationNestDepth;
|
||||
++getStatic().sIterationNestDepth;
|
||||
}
|
||||
|
||||
~LLInstanceTrackerScopedGuard()
|
||||
instance_iter(const instance_iter& other)
|
||||
: mIterator(other.mIterator)
|
||||
{
|
||||
--sIterationNestDepth;
|
||||
++getStatic().sIterationNestDepth;
|
||||
}
|
||||
|
||||
static instance_iter beginInstances() { return instance_iter(getSet_().begin()); }
|
||||
static instance_iter endInstances() { return instance_iter(getSet_().end()); }
|
||||
static key_iter beginKeys() { return getSet_().begin(); }
|
||||
static key_iter endKeys() { return getSet_().end(); }
|
||||
~instance_iter()
|
||||
{
|
||||
--getStatic().sIterationNestDepth;
|
||||
}
|
||||
|
||||
private:
|
||||
friend class boost::iterator_core_access;
|
||||
|
||||
void increment() { mIterator++; }
|
||||
bool equal(instance_iter const& other) const
|
||||
{
|
||||
return mIterator == other.mIterator;
|
||||
}
|
||||
|
||||
T& dereference() const
|
||||
{
|
||||
return **mIterator;
|
||||
}
|
||||
|
||||
typename InstanceSet::iterator mIterator;
|
||||
};
|
||||
|
||||
static instance_iter beginInstances() { return instance_iter(getSet_().begin()); }
|
||||
static instance_iter endInstances() { return instance_iter(getSet_().end()); }
|
||||
|
||||
protected:
|
||||
LLInstanceTracker()
|
||||
{
|
||||
// it's safe but unpredictable to create instances of this type while all instances are being iterated over. I hate unpredictable. This assert will probably be turned on early in the next development cycle.
|
||||
//llassert(sIterationNestDepth == 0);
|
||||
getSet_().insert(static_cast<T*>(this));
|
||||
}
|
||||
virtual ~LLInstanceTracker()
|
||||
{
|
||||
// it's unsafe to delete instances of this type while all instances are being iterated over.
|
||||
llassert(sIterationNestDepth == 0);
|
||||
llassert_always(getStatic().sIterationNestDepth == 0);
|
||||
getSet_().erase(static_cast<T*>(this));
|
||||
}
|
||||
|
||||
LLInstanceTracker(const LLInstanceTracker& other)
|
||||
{
|
||||
//llassert(sIterationNestDepth == 0);
|
||||
getSet_().insert(static_cast<T*>(this));
|
||||
}
|
||||
|
||||
static InstanceSet& getSet_()
|
||||
{
|
||||
void * & instances = getInstances(typeid(MyT));
|
||||
if (! instances)
|
||||
{
|
||||
instances = new InstanceSet;
|
||||
}
|
||||
return * static_cast<InstanceSet *>(instances);
|
||||
}
|
||||
|
||||
static S32 sIterationNestDepth;
|
||||
};
|
||||
|
||||
template <typename T> S32 LLInstanceTracker<T, T*>::sIterationNestDepth = 0;
|
||||
|
||||
#endif
|
||||
|
||||
@@ -118,6 +118,62 @@ public:
|
||||
THROTTLE_BLOCKED, // rate exceed, block key
|
||||
};
|
||||
|
||||
F64 getActionCount(const T& id)
|
||||
{
|
||||
U64 now = 0;
|
||||
if ( mIsRealtime )
|
||||
{
|
||||
now = LLKeyThrottleImpl<T>::getTime();
|
||||
}
|
||||
else
|
||||
{
|
||||
now = LLKeyThrottleImpl<T>::getFrame();
|
||||
}
|
||||
|
||||
if (now >= (m.startTime + m.intervalLength))
|
||||
{
|
||||
if (now < (m.startTime + 2 * m.intervalLength))
|
||||
{
|
||||
// prune old data
|
||||
delete m.prevMap;
|
||||
m.prevMap = m.currMap;
|
||||
m.currMap = new typename LLKeyThrottleImpl<T>::EntryMap;
|
||||
|
||||
m.startTime += m.intervalLength;
|
||||
}
|
||||
else
|
||||
{
|
||||
// lots of time has passed, all data is stale
|
||||
delete m.prevMap;
|
||||
delete m.currMap;
|
||||
m.prevMap = new typename LLKeyThrottleImpl<T>::EntryMap;
|
||||
m.currMap = new typename LLKeyThrottleImpl<T>::EntryMap;
|
||||
|
||||
m.startTime = now;
|
||||
}
|
||||
}
|
||||
|
||||
U32 prevCount = 0;
|
||||
|
||||
typename LLKeyThrottleImpl<T>::EntryMap::const_iterator prev = m.prevMap->find(id);
|
||||
if (prev != m.prevMap->end())
|
||||
{
|
||||
prevCount = prev->second.count;
|
||||
}
|
||||
|
||||
typename LLKeyThrottleImpl<T>::Entry& curr = (*m.currMap)[id];
|
||||
|
||||
// curr.count is the number of keys in
|
||||
// this current 'time slice' from the beginning of it until now
|
||||
// prevCount is the number of keys in the previous
|
||||
// time slice scaled to be one full time slice back from the current
|
||||
// (now) time.
|
||||
|
||||
// compute current, windowed rate
|
||||
F64 timeInCurrent = ((F64)(now - m.startTime) / m.intervalLength);
|
||||
F64 averageCount = curr.count + prevCount * (1.0 - timeInCurrent);
|
||||
return averageCount;
|
||||
}
|
||||
// call each time the key wants use
|
||||
State noteAction(const T& id, S32 weight = 1)
|
||||
{
|
||||
|
||||
@@ -48,6 +48,7 @@ const U32 AGENT_TYPING = 0x0200;
|
||||
const U32 AGENT_CROUCHING = 0x0400;
|
||||
const U32 AGENT_BUSY = 0x0800;
|
||||
const U32 AGENT_ALWAYS_RUN = 0x1000;
|
||||
const U32 AGENT_AUTOPILOT = 0x2000;
|
||||
|
||||
const S32 LSL_REMOTE_DATA_CHANNEL = 1;
|
||||
const S32 LSL_REMOTE_DATA_REQUEST = 2;
|
||||
@@ -184,6 +185,10 @@ const S32 OBJECT_VELOCITY = 5;
|
||||
const S32 OBJECT_OWNER = 6;
|
||||
const S32 OBJECT_GROUP = 7;
|
||||
const S32 OBJECT_CREATOR = 8;
|
||||
const S32 OBJECT_RUNNING_SCRIPT_COUNT = 9;
|
||||
const S32 OBJECT_TOTAL_SCRIPT_COUNT = 10;
|
||||
const S32 OBJECT_SCRIPT_MEMORY = 11;
|
||||
const S32 OBJECT_SCRIPT_TIME = 12;
|
||||
|
||||
// changed() event flags
|
||||
const U32 CHANGED_NONE = 0x0;
|
||||
@@ -198,5 +203,17 @@ const U32 CHANGED_OWNER = 0x80;
|
||||
const U32 CHANGED_REGION = 0x100;
|
||||
const U32 CHANGED_TELEPORT = 0x200;
|
||||
const U32 CHANGED_REGION_START = 0x400;
|
||||
const U32 CHANGED_MEDIA = 0x800;
|
||||
|
||||
// Possible error results
|
||||
const U32 LSL_STATUS_OK = 0;
|
||||
const U32 LSL_STATUS_MALFORMED_PARAMS = 1000;
|
||||
const U32 LSL_STATUS_TYPE_MISMATCH = 1001;
|
||||
const U32 LSL_STATUS_BOUNDS_ERROR = 1002;
|
||||
const U32 LSL_STATUS_NOT_FOUND = 1003;
|
||||
const U32 LSL_STATUS_NOT_SUPPORTED = 1004;
|
||||
const U32 LSL_STATUS_INTERNAL_ERROR = 1999;
|
||||
|
||||
// Start per-function errors below, starting at 2000:
|
||||
const U32 LSL_STATUS_WHITELIST_FAILED = 2001;
|
||||
#endif
|
||||
|
||||
@@ -276,37 +276,12 @@ void operator delete[] (void *p)
|
||||
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
LLRefCount::LLRefCount() :
|
||||
mRef(0)
|
||||
{
|
||||
}
|
||||
|
||||
LLRefCount::LLRefCount(const LLRefCount& other)
|
||||
: mRef(0)
|
||||
{
|
||||
}
|
||||
|
||||
LLRefCount::~LLRefCount()
|
||||
{
|
||||
if (mRef != 0)
|
||||
{
|
||||
llerrs << "deleting non-zero reference" << llendl;
|
||||
}
|
||||
}
|
||||
|
||||
LLRefCount& LLRefCount::operator=(const LLRefCount&)
|
||||
{
|
||||
// do nothing, since ref count is specific to *this* reference
|
||||
return *this;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#if defined(LL_WINDOWS)
|
||||
|
||||
U64 getCurrentRSS()
|
||||
U64 LLMemory::getCurrentRSS()
|
||||
{
|
||||
HANDLE self = GetCurrentProcess();
|
||||
PROCESS_MEMORY_COUNTERS counters;
|
||||
@@ -320,6 +295,20 @@ U64 getCurrentRSS()
|
||||
return counters.WorkingSetSize;
|
||||
}
|
||||
|
||||
//static
|
||||
U32 LLMemory::getWorkingSetSize()
|
||||
{
|
||||
PROCESS_MEMORY_COUNTERS pmc ;
|
||||
U32 ret = 0 ;
|
||||
|
||||
if (GetProcessMemoryInfo( GetCurrentProcess(), &pmc, sizeof(pmc)) )
|
||||
{
|
||||
ret = pmc.WorkingSetSize ;
|
||||
}
|
||||
|
||||
return ret ;
|
||||
}
|
||||
|
||||
#elif defined(LL_DARWIN)
|
||||
|
||||
/*
|
||||
@@ -344,7 +333,7 @@ U64 getCurrentRSS()
|
||||
// }
|
||||
// }
|
||||
|
||||
U64 getCurrentRSS()
|
||||
U64 LLMemory::getCurrentRSS()
|
||||
{
|
||||
U64 residentSize = 0;
|
||||
task_basic_info_data_t basicInfo;
|
||||
@@ -366,9 +355,14 @@ U64 getCurrentRSS()
|
||||
return residentSize;
|
||||
}
|
||||
|
||||
U32 LLMemory::getWorkingSetSize()
|
||||
{
|
||||
return 0 ;
|
||||
}
|
||||
|
||||
#elif defined(LL_LINUX)
|
||||
|
||||
U64 getCurrentRSS()
|
||||
U64 LLMemory::getCurrentRSS()
|
||||
{
|
||||
static const char statPath[] = "/proc/self/stat";
|
||||
LLFILE *fp = LLFile::fopen(statPath, "r");
|
||||
@@ -400,6 +394,10 @@ bail:
|
||||
return rss;
|
||||
}
|
||||
|
||||
U32 LLMemory::getWorkingSetSize()
|
||||
{
|
||||
return 0 ;
|
||||
}
|
||||
#elif LL_SOLARIS
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
@@ -407,7 +405,7 @@ bail:
|
||||
#define _STRUCTURED_PROC 1
|
||||
#include <sys/procfs.h>
|
||||
|
||||
U64 getCurrentRSS()
|
||||
U64 LLMemory::getCurrentRSS()
|
||||
{
|
||||
char path [LL_MAX_PATH]; /* Flawfinder: ignore */
|
||||
|
||||
@@ -428,11 +426,22 @@ U64 getCurrentRSS()
|
||||
|
||||
return((U64)proc_psinfo.pr_rssize * 1024);
|
||||
}
|
||||
|
||||
U32 LLMemory::getWorkingSetSize()
|
||||
{
|
||||
return 0 ;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
U64 getCurrentRSS()
|
||||
U64 LLMemory::getCurrentRSS()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
U32 LLMemory::getWorkingSetSize()
|
||||
{
|
||||
return 0 ;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -29,453 +29,115 @@
|
||||
* COMPLETENESS OR PERFORMANCE.
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
#ifndef LL_MEMORY_H
|
||||
#define LL_MEMORY_H
|
||||
#ifndef LLMEMORY_H
|
||||
#define LLMEMORY_H
|
||||
|
||||
|
||||
#include <new>
|
||||
#include <cstdlib>
|
||||
#if !LL_WINDOWS
|
||||
#include <stdint.h> // uintptr_t
|
||||
#endif
|
||||
|
||||
#include "llerror.h"
|
||||
|
||||
extern S32 gTotalDAlloc;
|
||||
extern S32 gTotalDAUse;
|
||||
extern S32 gDACount;
|
||||
|
||||
const U32 LLREFCOUNT_SENTINEL_VALUE = 0xAAAAAAAA;
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#if LL_DEBUG
|
||||
inline void* ll_aligned_malloc( size_t size, int align )
|
||||
{
|
||||
void* mem = malloc( size + (align - 1) + sizeof(void*) );
|
||||
char* aligned = ((char*)mem) + sizeof(void*);
|
||||
aligned += align - ((uintptr_t)aligned & (align - 1));
|
||||
|
||||
((void**)aligned)[-1] = mem;
|
||||
return aligned;
|
||||
}
|
||||
|
||||
inline void ll_aligned_free( void* ptr )
|
||||
{
|
||||
free( ((void**)ptr)[-1] );
|
||||
}
|
||||
|
||||
inline void* ll_aligned_malloc_16(size_t size) // returned hunk MUST be freed with ll_aligned_free_16().
|
||||
{
|
||||
#if defined(LL_WINDOWS)
|
||||
return _mm_malloc(size, 16);
|
||||
#elif defined(LL_DARWIN)
|
||||
return malloc(size); // default osx malloc is 16 byte aligned.
|
||||
#else
|
||||
void *rtn;
|
||||
if (LL_LIKELY(0 == posix_memalign(&rtn, 16, size)))
|
||||
return rtn;
|
||||
else // bad alignment requested, or out of memory
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void ll_aligned_free_16(void *p)
|
||||
{
|
||||
#if defined(LL_WINDOWS)
|
||||
_mm_free(p);
|
||||
#elif defined(LL_DARWIN)
|
||||
return free(p);
|
||||
#else
|
||||
free(p); // posix_memalign() is compatible with heap deallocator
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void* ll_aligned_malloc_32(size_t size) // returned hunk MUST be freed with ll_aligned_free_32().
|
||||
{
|
||||
#if defined(LL_WINDOWS)
|
||||
return _mm_malloc(size, 32);
|
||||
#elif defined(LL_DARWIN)
|
||||
return ll_aligned_malloc( size, 32 );
|
||||
#else
|
||||
void *rtn;
|
||||
if (LL_LIKELY(0 == posix_memalign(&rtn, 32, size)))
|
||||
return rtn;
|
||||
else // bad alignment requested, or out of memory
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void ll_aligned_free_32(void *p)
|
||||
{
|
||||
#if defined(LL_WINDOWS)
|
||||
_mm_free(p);
|
||||
#elif defined(LL_DARWIN)
|
||||
ll_aligned_free( p );
|
||||
#else
|
||||
free(p); // posix_memalign() is compatible with heap deallocator
|
||||
#endif
|
||||
}
|
||||
#else // LL_DEBUG
|
||||
// ll_aligned_foo are noops now that we use tcmalloc everywhere (tcmalloc aligns automatically at appropriate intervals)
|
||||
#define ll_aligned_malloc( size, align ) malloc(size)
|
||||
#define ll_aligned_free( ptr ) free(ptr)
|
||||
#define ll_aligned_malloc_16 malloc
|
||||
#define ll_aligned_free_16 free
|
||||
#define ll_aligned_malloc_32 malloc
|
||||
#define ll_aligned_free_32 free
|
||||
#endif // LL_DEBUG
|
||||
|
||||
class LL_COMMON_API LLMemory
|
||||
{
|
||||
public:
|
||||
static void initClass();
|
||||
static void cleanupClass();
|
||||
static void freeReserve();
|
||||
// Return the resident set size of the current process, in bytes.
|
||||
// Return value is zero if not known.
|
||||
static U64 getCurrentRSS();
|
||||
static U32 getWorkingSetSize();
|
||||
private:
|
||||
static char* reserveMem;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// RefCount objects should generally only be accessed by way of LLPointer<>'s
|
||||
// NOTE: LLPointer<LLFoo> x = new LLFoo(); MAY NOT BE THREAD SAFE
|
||||
// if LLFoo::LLFoo() does anything like put itself in an update queue.
|
||||
// The queue may get accessed before it gets assigned to x.
|
||||
// The correct implementation is:
|
||||
// LLPointer<LLFoo> x = new LLFoo; // constructor does not do anything interesting
|
||||
// x->instantiate(); // does stuff like place x into an update queue
|
||||
|
||||
// see llthread.h for LLThreadSafeRefCount
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
class LL_COMMON_API LLRefCount
|
||||
{
|
||||
protected:
|
||||
LLRefCount(const LLRefCount&);
|
||||
private:
|
||||
LLRefCount&operator=(const LLRefCount&);
|
||||
|
||||
protected:
|
||||
virtual ~LLRefCount(); // use unref()
|
||||
|
||||
public:
|
||||
LLRefCount();
|
||||
|
||||
void ref()
|
||||
{
|
||||
mRef++;
|
||||
}
|
||||
|
||||
S32 unref()
|
||||
{
|
||||
llassert(mRef >= 1);
|
||||
if (0 == --mRef)
|
||||
{
|
||||
delete this;
|
||||
return 0;
|
||||
}
|
||||
return mRef;
|
||||
}
|
||||
|
||||
S32 getNumRefs() const
|
||||
{
|
||||
return mRef;
|
||||
}
|
||||
|
||||
private:
|
||||
S32 mRef;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
// Note: relies on Type having ref() and unref() methods
|
||||
template <class Type> class LLPointer
|
||||
{
|
||||
public:
|
||||
|
||||
LLPointer() :
|
||||
mPointer(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
LLPointer(Type* ptr) :
|
||||
mPointer(ptr)
|
||||
{
|
||||
ref();
|
||||
}
|
||||
|
||||
LLPointer(const LLPointer<Type>& ptr) :
|
||||
mPointer(ptr.mPointer)
|
||||
{
|
||||
ref();
|
||||
}
|
||||
|
||||
// support conversion up the type hierarchy. See Item 45 in Effective C++, 3rd Ed.
|
||||
template<typename Subclass>
|
||||
LLPointer(const LLPointer<Subclass>& ptr) :
|
||||
mPointer(ptr.get())
|
||||
{
|
||||
ref();
|
||||
}
|
||||
|
||||
~LLPointer()
|
||||
{
|
||||
unref();
|
||||
}
|
||||
|
||||
Type* get() const { return mPointer; }
|
||||
const Type* operator->() const { return mPointer; }
|
||||
Type* operator->() { return mPointer; }
|
||||
const Type& operator*() const { return *mPointer; }
|
||||
Type& operator*() { return *mPointer; }
|
||||
|
||||
operator BOOL() const { return (mPointer != NULL); }
|
||||
operator bool() const { return (mPointer != NULL); }
|
||||
bool operator!() const { return (mPointer == NULL); }
|
||||
bool isNull() const { return (mPointer == NULL); }
|
||||
bool notNull() const { return (mPointer != NULL); }
|
||||
|
||||
operator Type*() const { return mPointer; }
|
||||
operator const Type*() const { return mPointer; }
|
||||
bool operator !=(Type* ptr) const { return (mPointer != ptr); }
|
||||
bool operator ==(Type* ptr) const { return (mPointer == ptr); }
|
||||
bool operator ==(const LLPointer<Type>& ptr) const { return (mPointer == ptr.mPointer); }
|
||||
bool operator < (const LLPointer<Type>& ptr) const { return (mPointer < ptr.mPointer); }
|
||||
bool operator > (const LLPointer<Type>& ptr) const { return (mPointer > ptr.mPointer); }
|
||||
|
||||
LLPointer<Type>& operator =(Type* ptr)
|
||||
{
|
||||
if( mPointer != ptr )
|
||||
{
|
||||
unref();
|
||||
mPointer = ptr;
|
||||
ref();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
LLPointer<Type>& operator =(const LLPointer<Type>& ptr)
|
||||
{
|
||||
if( mPointer != ptr.mPointer )
|
||||
{
|
||||
unref();
|
||||
mPointer = ptr.mPointer;
|
||||
ref();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// support assignment up the type hierarchy. See Item 45 in Effective C++, 3rd Ed.
|
||||
template<typename Subclass>
|
||||
LLPointer<Type>& operator =(const LLPointer<Subclass>& ptr)
|
||||
{
|
||||
if( mPointer != ptr.get() )
|
||||
{
|
||||
unref();
|
||||
mPointer = ptr.get();
|
||||
ref();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Just exchange the pointers, which will not change the reference counts.
|
||||
static void swap(LLPointer<Type>& a, LLPointer<Type>& b)
|
||||
{
|
||||
Type* temp = a.mPointer;
|
||||
a.mPointer = b.mPointer;
|
||||
b.mPointer = temp;
|
||||
}
|
||||
|
||||
protected:
|
||||
void ref()
|
||||
{
|
||||
if (mPointer)
|
||||
{
|
||||
mPointer->ref();
|
||||
}
|
||||
}
|
||||
|
||||
void unref()
|
||||
{
|
||||
if (mPointer)
|
||||
{
|
||||
Type *tempp = mPointer;
|
||||
mPointer = NULL;
|
||||
tempp->unref();
|
||||
if (mPointer != NULL)
|
||||
{
|
||||
llwarns << "Unreference did assignment to non-NULL because of destructor" << llendl;
|
||||
unref();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
Type* mPointer;
|
||||
};
|
||||
|
||||
//template <class Type>
|
||||
//class LLPointerTraits
|
||||
//{
|
||||
// static Type* null();
|
||||
//};
|
||||
//
|
||||
// Expands LLPointer to return a pointer to a special instance of class Type instead of NULL.
|
||||
// This is useful in instances where operations on NULL pointers are semantically safe and/or
|
||||
// when error checking occurs at a different granularity or in a different part of the code
|
||||
// than when referencing an object via a LLSafeHandle.
|
||||
//
|
||||
|
||||
template <class Type>
|
||||
class LLSafeHandle
|
||||
{
|
||||
public:
|
||||
LLSafeHandle() :
|
||||
mPointer(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
LLSafeHandle(Type* ptr) :
|
||||
mPointer(NULL)
|
||||
{
|
||||
assign(ptr);
|
||||
}
|
||||
|
||||
LLSafeHandle(const LLSafeHandle<Type>& ptr) :
|
||||
mPointer(NULL)
|
||||
{
|
||||
assign(ptr.mPointer);
|
||||
}
|
||||
|
||||
// support conversion up the type hierarchy. See Item 45 in Effective C++, 3rd Ed.
|
||||
template<typename Subclass>
|
||||
LLSafeHandle(const LLSafeHandle<Subclass>& ptr) :
|
||||
mPointer(NULL)
|
||||
{
|
||||
assign(ptr.get());
|
||||
}
|
||||
|
||||
~LLSafeHandle()
|
||||
{
|
||||
unref();
|
||||
}
|
||||
|
||||
const Type* operator->() const { return nonNull(mPointer); }
|
||||
Type* operator->() { return nonNull(mPointer); }
|
||||
|
||||
Type* get() const { return mPointer; }
|
||||
// we disallow these operations as they expose our null objects to direct manipulation
|
||||
// and bypass the reference counting semantics
|
||||
//const Type& operator*() const { return *nonNull(mPointer); }
|
||||
//Type& operator*() { return *nonNull(mPointer); }
|
||||
|
||||
operator BOOL() const { return mPointer != NULL; }
|
||||
operator bool() const { return mPointer != NULL; }
|
||||
bool operator!() const { return mPointer == NULL; }
|
||||
bool isNull() const { return mPointer == NULL; }
|
||||
bool notNull() const { return mPointer != NULL; }
|
||||
|
||||
|
||||
operator Type*() const { return mPointer; }
|
||||
operator const Type*() const { return mPointer; }
|
||||
bool operator !=(Type* ptr) const { return (mPointer != ptr); }
|
||||
bool operator ==(Type* ptr) const { return (mPointer == ptr); }
|
||||
bool operator ==(const LLSafeHandle<Type>& ptr) const { return (mPointer == ptr.mPointer); }
|
||||
bool operator < (const LLSafeHandle<Type>& ptr) const { return (mPointer < ptr.mPointer); }
|
||||
bool operator > (const LLSafeHandle<Type>& ptr) const { return (mPointer > ptr.mPointer); }
|
||||
|
||||
LLSafeHandle<Type>& operator =(Type* ptr)
|
||||
{
|
||||
assign(ptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
LLSafeHandle<Type>& operator =(const LLSafeHandle<Type>& ptr)
|
||||
{
|
||||
assign(ptr.mPointer);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// support assignment up the type hierarchy. See Item 45 in Effective C++, 3rd Ed.
|
||||
template<typename Subclass>
|
||||
LLSafeHandle<Type>& operator =(const LLSafeHandle<Subclass>& ptr)
|
||||
{
|
||||
assign(ptr.get());
|
||||
return *this;
|
||||
}
|
||||
|
||||
public:
|
||||
typedef Type* (*NullFunc)();
|
||||
static const NullFunc sNullFunc;
|
||||
|
||||
protected:
|
||||
void ref()
|
||||
{
|
||||
if (mPointer)
|
||||
{
|
||||
mPointer->ref();
|
||||
}
|
||||
}
|
||||
|
||||
void unref()
|
||||
{
|
||||
if (mPointer)
|
||||
{
|
||||
Type *tempp = mPointer;
|
||||
mPointer = NULL;
|
||||
tempp->unref();
|
||||
if (mPointer != NULL)
|
||||
{
|
||||
llwarns << "Unreference did assignment to non-NULL because of destructor" << llendl;
|
||||
unref();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void assign(Type* ptr)
|
||||
{
|
||||
if( mPointer != ptr )
|
||||
{
|
||||
unref();
|
||||
mPointer = ptr;
|
||||
ref();
|
||||
}
|
||||
}
|
||||
|
||||
static Type* nonNull(Type* ptr)
|
||||
{
|
||||
return ptr == NULL ? sNullFunc() : ptr;
|
||||
}
|
||||
|
||||
protected:
|
||||
Type* mPointer;
|
||||
};
|
||||
|
||||
// LLInitializedPointer is just a pointer with a default constructor that initializes it to NULL
|
||||
// NOT a smart pointer like LLPointer<>
|
||||
// Useful for example in std::map<int,LLInitializedPointer<LLFoo> >
|
||||
// (std::map uses the default constructor for creating new entries)
|
||||
template <typename T> class LLInitializedPointer
|
||||
{
|
||||
public:
|
||||
LLInitializedPointer() : mPointer(NULL) {}
|
||||
~LLInitializedPointer() { delete mPointer; }
|
||||
|
||||
const T* operator->() const { return mPointer; }
|
||||
T* operator->() { return mPointer; }
|
||||
const T& operator*() const { return *mPointer; }
|
||||
T& operator*() { return *mPointer; }
|
||||
operator const T*() const { return mPointer; }
|
||||
operator T*() { return mPointer; }
|
||||
T* operator=(T* x) { return (mPointer = x); }
|
||||
operator bool() const { return mPointer != NULL; }
|
||||
bool operator!() const { return mPointer == NULL; }
|
||||
bool operator==(T* rhs) { return mPointer == rhs; }
|
||||
bool operator==(const LLInitializedPointer<T>* rhs) { return mPointer == rhs.mPointer; }
|
||||
|
||||
protected:
|
||||
T* mPointer;
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
// 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.
|
||||
//
|
||||
// There are two ways to use LLSingleton. The first way is to inherit from it
|
||||
// while using the typename that you'd like to be static as the template
|
||||
// parameter, like so:
|
||||
//
|
||||
// class Foo: public LLSingleton<Foo>{};
|
||||
//
|
||||
// Foo& instance = Foo::instance();
|
||||
//
|
||||
// The second way is to use the singleton class directly, without inheritance:
|
||||
//
|
||||
// typedef LLSingleton<Foo> FooSingleton;
|
||||
//
|
||||
// Foo& instance = FooSingleton::instance();
|
||||
//
|
||||
// In this case, the class being managed as a singleton needs to provide an
|
||||
// initSingleton() method since the LLSingleton virtual method won't be
|
||||
// available
|
||||
//
|
||||
// As currently written, it is not thread-safe.
|
||||
template <typename T>
|
||||
class LLSingleton
|
||||
{
|
||||
static bool &needsInit()
|
||||
{
|
||||
static bool needs_init = true;
|
||||
return needs_init;
|
||||
}
|
||||
public:
|
||||
static bool instanceExists()
|
||||
{
|
||||
return !needsInit();
|
||||
}
|
||||
virtual ~LLSingleton() {}
|
||||
#ifdef LL_MSVC7
|
||||
// workaround for VC7 compiler bug
|
||||
// adapted from http://www.codeproject.com/KB/tips/VC2003MeyersSingletonBug.aspx
|
||||
// our version doesn't introduce a nested struct so that you can still declare LLSingleton<MyClass>
|
||||
// a friend and hide your constructor
|
||||
static T* getInstance()
|
||||
{
|
||||
LLSingleton<T> singleton;
|
||||
return singleton.vsHack();
|
||||
}
|
||||
|
||||
T* vsHack()
|
||||
#else
|
||||
static T* getInstance()
|
||||
#endif
|
||||
{
|
||||
static T instance;
|
||||
bool &needs_init = needsInit();
|
||||
if (needs_init)
|
||||
{
|
||||
needs_init = false;
|
||||
instance.initSingleton();
|
||||
}
|
||||
return &instance;
|
||||
}
|
||||
|
||||
static T& instance()
|
||||
{
|
||||
return *getInstance();
|
||||
}
|
||||
|
||||
private:
|
||||
virtual void initSingleton() {}
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
// Return the resident set size of the current process, in bytes.
|
||||
// Return value is zero if not known.
|
||||
LL_COMMON_API U64 getCurrentRSS();
|
||||
//EVENTUALLY REMOVE THESE:
|
||||
#include "llpointer.h"
|
||||
#include "llrefcount.h"
|
||||
#include "llsingleton.h"
|
||||
#include "llsafehandle.h"
|
||||
|
||||
#endif
|
||||
|
||||
@@ -74,9 +74,3 @@ void LLMortician::setZealous(BOOL b)
|
||||
{
|
||||
sDestroyImmediate = b;
|
||||
}
|
||||
|
||||
// static
|
||||
BOOL LLMortician::getZealous()
|
||||
{
|
||||
return sDestroyImmediate;
|
||||
}
|
||||
|
||||
@@ -46,7 +46,6 @@ public:
|
||||
|
||||
// sets destroy immediate true
|
||||
static void setZealous(BOOL b);
|
||||
static BOOL getZealous();
|
||||
|
||||
private:
|
||||
static BOOL sDestroyImmediate;
|
||||
|
||||
170
indra/llcommon/llpointer.h
Normal file
170
indra/llcommon/llpointer.h
Normal file
@@ -0,0 +1,170 @@
|
||||
/**
|
||||
* @file llpointer.h
|
||||
* @brief A reference-counted pointer for objects derived from LLRefCount
|
||||
*
|
||||
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
#ifndef LLPOINTER_H
|
||||
#define LLPOINTER_H
|
||||
|
||||
#include "llerror.h" // *TODO: consider eliminating this
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// RefCount objects should generally only be accessed by way of LLPointer<>'s
|
||||
// NOTE: LLPointer<LLFoo> x = new LLFoo(); MAY NOT BE THREAD SAFE
|
||||
// if LLFoo::LLFoo() does anything like put itself in an update queue.
|
||||
// The queue may get accessed before it gets assigned to x.
|
||||
// The correct implementation is:
|
||||
// LLPointer<LLFoo> x = new LLFoo; // constructor does not do anything interesting
|
||||
// x->instantiate(); // does stuff like place x into an update queue
|
||||
|
||||
// see llthread.h for LLThreadSafeRefCount
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
// Note: relies on Type having ref() and unref() methods
|
||||
template <class Type> class LLPointer
|
||||
{
|
||||
public:
|
||||
|
||||
LLPointer() :
|
||||
mPointer(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
LLPointer(Type* ptr) :
|
||||
mPointer(ptr)
|
||||
{
|
||||
ref();
|
||||
}
|
||||
|
||||
LLPointer(const LLPointer<Type>& ptr) :
|
||||
mPointer(ptr.mPointer)
|
||||
{
|
||||
ref();
|
||||
}
|
||||
|
||||
// support conversion up the type hierarchy. See Item 45 in Effective C++, 3rd Ed.
|
||||
template<typename Subclass>
|
||||
LLPointer(const LLPointer<Subclass>& ptr) :
|
||||
mPointer(ptr.get())
|
||||
{
|
||||
ref();
|
||||
}
|
||||
|
||||
~LLPointer()
|
||||
{
|
||||
unref();
|
||||
}
|
||||
|
||||
Type* get() const { return mPointer; }
|
||||
const Type* operator->() const { return mPointer; }
|
||||
Type* operator->() { return mPointer; }
|
||||
const Type& operator*() const { return *mPointer; }
|
||||
Type& operator*() { return *mPointer; }
|
||||
|
||||
operator BOOL() const { return (mPointer != NULL); }
|
||||
operator bool() const { return (mPointer != NULL); }
|
||||
bool operator!() const { return (mPointer == NULL); }
|
||||
bool isNull() const { return (mPointer == NULL); }
|
||||
bool notNull() const { return (mPointer != NULL); }
|
||||
|
||||
operator Type*() const { return mPointer; }
|
||||
bool operator !=(Type* ptr) const { return (mPointer != ptr); }
|
||||
bool operator ==(Type* ptr) const { return (mPointer == ptr); }
|
||||
bool operator ==(const LLPointer<Type>& ptr) const { return (mPointer == ptr.mPointer); }
|
||||
bool operator < (const LLPointer<Type>& ptr) const { return (mPointer < ptr.mPointer); }
|
||||
bool operator > (const LLPointer<Type>& ptr) const { return (mPointer > ptr.mPointer); }
|
||||
|
||||
LLPointer<Type>& operator =(Type* ptr)
|
||||
{
|
||||
if( mPointer != ptr )
|
||||
{
|
||||
unref();
|
||||
mPointer = ptr;
|
||||
ref();
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
LLPointer<Type>& operator =(const LLPointer<Type>& ptr)
|
||||
{
|
||||
if( mPointer != ptr.mPointer )
|
||||
{
|
||||
unref();
|
||||
mPointer = ptr.mPointer;
|
||||
ref();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// support assignment up the type hierarchy. See Item 45 in Effective C++, 3rd Ed.
|
||||
template<typename Subclass>
|
||||
LLPointer<Type>& operator =(const LLPointer<Subclass>& ptr)
|
||||
{
|
||||
if( mPointer != ptr.get() )
|
||||
{
|
||||
unref();
|
||||
mPointer = ptr.get();
|
||||
ref();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Just exchange the pointers, which will not change the reference counts.
|
||||
static void swap(LLPointer<Type>& a, LLPointer<Type>& b)
|
||||
{
|
||||
Type* temp = a.mPointer;
|
||||
a.mPointer = b.mPointer;
|
||||
b.mPointer = temp;
|
||||
}
|
||||
|
||||
protected:
|
||||
void ref()
|
||||
{
|
||||
if (mPointer)
|
||||
{
|
||||
mPointer->ref();
|
||||
}
|
||||
}
|
||||
|
||||
void unref()
|
||||
{
|
||||
if (mPointer)
|
||||
{
|
||||
Type *tempp = mPointer;
|
||||
mPointer = NULL;
|
||||
tempp->unref();
|
||||
if (mPointer != NULL)
|
||||
{
|
||||
llwarns << "Unreference did assignment to non-NULL because of destructor" << llendl;
|
||||
unref();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
Type* mPointer;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -107,7 +107,17 @@
|
||||
|
||||
#endif
|
||||
|
||||
// Deal with the differences on Windows
|
||||
|
||||
// Static linking with apr on windows needs to be declared.
|
||||
#if LL_WINDOWS && !LL_COMMON_LINK_SHARED
|
||||
#ifndef APR_DECLARE_STATIC
|
||||
#define APR_DECLARE_STATIC // For APR on Windows
|
||||
#endif
|
||||
#ifndef APU_DECLARE_STATIC
|
||||
#define APU_DECLARE_STATIC // For APR util on Windows
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(LL_WINDOWS)
|
||||
#define BOOST_REGEX_NO_LIB 1
|
||||
#define CURL_STATICLIB 1
|
||||
@@ -159,12 +169,19 @@
|
||||
#define LL_DLLIMPORT
|
||||
#endif // LL_WINDOWS
|
||||
|
||||
#ifdef llcommon_EXPORTS
|
||||
// Compiling llcommon (shared)
|
||||
#define LL_COMMON_API LL_DLLEXPORT
|
||||
#else // llcommon_EXPORTS
|
||||
// Using llcommon (shared)
|
||||
#define LL_COMMON_API LL_DLLIMPORT
|
||||
#endif // llcommon_EXPORTS
|
||||
#if LL_COMMON_LINK_SHARED
|
||||
// CMake automagically defines llcommon_EXPORTS only when building llcommon
|
||||
// sources, and only when llcommon is a shared library (i.e. when
|
||||
// LL_COMMON_LINK_SHARED). We must still test LL_COMMON_LINK_SHARED because
|
||||
// otherwise we can't distinguish between (non-llcommon source) and (llcommon
|
||||
// not shared).
|
||||
# if defined(llcommon_EXPORTS)
|
||||
# define LL_COMMON_API LL_DLLEXPORT
|
||||
# else //llcommon_EXPORTS
|
||||
# define LL_COMMON_API LL_DLLIMPORT
|
||||
# endif //llcommon_EXPORTS
|
||||
#else // LL_COMMON_LINK_SHARED
|
||||
# define LL_COMMON_API
|
||||
#endif // LL_COMMON_LINK_SHARED
|
||||
|
||||
#endif // not LL_LINDEN_PREPROCESSOR_H
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
#include <apr_file_io.h>
|
||||
#include <apr_thread_proc.h>
|
||||
#include "llprocesslauncher.h"
|
||||
#include "aiaprpool.h"
|
||||
#include "llaprpool.h"
|
||||
|
||||
#include <iostream>
|
||||
#if LL_DARWIN || LL_LINUX
|
||||
@@ -102,7 +102,7 @@ int LLProcessLauncher::launch(void)
|
||||
STARTUPINFOA sinfo;
|
||||
memset(&sinfo, 0, sizeof(sinfo));
|
||||
|
||||
std::string args = "\"" + mExecutable + "\"";
|
||||
std::string args = mExecutable;
|
||||
for(int i = 0; i < (int)mLaunchArguments.size(); i++)
|
||||
{
|
||||
args += " ";
|
||||
@@ -114,10 +114,30 @@ int LLProcessLauncher::launch(void)
|
||||
char *args2 = new char[args.size() + 1];
|
||||
strcpy(args2, args.c_str());
|
||||
|
||||
if( ! CreateProcessA( NULL, args2, NULL, NULL, FALSE, 0, NULL, NULL, &sinfo, &pinfo ) )
|
||||
const char * working_directory = 0;
|
||||
if(!mWorkingDir.empty()) working_directory = mWorkingDir.c_str();
|
||||
if( ! CreateProcessA( NULL, args2, NULL, NULL, FALSE, 0, NULL, working_directory, &sinfo, &pinfo ) )
|
||||
{
|
||||
// TODO: do better than returning the OS-specific error code on failure...
|
||||
result = GetLastError();
|
||||
|
||||
LPTSTR error_str = 0;
|
||||
if(
|
||||
FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
|
||||
NULL,
|
||||
result,
|
||||
0,
|
||||
(LPTSTR)&error_str,
|
||||
0,
|
||||
NULL)
|
||||
!= 0)
|
||||
{
|
||||
char message[256];
|
||||
wcstombs(message, error_str, 256);
|
||||
message[255] = 0;
|
||||
llwarns << "CreateProcessA failed: " << message << llendl;
|
||||
LocalFree(error_str);
|
||||
}
|
||||
|
||||
if(result == 0)
|
||||
{
|
||||
// Make absolutely certain we return a non-zero value on failure.
|
||||
@@ -326,7 +346,7 @@ int LLProcessLauncher::launch(void)
|
||||
// Set up a pipe to the child process for error reporting.
|
||||
apr_file_t* in;
|
||||
apr_file_t* out;
|
||||
AIAPRPool pool;
|
||||
LLAPRPool pool;
|
||||
pool.create();
|
||||
#if(APR_VERSION_MAJOR==1 && APR_VERSION_MINOR>=3 || APR_VERSION_MAJOR>1)
|
||||
apr_status_t status = apr_file_pipe_create_ex(&in, &out, APR_FULL_BLOCK, pool());
|
||||
|
||||
@@ -31,8 +31,9 @@
|
||||
|
||||
#include "linden_common.h"
|
||||
#include "llqueuedthread.h"
|
||||
|
||||
#include "llstl.h"
|
||||
#include "lltimer.h"
|
||||
#include "lltimer.h" // ms_sleep()
|
||||
|
||||
//============================================================================
|
||||
|
||||
@@ -41,7 +42,8 @@ LLQueuedThread::LLQueuedThread(const std::string& name, bool threaded) :
|
||||
LLThread(name),
|
||||
mThreaded(threaded),
|
||||
mIdleThread(TRUE),
|
||||
mNextHandle(0)
|
||||
mNextHandle(0),
|
||||
mStarted(FALSE)
|
||||
{
|
||||
if (mThreaded)
|
||||
{
|
||||
@@ -52,6 +54,10 @@ LLQueuedThread::LLQueuedThread(const std::string& name, bool threaded) :
|
||||
// MAIN THREAD
|
||||
LLQueuedThread::~LLQueuedThread()
|
||||
{
|
||||
if (!mThreaded)
|
||||
{
|
||||
endThread();
|
||||
}
|
||||
shutdown();
|
||||
// ~LLThread() will be called here
|
||||
}
|
||||
@@ -90,6 +96,7 @@ void LLQueuedThread::shutdown()
|
||||
if (req->getStatus() == STATUS_QUEUED || req->getStatus() == STATUS_INPROGRESS)
|
||||
{
|
||||
++active_count;
|
||||
req->setStatus(STATUS_ABORTED); // avoid assert in deleteRequest
|
||||
}
|
||||
req->deleteRequest();
|
||||
}
|
||||
@@ -105,6 +112,14 @@ void LLQueuedThread::shutdown()
|
||||
// virtual
|
||||
S32 LLQueuedThread::update(U32 max_time_ms)
|
||||
{
|
||||
if (!mStarted)
|
||||
{
|
||||
if (!mThreaded)
|
||||
{
|
||||
startThread();
|
||||
mStarted = TRUE;
|
||||
}
|
||||
}
|
||||
return updateQueue(max_time_ms);
|
||||
}
|
||||
|
||||
@@ -118,8 +133,11 @@ S32 LLQueuedThread::updateQueue(U32 max_time_ms)
|
||||
if (mThreaded)
|
||||
{
|
||||
pending = getPending();
|
||||
if(pending > 0)
|
||||
{
|
||||
unpause();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
while (pending > 0)
|
||||
@@ -349,9 +367,9 @@ bool LLQueuedThread::completeRequest(handle_t handle)
|
||||
#if _DEBUG
|
||||
// llinfos << llformat("LLQueuedThread::Completed req [%08d]",handle) << llendl;
|
||||
#endif
|
||||
//re insert to the queue to schedule for a delete later
|
||||
req->setStatus(STATUS_DELETE);
|
||||
mRequestQueue.insert(req);
|
||||
mRequestHash.erase(handle);
|
||||
req->deleteRequest();
|
||||
// check();
|
||||
res = true;
|
||||
}
|
||||
unlockData();
|
||||
@@ -395,19 +413,11 @@ S32 LLQueuedThread::processNextRequest()
|
||||
}
|
||||
req = *mRequestQueue.begin();
|
||||
mRequestQueue.erase(mRequestQueue.begin());
|
||||
|
||||
if(req->getStatus() == STATUS_DELETE)
|
||||
{
|
||||
mRequestHash.erase(req);
|
||||
req->deleteRequest();
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((req->getFlags() & FLAG_ABORT) || (mStatus == QUITTING))
|
||||
{
|
||||
req->setStatus(STATUS_ABORTED);
|
||||
req->finishRequest(false);
|
||||
if ((req->getFlags() & FLAG_AUTO_COMPLETE))
|
||||
if (req->getFlags() & FLAG_AUTO_COMPLETE)
|
||||
{
|
||||
mRequestHash.erase(req);
|
||||
req->deleteRequest();
|
||||
@@ -418,9 +428,11 @@ S32 LLQueuedThread::processNextRequest()
|
||||
llassert_always(req->getStatus() == STATUS_QUEUED);
|
||||
break;
|
||||
}
|
||||
U32 start_priority = 0 ;
|
||||
if (req)
|
||||
{
|
||||
req->setStatus(STATUS_INPROGRESS);
|
||||
start_priority = req->getPriority();
|
||||
}
|
||||
unlockData();
|
||||
|
||||
@@ -436,13 +448,12 @@ S32 LLQueuedThread::processNextRequest()
|
||||
{
|
||||
lockData();
|
||||
req->setStatus(STATUS_COMPLETE);
|
||||
|
||||
req->finishRequest(true);
|
||||
|
||||
if ((req->getFlags() & FLAG_AUTO_COMPLETE))
|
||||
if (req->getFlags() & FLAG_AUTO_COMPLETE)
|
||||
{
|
||||
mRequestHash.erase(req);
|
||||
req->deleteRequest();
|
||||
// check();
|
||||
}
|
||||
unlockData();
|
||||
}
|
||||
@@ -451,9 +462,8 @@ S32 LLQueuedThread::processNextRequest()
|
||||
lockData();
|
||||
req->setStatus(STATUS_QUEUED);
|
||||
mRequestQueue.insert(req);
|
||||
U32 priority = req->getPriority();
|
||||
unlockData();
|
||||
if (priority < PRIORITY_NORMAL)
|
||||
if (mThreaded && start_priority < PRIORITY_NORMAL)
|
||||
{
|
||||
ms_sleep(1); // sleep the thread a little
|
||||
}
|
||||
@@ -481,6 +491,7 @@ void LLQueuedThread::run()
|
||||
// call checPause() immediately so we don't try to do anything before the class is fully constructed
|
||||
checkPause();
|
||||
startThread();
|
||||
mStarted = TRUE;
|
||||
|
||||
while (1)
|
||||
{
|
||||
|
||||
@@ -184,7 +184,7 @@ public:
|
||||
void waitOnPending();
|
||||
void printQueueStats();
|
||||
|
||||
S32 getPending();
|
||||
virtual S32 getPending();
|
||||
bool getThreaded() { return mThreaded ? true : false; }
|
||||
|
||||
// Request accessors
|
||||
@@ -202,6 +202,7 @@ public:
|
||||
|
||||
protected:
|
||||
BOOL mThreaded; // if false, run on main thread and do updates during update()
|
||||
BOOL mStarted; // required when mThreaded is false to call startThread() from update()
|
||||
LLAtomic32<BOOL> mIdleThread; // request queue is empty (or we are quitting) and the thread is idle
|
||||
|
||||
typedef std::set<QueuedRequest*, queued_request_less> request_queue_t;
|
||||
|
||||
164
indra/llcommon/llrefcount.cpp
Normal file
164
indra/llcommon/llrefcount.cpp
Normal file
@@ -0,0 +1,164 @@
|
||||
/**
|
||||
* @file llrefcount.cpp
|
||||
* @brief Base class for reference counted objects for use with LLPointer
|
||||
*
|
||||
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "llrefcount.h"
|
||||
|
||||
#include "llerror.h"
|
||||
|
||||
#if LL_REF_COUNT_DEBUG
|
||||
#include "llthread.h"
|
||||
#include "llapr.h"
|
||||
#endif
|
||||
|
||||
LLRefCount::LLRefCount(const LLRefCount& other)
|
||||
: mRef(0)
|
||||
{
|
||||
#if LL_REF_COUNT_DEBUG
|
||||
if(gAPRPoolp)
|
||||
{
|
||||
mMutexp = new LLMutex(gAPRPoolp) ;
|
||||
}
|
||||
else
|
||||
{
|
||||
mMutexp = NULL ;
|
||||
}
|
||||
mCrashAtUnlock = FALSE ;
|
||||
#endif
|
||||
}
|
||||
|
||||
LLRefCount& LLRefCount::operator=(const LLRefCount&)
|
||||
{
|
||||
// do nothing, since ref count is specific to *this* reference
|
||||
return *this;
|
||||
}
|
||||
|
||||
LLRefCount::LLRefCount() :
|
||||
mRef(0)
|
||||
{
|
||||
#if LL_REF_COUNT_DEBUG
|
||||
if(gAPRPoolp)
|
||||
{
|
||||
mMutexp = new LLMutex(gAPRPoolp) ;
|
||||
}
|
||||
else
|
||||
{
|
||||
mMutexp = NULL ;
|
||||
}
|
||||
mCrashAtUnlock = FALSE ;
|
||||
#endif
|
||||
}
|
||||
|
||||
LLRefCount::~LLRefCount()
|
||||
{
|
||||
if (mRef != 0)
|
||||
{
|
||||
llerrs << "deleting non-zero reference" << llendl;
|
||||
}
|
||||
|
||||
#if LL_REF_COUNT_DEBUG
|
||||
if(gAPRPoolp)
|
||||
{
|
||||
delete mMutexp ;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if LL_REF_COUNT_DEBUG
|
||||
void LLRefCount::ref() const
|
||||
{
|
||||
if(mMutexp)
|
||||
{
|
||||
if(mMutexp->isLocked())
|
||||
{
|
||||
mCrashAtUnlock = TRUE ;
|
||||
llerrs << "the mutex is locked by the thread: " << mLockedThreadID
|
||||
<< " Current thread: " << LLThread::currentID() << llendl ;
|
||||
}
|
||||
|
||||
mMutexp->lock() ;
|
||||
mLockedThreadID = LLThread::currentID() ;
|
||||
|
||||
mRef++;
|
||||
|
||||
if(mCrashAtUnlock)
|
||||
{
|
||||
while(1); //crash here.
|
||||
}
|
||||
mMutexp->unlock() ;
|
||||
}
|
||||
else
|
||||
{
|
||||
mRef++;
|
||||
}
|
||||
}
|
||||
|
||||
S32 LLRefCount::unref() const
|
||||
{
|
||||
if(mMutexp)
|
||||
{
|
||||
if(mMutexp->isLocked())
|
||||
{
|
||||
mCrashAtUnlock = TRUE ;
|
||||
llerrs << "the mutex is locked by the thread: " << mLockedThreadID
|
||||
<< " Current thread: " << LLThread::currentID() << llendl ;
|
||||
}
|
||||
|
||||
mMutexp->lock() ;
|
||||
mLockedThreadID = LLThread::currentID() ;
|
||||
|
||||
llassert(mRef >= 1);
|
||||
if (0 == --mRef)
|
||||
{
|
||||
if(mCrashAtUnlock)
|
||||
{
|
||||
while(1); //crash here.
|
||||
}
|
||||
mMutexp->unlock() ;
|
||||
|
||||
delete this;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(mCrashAtUnlock)
|
||||
{
|
||||
while(1); //crash here.
|
||||
}
|
||||
mMutexp->unlock() ;
|
||||
return mRef;
|
||||
}
|
||||
else
|
||||
{
|
||||
llassert(mRef >= 1);
|
||||
if (0 == --mRef)
|
||||
{
|
||||
delete this;
|
||||
return 0;
|
||||
}
|
||||
return mRef;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
89
indra/llcommon/llrefcount.h
Normal file
89
indra/llcommon/llrefcount.h
Normal file
@@ -0,0 +1,89 @@
|
||||
/**
|
||||
* @file llrefcount.h
|
||||
* @brief Base class for reference counted objects for use with LLPointer
|
||||
*
|
||||
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
#ifndef LLREFCOUNT_H
|
||||
#define LLREFCOUNT_H
|
||||
|
||||
#include <boost/noncopyable.hpp>
|
||||
|
||||
#define LL_REF_COUNT_DEBUG 0
|
||||
#if LL_REF_COUNT_DEBUG
|
||||
class LLMutex ;
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// RefCount objects should generally only be accessed by way of LLPointer<>'s
|
||||
// see llthread.h for LLThreadSafeRefCount
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
class LL_COMMON_API LLRefCount
|
||||
{
|
||||
protected:
|
||||
LLRefCount(const LLRefCount& other);
|
||||
LLRefCount& operator=(const LLRefCount&);
|
||||
virtual ~LLRefCount(); // use unref()
|
||||
|
||||
public:
|
||||
LLRefCount();
|
||||
|
||||
#if LL_REF_COUNT_DEBUG
|
||||
void ref() const ;
|
||||
S32 unref() const ;
|
||||
#else
|
||||
inline void ref() const
|
||||
{
|
||||
mRef++;
|
||||
}
|
||||
|
||||
inline S32 unref() const
|
||||
{
|
||||
llassert(mRef >= 1);
|
||||
if (0 == --mRef)
|
||||
{
|
||||
delete this;
|
||||
return 0;
|
||||
}
|
||||
return mRef;
|
||||
}
|
||||
#endif
|
||||
|
||||
//NOTE: when passing around a const LLRefCount object, this can return different results
|
||||
// at different types, since mRef is mutable
|
||||
S32 getNumRefs() const
|
||||
{
|
||||
return mRef;
|
||||
}
|
||||
|
||||
private:
|
||||
mutable S32 mRef;
|
||||
|
||||
#if LL_REF_COUNT_DEBUG
|
||||
LLMutex* mMutexp ;
|
||||
mutable U32 mLockedThreadID ;
|
||||
mutable BOOL mCrashAtUnlock ;
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif
|
||||
162
indra/llcommon/llsafehandle.h
Normal file
162
indra/llcommon/llsafehandle.h
Normal file
@@ -0,0 +1,162 @@
|
||||
/**
|
||||
* @file llsafehandle.h
|
||||
* @brief Reference-counted object where Object() is valid, not NULL.
|
||||
*
|
||||
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
#ifndef LLSAFEHANDLE_H
|
||||
#define LLSAFEHANDLE_H
|
||||
|
||||
#include "llerror.h" // *TODO: consider eliminating this
|
||||
|
||||
// Expands LLPointer to return a pointer to a special instance of class Type instead of NULL.
|
||||
// This is useful in instances where operations on NULL pointers are semantically safe and/or
|
||||
// when error checking occurs at a different granularity or in a different part of the code
|
||||
// than when referencing an object via a LLSafeHandle.
|
||||
|
||||
template <class Type>
|
||||
class LLSafeHandle
|
||||
{
|
||||
public:
|
||||
LLSafeHandle() :
|
||||
mPointer(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
LLSafeHandle(Type* ptr) :
|
||||
mPointer(NULL)
|
||||
{
|
||||
assign(ptr);
|
||||
}
|
||||
|
||||
LLSafeHandle(const LLSafeHandle<Type>& ptr) :
|
||||
mPointer(NULL)
|
||||
{
|
||||
assign(ptr.mPointer);
|
||||
}
|
||||
|
||||
// support conversion up the type hierarchy. See Item 45 in Effective C++, 3rd Ed.
|
||||
template<typename Subclass>
|
||||
LLSafeHandle(const LLSafeHandle<Subclass>& ptr) :
|
||||
mPointer(NULL)
|
||||
{
|
||||
assign(ptr.get());
|
||||
}
|
||||
|
||||
~LLSafeHandle()
|
||||
{
|
||||
unref();
|
||||
}
|
||||
|
||||
const Type* operator->() const { return nonNull(mPointer); }
|
||||
Type* operator->() { return nonNull(mPointer); }
|
||||
|
||||
Type* get() const { return mPointer; }
|
||||
void clear() { assign(NULL); }
|
||||
// we disallow these operations as they expose our null objects to direct manipulation
|
||||
// and bypass the reference counting semantics
|
||||
//const Type& operator*() const { return *nonNull(mPointer); }
|
||||
//Type& operator*() { return *nonNull(mPointer); }
|
||||
|
||||
operator BOOL() const { return mPointer != NULL; }
|
||||
operator bool() const { return mPointer != NULL; }
|
||||
bool operator!() const { return mPointer == NULL; }
|
||||
bool isNull() const { return mPointer == NULL; }
|
||||
bool notNull() const { return mPointer != NULL; }
|
||||
|
||||
|
||||
operator Type*() const { return mPointer; }
|
||||
operator const Type*() const { return mPointer; }
|
||||
bool operator !=(Type* ptr) const { return (mPointer != ptr); }
|
||||
bool operator ==(Type* ptr) const { return (mPointer == ptr); }
|
||||
bool operator ==(const LLSafeHandle<Type>& ptr) const { return (mPointer == ptr.mPointer); }
|
||||
bool operator < (const LLSafeHandle<Type>& ptr) const { return (mPointer < ptr.mPointer); }
|
||||
bool operator > (const LLSafeHandle<Type>& ptr) const { return (mPointer > ptr.mPointer); }
|
||||
|
||||
LLSafeHandle<Type>& operator =(Type* ptr)
|
||||
{
|
||||
assign(ptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
LLSafeHandle<Type>& operator =(const LLSafeHandle<Type>& ptr)
|
||||
{
|
||||
assign(ptr.mPointer);
|
||||
return *this;
|
||||
}
|
||||
|
||||
// support assignment up the type hierarchy. See Item 45 in Effective C++, 3rd Ed.
|
||||
template<typename Subclass>
|
||||
LLSafeHandle<Type>& operator =(const LLSafeHandle<Subclass>& ptr)
|
||||
{
|
||||
assign(ptr.get());
|
||||
return *this;
|
||||
}
|
||||
|
||||
public:
|
||||
typedef Type* (*NullFunc)();
|
||||
static const NullFunc sNullFunc;
|
||||
|
||||
protected:
|
||||
void ref()
|
||||
{
|
||||
if (mPointer)
|
||||
{
|
||||
mPointer->ref();
|
||||
}
|
||||
}
|
||||
|
||||
void unref()
|
||||
{
|
||||
if (mPointer)
|
||||
{
|
||||
Type *tempp = mPointer;
|
||||
mPointer = NULL;
|
||||
tempp->unref();
|
||||
if (mPointer != NULL)
|
||||
{
|
||||
llwarns << "Unreference did assignment to non-NULL because of destructor" << llendl;
|
||||
unref();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void assign(Type* ptr)
|
||||
{
|
||||
if( mPointer != ptr )
|
||||
{
|
||||
unref();
|
||||
mPointer = ptr;
|
||||
ref();
|
||||
}
|
||||
}
|
||||
|
||||
static Type* nonNull(Type* ptr)
|
||||
{
|
||||
return ptr == NULL ? sNullFunc() : ptr;
|
||||
}
|
||||
|
||||
protected:
|
||||
Type* mPointer;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -35,21 +35,21 @@
|
||||
|
||||
#include "llthread.h"
|
||||
|
||||
//! Scoped volatile memory pool.
|
||||
//
|
||||
// As the AIVolatileAPRPool should never keep allocations very
|
||||
// long, it's most common use is for allocations with a lifetime
|
||||
// equal to it's scope.
|
||||
//
|
||||
// This is a convenience class that makes just a little easier to type.
|
||||
//
|
||||
class LLScopedVolatileAPRPool
|
||||
/** Scoped volatile memory pool.
|
||||
*
|
||||
* As the LLVolatileAPRPool should never keep allocations very
|
||||
* long, its most common use is for allocations with a lifetime
|
||||
* equal to it's scope.
|
||||
*
|
||||
* This is a convenience class that makes just a little easier to type.
|
||||
*/
|
||||
class LL_COMMON_API LLScopedVolatileAPRPool
|
||||
{
|
||||
private:
|
||||
AIVolatileAPRPool& mPool;
|
||||
LLVolatileAPRPool& mPool;
|
||||
apr_pool_t* mScopedAPRpool;
|
||||
public:
|
||||
LLScopedVolatileAPRPool() : mPool(AIThreadLocalData::tldata().mVolatileAPRPool), mScopedAPRpool(mPool.getVolatileAPRPool()) { }
|
||||
LLScopedVolatileAPRPool() : mPool(LLThreadLocalData::tldata().mVolatileAPRPool), mScopedAPRpool(mPool.getVolatileAPRPool()) { }
|
||||
~LLScopedVolatileAPRPool() { mPool.clearVolatileAPRPool(); }
|
||||
// Only use this to pass the pointer to a libapr-1 function that requires it.
|
||||
operator apr_pool_t*() const { return mScopedAPRpool; }
|
||||
|
||||
@@ -754,11 +754,7 @@ void LLSD::insert(const String& k, const LLSD& v) { makeMap(impl).insert(k, v);
|
||||
LLSD& LLSD::with(const String& k, const LLSD& v)
|
||||
{
|
||||
makeMap(impl).insert(k, v);
|
||||
#ifdef LL_MSVC7
|
||||
return *dynamic_cast<LLSD*>(this);
|
||||
#else
|
||||
return *this;
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
void LLSD::erase(const String& k) { makeMap(impl).erase(k); }
|
||||
|
||||
@@ -784,11 +780,7 @@ void LLSD::insert(Integer i, const LLSD& v) { makeArray(impl).insert(i, v); }
|
||||
LLSD& LLSD::with(Integer i, const LLSD& v)
|
||||
{
|
||||
makeArray(impl).insert(i, v);
|
||||
#ifdef LL_MSVC7
|
||||
return *dynamic_cast<LLSD*>(this);
|
||||
#else
|
||||
return *this;
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
void LLSD::append(const LLSD& v) { makeArray(impl).append(v); }
|
||||
void LLSD::erase(Integer i) { makeArray(impl).erase(i); }
|
||||
|
||||
@@ -34,11 +34,18 @@
|
||||
|
||||
#include "linden_common.h"
|
||||
#include "llsdserialize.h"
|
||||
#include "llmemory.h"
|
||||
#include "llpointer.h"
|
||||
#include "llstreamtools.h" // for fullread
|
||||
|
||||
#include <iostream>
|
||||
#include "apr_base64.h"
|
||||
#if MESH_ENABLED
|
||||
#ifdef LL_STANDALONE
|
||||
# include <zlib.h>
|
||||
#else
|
||||
# include "zlib/zlib.h" // for davep's dirty little zip functions
|
||||
#endif
|
||||
#endif //MESH_ENABLED
|
||||
|
||||
#if !LL_WINDOWS
|
||||
#include <netinet/in.h> // htonl & ntohl
|
||||
@@ -1447,12 +1454,9 @@ S32 LLSDBinaryFormatter::format(const LLSD& data, std::ostream& ostr, U32 option
|
||||
}
|
||||
|
||||
case LLSD::TypeUUID:
|
||||
{
|
||||
ostr.put('u');
|
||||
LLUUID d = data.asUUID();
|
||||
ostr.write((const char*)(&(d.mData)), UUID_BYTES);
|
||||
ostr.write((const char*)(&(data.asUUID().mData)), UUID_BYTES);
|
||||
break;
|
||||
}
|
||||
|
||||
case LLSD::TypeString:
|
||||
ostr.put('s');
|
||||
@@ -1505,7 +1509,7 @@ void LLSDBinaryFormatter::formatString(
|
||||
*/
|
||||
int deserialize_string(std::istream& istr, std::string& value, S32 max_bytes)
|
||||
{
|
||||
char c = istr.get();
|
||||
int c = istr.get();
|
||||
if(istr.fail())
|
||||
{
|
||||
// No data in stream, bail out but mention the character we
|
||||
@@ -1547,7 +1551,7 @@ int deserialize_string_delim(
|
||||
|
||||
while (true)
|
||||
{
|
||||
char next_char = istr.get();
|
||||
int next_byte = istr.get();
|
||||
++count;
|
||||
|
||||
if(istr.fail())
|
||||
@@ -1556,6 +1560,8 @@ int deserialize_string_delim(
|
||||
value = write_buffer.str();
|
||||
return LLSDParser::PARSE_FAILURE;
|
||||
}
|
||||
|
||||
char next_char = (char)next_byte; // Now that we know it's not EOF
|
||||
|
||||
if(found_escape)
|
||||
{
|
||||
@@ -1644,7 +1650,7 @@ int deserialize_string_raw(
|
||||
char buf[BUF_LEN]; /* Flawfinder: ignore */
|
||||
istr.get(buf, BUF_LEN - 1, ')');
|
||||
count += istr.gcount();
|
||||
char c = istr.get();
|
||||
int c = istr.get();
|
||||
c = istr.get();
|
||||
count += 2;
|
||||
if(((c == '"') || (c == '\'')) && (buf[0] == '('))
|
||||
@@ -1990,3 +1996,181 @@ std::ostream& operator<<(std::ostream& s, const LLSD& llsd)
|
||||
return s;
|
||||
}
|
||||
|
||||
#if MESH_ENABLED
|
||||
|
||||
//dirty little zippers -- yell at davep if these are horrid
|
||||
|
||||
//return a string containing gzipped bytes of binary serialized LLSD
|
||||
// VERY inefficient -- creates several copies of LLSD block in memory
|
||||
std::string zip_llsd(LLSD& data)
|
||||
{
|
||||
std::stringstream llsd_strm;
|
||||
|
||||
LLSDSerialize::toBinary(data, llsd_strm);
|
||||
|
||||
const U32 CHUNK = 65536;
|
||||
|
||||
z_stream strm;
|
||||
strm.zalloc = Z_NULL;
|
||||
strm.zfree = Z_NULL;
|
||||
strm.opaque = Z_NULL;
|
||||
|
||||
S32 ret = deflateInit(&strm, Z_BEST_COMPRESSION);
|
||||
if (ret != Z_OK)
|
||||
{
|
||||
llwarns << "Failed to compress LLSD block." << llendl;
|
||||
return std::string();
|
||||
}
|
||||
|
||||
std::string source = llsd_strm.str();
|
||||
|
||||
U8 out[CHUNK];
|
||||
|
||||
strm.avail_in = source.size();
|
||||
strm.next_in = (U8*) source.data();
|
||||
U8* output = NULL;
|
||||
|
||||
U32 cur_size = 0;
|
||||
|
||||
U32 have = 0;
|
||||
|
||||
do
|
||||
{
|
||||
strm.avail_out = CHUNK;
|
||||
strm.next_out = out;
|
||||
|
||||
ret = deflate(&strm, Z_FINISH);
|
||||
if (ret == Z_OK || ret == Z_STREAM_END)
|
||||
{ //copy result into output
|
||||
if (strm.avail_out >= CHUNK)
|
||||
{
|
||||
free(output);
|
||||
llwarns << "Failed to compress LLSD block." << llendl;
|
||||
return std::string();
|
||||
}
|
||||
|
||||
have = CHUNK-strm.avail_out;
|
||||
output = (U8*) realloc(output, cur_size+have);
|
||||
memcpy(output+cur_size, out, have);
|
||||
cur_size += have;
|
||||
}
|
||||
else
|
||||
{
|
||||
free(output);
|
||||
llwarns << "Failed to compress LLSD block." << llendl;
|
||||
return std::string();
|
||||
}
|
||||
}
|
||||
while (ret == Z_OK);
|
||||
|
||||
std::string::size_type size = cur_size;
|
||||
|
||||
std::string result((char*) output, size);
|
||||
deflateEnd(&strm);
|
||||
free(output);
|
||||
|
||||
#if 0 //verify results work with unzip_llsd
|
||||
std::istringstream test(result);
|
||||
LLSD test_sd;
|
||||
if (!unzip_llsd(test_sd, test, result.size()))
|
||||
{
|
||||
llerrs << "Invalid compression result!" << llendl;
|
||||
}
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
//decompress a block of LLSD from provided istream
|
||||
// not very efficient -- creats a copy of decompressed LLSD block in memory
|
||||
// and deserializes from that copy using LLSDSerialize
|
||||
bool unzip_llsd(LLSD& data, std::istream& is, S32 size)
|
||||
{
|
||||
U8* result = NULL;
|
||||
U32 cur_size = 0;
|
||||
z_stream strm;
|
||||
|
||||
const U32 CHUNK = 65536;
|
||||
|
||||
U8 *in = new U8[size];
|
||||
is.read((char*) in, size);
|
||||
|
||||
U8 out[CHUNK];
|
||||
|
||||
strm.zalloc = Z_NULL;
|
||||
strm.zfree = Z_NULL;
|
||||
strm.opaque = Z_NULL;
|
||||
strm.avail_in = size;
|
||||
strm.next_in = in;
|
||||
|
||||
S32 ret = inflateInit(&strm);
|
||||
|
||||
do
|
||||
{
|
||||
strm.avail_out = CHUNK;
|
||||
strm.next_out = out;
|
||||
ret = inflate(&strm, Z_NO_FLUSH);
|
||||
if (ret == Z_STREAM_ERROR)
|
||||
{
|
||||
inflateEnd(&strm);
|
||||
free(result);
|
||||
delete [] in;
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (ret)
|
||||
{
|
||||
case Z_NEED_DICT:
|
||||
ret = Z_DATA_ERROR;
|
||||
case Z_DATA_ERROR:
|
||||
case Z_MEM_ERROR:
|
||||
inflateEnd(&strm);
|
||||
free(result);
|
||||
delete [] in;
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
U32 have = CHUNK-strm.avail_out;
|
||||
|
||||
result = (U8*) realloc(result, cur_size + have);
|
||||
memcpy(result+cur_size, out, have);
|
||||
cur_size += have;
|
||||
|
||||
} while (ret == Z_OK);
|
||||
|
||||
inflateEnd(&strm);
|
||||
delete [] in;
|
||||
|
||||
if (ret != Z_STREAM_END)
|
||||
{
|
||||
free(result);
|
||||
return false;
|
||||
}
|
||||
|
||||
//result now points to the decompressed LLSD block
|
||||
{
|
||||
std::string res_str((char*) result, cur_size);
|
||||
|
||||
std::string deprecated_header("<? LLSD/Binary ?>");
|
||||
|
||||
if (res_str.substr(0, deprecated_header.size()) == deprecated_header)
|
||||
{
|
||||
res_str = res_str.substr(deprecated_header.size()+1, cur_size);
|
||||
}
|
||||
cur_size = res_str.size();
|
||||
|
||||
std::istringstream istr(res_str);
|
||||
|
||||
if (!LLSDSerialize::fromBinary(data, istr, cur_size))
|
||||
{
|
||||
llwarns << "Failed to unzip LLSD block" << llendl;
|
||||
free(result);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
free(result);
|
||||
return true;
|
||||
}
|
||||
#endif //MESH_ENABLED
|
||||
@@ -36,8 +36,9 @@
|
||||
#define LL_LLSDSERIALIZE_H
|
||||
|
||||
#include <iosfwd>
|
||||
#include "llpointer.h"
|
||||
#include "llrefcount.h"
|
||||
#include "llsd.h"
|
||||
#include "llmemory.h"
|
||||
|
||||
/**
|
||||
* @class LLSDParser
|
||||
@@ -787,4 +788,9 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
#if MESH_ENABLED
|
||||
//dirty little zip functions -- yell at davep
|
||||
LL_COMMON_API std::string zip_llsd(LLSD& data);
|
||||
LL_COMMON_API bool unzip_llsd(LLSD& data, std::istream& is, S32 size);
|
||||
#endif //MESH_ENABLED
|
||||
#endif // LL_LLSDSERIALIZE_H
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include <deque>
|
||||
|
||||
#include "apr_base64.h"
|
||||
#include <boost/regex.hpp>
|
||||
|
||||
extern "C"
|
||||
{
|
||||
@@ -734,6 +735,7 @@ void LLSDXMLParser::Impl::endElementHandler(const XML_Char* name)
|
||||
case ELEMENT_INTEGER:
|
||||
{
|
||||
S32 i;
|
||||
// sscanf okay here with different locales - ints don't change for different locale settings like floats do.
|
||||
if ( sscanf(mCurrentContent.c_str(), "%d", &i ) == 1 )
|
||||
{ // See if sscanf works - it's faster
|
||||
value = i;
|
||||
@@ -747,15 +749,19 @@ void LLSDXMLParser::Impl::endElementHandler(const XML_Char* name)
|
||||
|
||||
case ELEMENT_REAL:
|
||||
{
|
||||
F64 r;
|
||||
if ( sscanf(mCurrentContent.c_str(), "%lf", &r ) == 1 )
|
||||
{ // See if sscanf works - it's faster
|
||||
value = r;
|
||||
}
|
||||
else
|
||||
{
|
||||
value = LLSD(mCurrentContent).asReal();
|
||||
}
|
||||
value = LLSD(mCurrentContent).asReal();
|
||||
// removed since this breaks when locale has decimal separator that isn't '.'
|
||||
// investigated changing local to something compatible each time but deemed higher
|
||||
// risk that just using LLSD.asReal() each time.
|
||||
//F64 r;
|
||||
//if ( sscanf(mCurrentContent.c_str(), "%lf", &r ) == 1 )
|
||||
//{ // See if sscanf works - it's faster
|
||||
// value = r;
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// value = LLSD(mCurrentContent).asReal();
|
||||
//}
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -777,10 +783,17 @@ void LLSDXMLParser::Impl::endElementHandler(const XML_Char* name)
|
||||
|
||||
case ELEMENT_BINARY:
|
||||
{
|
||||
S32 len = apr_base64_decode_len(mCurrentContent.c_str());
|
||||
// Regex is expensive, but only fix for whitespace in base64,
|
||||
// created by python and other non-linden systems - DEV-39358
|
||||
// Fortunately we have very little binary passing now,
|
||||
// so performance impact shold be negligible. + poppy 2009-09-04
|
||||
boost::regex r;
|
||||
r.assign("\\s");
|
||||
std::string stripped = boost::regex_replace(mCurrentContent, r, "");
|
||||
S32 len = apr_base64_decode_len(stripped.c_str());
|
||||
std::vector<U8> data;
|
||||
data.resize(len);
|
||||
len = apr_base64_decode_binary(&data[0], mCurrentContent.c_str());
|
||||
len = apr_base64_decode_binary(&data[0], stripped.c_str());
|
||||
data.resize(len);
|
||||
value = data;
|
||||
break;
|
||||
|
||||
@@ -46,6 +46,12 @@
|
||||
#endif
|
||||
|
||||
#include "llsdserialize.h"
|
||||
#include "stringize.h"
|
||||
#include "is_approx_equal_fraction.h"
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <boost/range.hpp>
|
||||
|
||||
// U32
|
||||
LLSD ll_sd_from_U32(const U32 val)
|
||||
@@ -171,6 +177,15 @@ char* ll_print_sd(const LLSD& sd)
|
||||
return buffer;
|
||||
}
|
||||
|
||||
char* ll_pretty_print_sd_ptr(const LLSD* sd)
|
||||
{
|
||||
if (sd)
|
||||
{
|
||||
return ll_pretty_print_sd(*sd);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char* ll_pretty_print_sd(const LLSD& sd)
|
||||
{
|
||||
const U32 bufferSize = 10 * 1024;
|
||||
@@ -304,3 +319,363 @@ BOOL compare_llsd_with_template(
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* Helpers for llsd_matches()
|
||||
*****************************************************************************/
|
||||
// raw data used for LLSD::Type lookup
|
||||
struct Data
|
||||
{
|
||||
LLSD::Type type;
|
||||
const char* name;
|
||||
} typedata[] =
|
||||
{
|
||||
#define def(type) { LLSD::type, #type + 4 }
|
||||
def(TypeUndefined),
|
||||
def(TypeBoolean),
|
||||
def(TypeInteger),
|
||||
def(TypeReal),
|
||||
def(TypeString),
|
||||
def(TypeUUID),
|
||||
def(TypeDate),
|
||||
def(TypeURI),
|
||||
def(TypeBinary),
|
||||
def(TypeMap),
|
||||
def(TypeArray)
|
||||
#undef def
|
||||
};
|
||||
|
||||
// LLSD::Type lookup class into which we load the above static data
|
||||
class TypeLookup
|
||||
{
|
||||
typedef std::map<LLSD::Type, std::string> MapType;
|
||||
|
||||
public:
|
||||
TypeLookup()
|
||||
{
|
||||
for (const Data *di(boost::begin(typedata)), *dend(boost::end(typedata)); di != dend; ++di)
|
||||
{
|
||||
mMap[di->type] = di->name;
|
||||
}
|
||||
}
|
||||
|
||||
std::string lookup(LLSD::Type type) const
|
||||
{
|
||||
MapType::const_iterator found = mMap.find(type);
|
||||
if (found != mMap.end())
|
||||
{
|
||||
return found->second;
|
||||
}
|
||||
return STRINGIZE("<unknown LLSD type " << type << ">");
|
||||
}
|
||||
|
||||
private:
|
||||
MapType mMap;
|
||||
};
|
||||
|
||||
// static instance of the lookup class
|
||||
static const TypeLookup sTypes;
|
||||
|
||||
// describe a mismatch; phrasing may want tweaking
|
||||
const std::string op(" required instead of ");
|
||||
|
||||
// llsd_matches() wants to identify specifically where in a complex prototype
|
||||
// structure the mismatch occurred. This entails passing a prefix string,
|
||||
// empty for the top-level call. If the prototype contains an array of maps,
|
||||
// and the mismatch occurs in the second map in a key 'foo', we want to
|
||||
// decorate the returned string with: "[1]['foo']: etc." On the other hand, we
|
||||
// want to omit the entire prefix -- including colon -- if the mismatch is at
|
||||
// top level. This helper accepts the (possibly empty) recursively-accumulated
|
||||
// prefix string, returning either empty or the original string with colon
|
||||
// appended.
|
||||
static std::string colon(const std::string& pfx)
|
||||
{
|
||||
if (pfx.empty())
|
||||
return pfx;
|
||||
return pfx + ": ";
|
||||
}
|
||||
|
||||
// param type for match_types
|
||||
typedef std::vector<LLSD::Type> TypeVector;
|
||||
|
||||
// The scalar cases in llsd_matches() use this helper. In most cases, we can
|
||||
// accept not only the exact type specified in the prototype, but also other
|
||||
// types convertible to the expected type. That implies looping over an array
|
||||
// of such types. If the actual type doesn't match any of them, we want to
|
||||
// provide a list of acceptable conversions as well as the exact type, e.g.:
|
||||
// "Integer (or Boolean, Real, String) required instead of UUID". Both the
|
||||
// implementation and the calling logic are simplified by separating out the
|
||||
// expected type from the convertible types.
|
||||
static std::string match_types(LLSD::Type expect, // prototype.type()
|
||||
const TypeVector& accept, // types convertible to that type
|
||||
LLSD::Type actual, // type we're checking
|
||||
const std::string& pfx) // as for llsd_matches
|
||||
{
|
||||
// Trivial case: if the actual type is exactly what we expect, we're good.
|
||||
if (actual == expect)
|
||||
return "";
|
||||
|
||||
// For the rest of the logic, build up a suitable error string as we go so
|
||||
// we only have to make a single pass over the list of acceptable types.
|
||||
// If we detect success along the way, we'll simply discard the partial
|
||||
// error string.
|
||||
std::ostringstream out;
|
||||
out << colon(pfx) << sTypes.lookup(expect);
|
||||
|
||||
// If there are any convertible types, append that list.
|
||||
if (! accept.empty())
|
||||
{
|
||||
out << " (";
|
||||
const char* sep = "or ";
|
||||
for (TypeVector::const_iterator ai(accept.begin()), aend(accept.end());
|
||||
ai != aend; ++ai, sep = ", ")
|
||||
{
|
||||
// Don't forget to return success if we match any of those types...
|
||||
if (actual == *ai)
|
||||
return "";
|
||||
out << sep << sTypes.lookup(*ai);
|
||||
}
|
||||
out << ')';
|
||||
}
|
||||
// If we got this far, it's because 'actual' was not one of the acceptable
|
||||
// types, so we must return an error. 'out' already contains colon(pfx)
|
||||
// and the formatted list of acceptable types, so just append the mismatch
|
||||
// phrase and the actual type.
|
||||
out << op << sTypes.lookup(actual);
|
||||
return out.str();
|
||||
}
|
||||
|
||||
// see docstring in .h file
|
||||
std::string llsd_matches(const LLSD& prototype, const LLSD& data, const std::string& pfx)
|
||||
{
|
||||
// An undefined prototype means that any data is valid.
|
||||
// An undefined slot in an array or map prototype means that any data
|
||||
// may fill that slot.
|
||||
if (prototype.isUndefined())
|
||||
return "";
|
||||
// A prototype array must match a data array with at least as many
|
||||
// entries. Moreover, every prototype entry must match the
|
||||
// corresponding data entry.
|
||||
if (prototype.isArray())
|
||||
{
|
||||
if (! data.isArray())
|
||||
{
|
||||
return STRINGIZE(colon(pfx) << "Array" << op << sTypes.lookup(data.type()));
|
||||
}
|
||||
if (data.size() < prototype.size())
|
||||
{
|
||||
return STRINGIZE(colon(pfx) << "Array size " << prototype.size() << op
|
||||
<< "Array size " << data.size());
|
||||
}
|
||||
for (LLSD::Integer i = 0; i < prototype.size(); ++i)
|
||||
{
|
||||
std::string match(llsd_matches(prototype[i], data[i], STRINGIZE('[' << i << ']')));
|
||||
if (! match.empty())
|
||||
{
|
||||
return match;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
// A prototype map must match a data map. Every key in the prototype
|
||||
// must have a corresponding key in the data map; every value in the
|
||||
// prototype must match the corresponding key's value in the data.
|
||||
if (prototype.isMap())
|
||||
{
|
||||
if (! data.isMap())
|
||||
{
|
||||
return STRINGIZE(colon(pfx) << "Map" << op << sTypes.lookup(data.type()));
|
||||
}
|
||||
// If there are a number of keys missing from the data, it would be
|
||||
// frustrating to a coder to discover them one at a time, with a big
|
||||
// build each time. Enumerate all missing keys.
|
||||
std::ostringstream out;
|
||||
out << colon(pfx);
|
||||
const char* init = "Map missing keys: ";
|
||||
const char* sep = init;
|
||||
for (LLSD::map_const_iterator mi = prototype.beginMap(); mi != prototype.endMap(); ++mi)
|
||||
{
|
||||
if (! data.has(mi->first))
|
||||
{
|
||||
out << sep << mi->first;
|
||||
sep = ", ";
|
||||
}
|
||||
}
|
||||
// So... are we missing any keys?
|
||||
if (sep != init)
|
||||
{
|
||||
return out.str();
|
||||
}
|
||||
// Good, the data block contains all the keys required by the
|
||||
// prototype. Now match the prototype entries.
|
||||
for (LLSD::map_const_iterator mi2 = prototype.beginMap(); mi2 != prototype.endMap(); ++mi2)
|
||||
{
|
||||
std::string match(llsd_matches(mi2->second, data[mi2->first],
|
||||
STRINGIZE("['" << mi2->first << "']")));
|
||||
if (! match.empty())
|
||||
{
|
||||
return match;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
// A String prototype can match String, Boolean, Integer, Real, UUID,
|
||||
// Date and URI, because any of these can be converted to String.
|
||||
if (prototype.isString())
|
||||
{
|
||||
static LLSD::Type accept[] =
|
||||
{
|
||||
LLSD::TypeBoolean,
|
||||
LLSD::TypeInteger,
|
||||
LLSD::TypeReal,
|
||||
LLSD::TypeUUID,
|
||||
LLSD::TypeDate,
|
||||
LLSD::TypeURI
|
||||
};
|
||||
return match_types(prototype.type(),
|
||||
TypeVector(boost::begin(accept), boost::end(accept)),
|
||||
data.type(),
|
||||
pfx);
|
||||
}
|
||||
// Boolean, Integer, Real match each other or String. TBD: ensure that
|
||||
// a String value is numeric.
|
||||
if (prototype.isBoolean() || prototype.isInteger() || prototype.isReal())
|
||||
{
|
||||
static LLSD::Type all[] =
|
||||
{
|
||||
LLSD::TypeBoolean,
|
||||
LLSD::TypeInteger,
|
||||
LLSD::TypeReal,
|
||||
LLSD::TypeString
|
||||
};
|
||||
// Funny business: shuffle the set of acceptable types to include all
|
||||
// but the prototype's type. Get the acceptable types in a set.
|
||||
std::set<LLSD::Type> rest(boost::begin(all), boost::end(all));
|
||||
// Remove the prototype's type because we pass that separately.
|
||||
rest.erase(prototype.type());
|
||||
return match_types(prototype.type(),
|
||||
TypeVector(rest.begin(), rest.end()),
|
||||
data.type(),
|
||||
pfx);
|
||||
}
|
||||
// UUID, Date and URI match themselves or String.
|
||||
if (prototype.isUUID() || prototype.isDate() || prototype.isURI())
|
||||
{
|
||||
static LLSD::Type accept[] =
|
||||
{
|
||||
LLSD::TypeString
|
||||
};
|
||||
return match_types(prototype.type(),
|
||||
TypeVector(boost::begin(accept), boost::end(accept)),
|
||||
data.type(),
|
||||
pfx);
|
||||
}
|
||||
// We don't yet know the conversion semantics associated with any new LLSD
|
||||
// data type that might be added, so until we've been extended to handle
|
||||
// them, assume it's strict: the new type matches only itself. (This is
|
||||
// true of Binary, which is why we don't handle that case separately.) Too
|
||||
// bad LLSD doesn't define isConvertible(Type to, Type from).
|
||||
return match_types(prototype.type(), TypeVector(), data.type(), pfx);
|
||||
}
|
||||
|
||||
bool llsd_equals(const LLSD& lhs, const LLSD& rhs, unsigned bits)
|
||||
{
|
||||
// We're comparing strict equality of LLSD representation rather than
|
||||
// performing any conversions. So if the types aren't equal, the LLSD
|
||||
// values aren't equal.
|
||||
if (lhs.type() != rhs.type())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Here we know both types are equal. Now compare values.
|
||||
switch (lhs.type())
|
||||
{
|
||||
case LLSD::TypeUndefined:
|
||||
// Both are TypeUndefined. There's nothing more to know.
|
||||
return true;
|
||||
|
||||
case LLSD::TypeReal:
|
||||
// This is where the 'bits' argument comes in handy. If passed
|
||||
// explicitly, it means to use is_approx_equal_fraction() to compare.
|
||||
if (bits >= 0)
|
||||
{
|
||||
return is_approx_equal_fraction(lhs.asReal(), rhs.asReal(), bits);
|
||||
}
|
||||
// Otherwise we compare bit representations, and the usual caveats
|
||||
// about comparing floating-point numbers apply. Omitting 'bits' when
|
||||
// comparing Real values is only useful when we expect identical bit
|
||||
// representation for a given Real value, e.g. for integer-valued
|
||||
// Reals.
|
||||
return (lhs.asReal() == rhs.asReal());
|
||||
|
||||
#define COMPARE_SCALAR(type) \
|
||||
case LLSD::Type##type: \
|
||||
/* LLSD::URI has operator!=() but not operator==() */ \
|
||||
/* rely on the optimizer for all others */ \
|
||||
return (! (lhs.as##type() != rhs.as##type()))
|
||||
|
||||
COMPARE_SCALAR(Boolean);
|
||||
COMPARE_SCALAR(Integer);
|
||||
COMPARE_SCALAR(String);
|
||||
COMPARE_SCALAR(UUID);
|
||||
COMPARE_SCALAR(Date);
|
||||
COMPARE_SCALAR(URI);
|
||||
COMPARE_SCALAR(Binary);
|
||||
|
||||
#undef COMPARE_SCALAR
|
||||
|
||||
case LLSD::TypeArray:
|
||||
{
|
||||
LLSD::array_const_iterator
|
||||
lai(lhs.beginArray()), laend(lhs.endArray()),
|
||||
rai(rhs.beginArray()), raend(rhs.endArray());
|
||||
// Compare array elements, walking the two arrays in parallel.
|
||||
for ( ; lai != laend && rai != raend; ++lai, ++rai)
|
||||
{
|
||||
// If any one array element is unequal, the arrays are unequal.
|
||||
if (! llsd_equals(*lai, *rai, bits))
|
||||
return false;
|
||||
}
|
||||
// Here we've reached the end of one or the other array. They're equal
|
||||
// only if they're BOTH at end: that is, if they have equal length too.
|
||||
return (lai == laend && rai == raend);
|
||||
}
|
||||
|
||||
case LLSD::TypeMap:
|
||||
{
|
||||
// Build a set of all rhs keys.
|
||||
std::set<LLSD::String> rhskeys;
|
||||
for (LLSD::map_const_iterator rmi(rhs.beginMap()), rmend(rhs.endMap());
|
||||
rmi != rmend; ++rmi)
|
||||
{
|
||||
rhskeys.insert(rmi->first);
|
||||
}
|
||||
// Now walk all the lhs keys.
|
||||
for (LLSD::map_const_iterator lmi(lhs.beginMap()), lmend(lhs.endMap());
|
||||
lmi != lmend; ++lmi)
|
||||
{
|
||||
// Try to erase this lhs key from the set of rhs keys. If rhs has
|
||||
// no such key, the maps are unequal. erase(key) returns count of
|
||||
// items erased.
|
||||
if (rhskeys.erase(lmi->first) != 1)
|
||||
return false;
|
||||
// Both maps have the current key. Compare values.
|
||||
if (! llsd_equals(lmi->second, rhs[lmi->first], bits))
|
||||
return false;
|
||||
}
|
||||
// We've now established that all the lhs keys have equal values in
|
||||
// both maps. The maps are equal unless rhs contains a superset of
|
||||
// those keys.
|
||||
return rhskeys.empty();
|
||||
}
|
||||
|
||||
default:
|
||||
// We expect that every possible type() value is specifically handled
|
||||
// above. Failing to extend this switch to support a new LLSD type is
|
||||
// an error that must be brought to the coder's attention.
|
||||
LL_ERRS("llsd_equals") << "llsd_equals(" << lhs << ", " << rhs << ", " << bits << "): "
|
||||
"unknown type " << lhs.type() << LL_ENDL;
|
||||
return false; // pacify the compiler
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
#ifndef LL_LLSDUTIL_H
|
||||
#define LL_LLSDUTIL_H
|
||||
|
||||
#include "llsd.h"
|
||||
class LLSD;
|
||||
|
||||
// U32
|
||||
LL_COMMON_API LLSD ll_sd_from_U32(const U32);
|
||||
@@ -59,6 +59,7 @@ LL_COMMON_API LLSD ll_binary_from_string(const LLSD& sd);
|
||||
LL_COMMON_API char* ll_print_sd(const LLSD& sd);
|
||||
|
||||
// Serializes sd to static buffer and returns pointer, using "pretty printing" mode.
|
||||
LL_COMMON_API char* ll_pretty_print_sd_ptr(const LLSD* sd);
|
||||
LL_COMMON_API char* ll_pretty_print_sd(const LLSD& sd);
|
||||
|
||||
//compares the structure of an LLSD to a template LLSD and stores the
|
||||
@@ -73,6 +74,66 @@ LL_COMMON_API BOOL compare_llsd_with_template(
|
||||
const LLSD& template_llsd,
|
||||
LLSD& resultant_llsd);
|
||||
|
||||
/**
|
||||
* Recursively determine whether a given LLSD data block "matches" another
|
||||
* LLSD prototype. The returned string is empty() on success, non-empty() on
|
||||
* mismatch.
|
||||
*
|
||||
* This function tests structure (types) rather than data values. It is
|
||||
* intended for when a consumer expects an LLSD block with a particular
|
||||
* structure, and must succinctly detect whether the arriving block is
|
||||
* well-formed. For instance, a test of the form:
|
||||
* @code
|
||||
* if (! (data.has("request") && data.has("target") && data.has("modifier") ...))
|
||||
* @endcode
|
||||
* could instead be expressed by initializing a prototype LLSD map with the
|
||||
* required keys and writing:
|
||||
* @code
|
||||
* if (! llsd_matches(prototype, data).empty())
|
||||
* @endcode
|
||||
*
|
||||
* A non-empty return value is an error-message fragment intended to indicate
|
||||
* to (English-speaking) developers where in the prototype structure the
|
||||
* mismatch occurred.
|
||||
*
|
||||
* * If a slot in the prototype isUndefined(), then anything is valid at that
|
||||
* place in the real object. (Passing prototype == LLSD() matches anything
|
||||
* at all.)
|
||||
* * An array in the prototype must match a data array at least that large.
|
||||
* (Additional entries in the data array are ignored.) Every isDefined()
|
||||
* entry in the prototype array must match the corresponding entry in the
|
||||
* data array.
|
||||
* * A map in the prototype must match a map in the data. Every key in the
|
||||
* prototype map must match a corresponding key in the data map. (Additional
|
||||
* keys in the data map are ignored.) Every isDefined() value in the
|
||||
* prototype map must match the corresponding key's value in the data map.
|
||||
* * Scalar values in the prototype are tested for @em type rather than value.
|
||||
* For instance, a String in the prototype matches any String at all. In
|
||||
* effect, storing an Integer at a particular place in the prototype asserts
|
||||
* that the caller intends to apply asInteger() to the corresponding slot in
|
||||
* the data.
|
||||
* * A String in the prototype matches String, Boolean, Integer, Real, UUID,
|
||||
* Date and URI, because asString() applied to any of these produces a
|
||||
* meaningful result.
|
||||
* * Similarly, a Boolean, Integer or Real in the prototype can match any of
|
||||
* Boolean, Integer or Real in the data -- or even String.
|
||||
* * UUID matches UUID or String.
|
||||
* * Date matches Date or String.
|
||||
* * URI matches URI or String.
|
||||
* * Binary in the prototype matches only Binary in the data.
|
||||
*
|
||||
* @TODO: when a Boolean, Integer or Real in the prototype matches a String in
|
||||
* the data, we should examine the String @em value to ensure it can be
|
||||
* meaningfully converted to the requested type. The same goes for UUID, Date
|
||||
* and URI.
|
||||
*/
|
||||
LL_COMMON_API std::string llsd_matches(const LLSD& prototype, const LLSD& data, const std::string& pfx="");
|
||||
|
||||
/// Deep equality. If you want to compare LLSD::Real values for approximate
|
||||
/// equality rather than bitwise equality, pass @a bits as for
|
||||
/// is_approx_equal_fraction().
|
||||
LL_COMMON_API bool llsd_equals(const LLSD& lhs, const LLSD& rhs, unsigned bits=-1);
|
||||
|
||||
// Simple function to copy data out of input & output iterators if
|
||||
// there is no need for casting.
|
||||
template<typename Input> LLSD llsd_copy_array(Input iter, Input end)
|
||||
@@ -85,4 +146,283 @@ template<typename Input> LLSD llsd_copy_array(Input iter, Input end)
|
||||
return dest;
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
* LLSDArray
|
||||
*****************************************************************************/
|
||||
/**
|
||||
* Construct an LLSD::Array inline, with implicit conversion to LLSD. Usage:
|
||||
*
|
||||
* @code
|
||||
* void somefunc(const LLSD&);
|
||||
* ...
|
||||
* somefunc(LLSDArray("text")(17)(3.14));
|
||||
* @endcode
|
||||
*
|
||||
* For completeness, LLSDArray() with no args constructs an empty array, so
|
||||
* <tt>LLSDArray()("text")(17)(3.14)</tt> produces an array equivalent to the
|
||||
* above. But for most purposes, LLSD() is already equivalent to an empty
|
||||
* array, and if you explicitly want an empty isArray(), there's
|
||||
* LLSD::emptyArray(). However, supporting a no-args LLSDArray() constructor
|
||||
* follows the principle of least astonishment.
|
||||
*/
|
||||
class LLSDArray
|
||||
{
|
||||
public:
|
||||
LLSDArray():
|
||||
_data(LLSD::emptyArray())
|
||||
{}
|
||||
|
||||
/**
|
||||
* Need an explicit copy constructor. Consider the following:
|
||||
*
|
||||
* @code
|
||||
* LLSD array_of_arrays(LLSDArray(LLSDArray(17)(34))
|
||||
* (LLSDArray("x")("y")));
|
||||
* @endcode
|
||||
*
|
||||
* The coder intends to construct [[17, 34], ["x", "y"]].
|
||||
*
|
||||
* With the compiler's implicit copy constructor, s/he gets instead
|
||||
* [17, 34, ["x", "y"]].
|
||||
*
|
||||
* The expression LLSDArray(17)(34) constructs an LLSDArray with those two
|
||||
* values. The reader assumes it should be converted to LLSD, as we always
|
||||
* want with LLSDArray, before passing it to the @em outer LLSDArray
|
||||
* constructor! This copy constructor makes that happen.
|
||||
*/
|
||||
LLSDArray(const LLSDArray& inner):
|
||||
_data(LLSD::emptyArray())
|
||||
{
|
||||
_data.append(inner);
|
||||
}
|
||||
|
||||
LLSDArray(const LLSD& value):
|
||||
_data(LLSD::emptyArray())
|
||||
{
|
||||
_data.append(value);
|
||||
}
|
||||
|
||||
LLSDArray& operator()(const LLSD& value)
|
||||
{
|
||||
_data.append(value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator LLSD() const { return _data; }
|
||||
LLSD get() const { return _data; }
|
||||
|
||||
private:
|
||||
LLSD _data;
|
||||
};
|
||||
|
||||
/*****************************************************************************
|
||||
* LLSDMap
|
||||
*****************************************************************************/
|
||||
/**
|
||||
* Construct an LLSD::Map inline, with implicit conversion to LLSD. Usage:
|
||||
*
|
||||
* @code
|
||||
* void somefunc(const LLSD&);
|
||||
* ...
|
||||
* somefunc(LLSDMap("alpha", "abc")("number", 17)("pi", 3.14));
|
||||
* @endcode
|
||||
*
|
||||
* For completeness, LLSDMap() with no args constructs an empty map, so
|
||||
* <tt>LLSDMap()("alpha", "abc")("number", 17)("pi", 3.14)</tt> produces a map
|
||||
* equivalent to the above. But for most purposes, LLSD() is already
|
||||
* equivalent to an empty map, and if you explicitly want an empty isMap(),
|
||||
* there's LLSD::emptyMap(). However, supporting a no-args LLSDMap()
|
||||
* constructor follows the principle of least astonishment.
|
||||
*/
|
||||
class LLSDMap
|
||||
{
|
||||
public:
|
||||
LLSDMap():
|
||||
_data(LLSD::emptyMap())
|
||||
{}
|
||||
LLSDMap(const LLSD::String& key, const LLSD& value):
|
||||
_data(LLSD::emptyMap())
|
||||
{
|
||||
_data[key] = value;
|
||||
}
|
||||
|
||||
LLSDMap& operator()(const LLSD::String& key, const LLSD& value)
|
||||
{
|
||||
_data[key] = value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
operator LLSD() const { return _data; }
|
||||
LLSD get() const { return _data; }
|
||||
|
||||
private:
|
||||
LLSD _data;
|
||||
};
|
||||
|
||||
/*****************************************************************************
|
||||
* LLSDParam
|
||||
*****************************************************************************/
|
||||
/**
|
||||
* LLSDParam is a customization point for passing LLSD values to function
|
||||
* parameters of more or less arbitrary type. LLSD provides a small set of
|
||||
* native conversions; but if a generic algorithm explicitly constructs an
|
||||
* LLSDParam object in the function's argument list, a consumer can provide
|
||||
* LLSDParam specializations to support more different parameter types than
|
||||
* LLSD's native conversions.
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* @code
|
||||
* void somefunc(const paramtype&);
|
||||
* ...
|
||||
* somefunc(..., LLSDParam<paramtype>(someLLSD), ...);
|
||||
* @endcode
|
||||
*/
|
||||
template <typename T>
|
||||
class LLSDParam
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Default implementation converts to T on construction, saves converted
|
||||
* value for later retrieval
|
||||
*/
|
||||
LLSDParam(const LLSD& value):
|
||||
_value(value)
|
||||
{}
|
||||
|
||||
operator T() const { return _value; }
|
||||
|
||||
private:
|
||||
T _value;
|
||||
};
|
||||
|
||||
/**
|
||||
* Turns out that several target types could accept an LLSD param using any of
|
||||
* a few different conversions, e.g. LLUUID's constructor can accept LLUUID or
|
||||
* std::string. Therefore, the compiler can't decide which LLSD conversion
|
||||
* operator to choose, even though to us it seems obvious. But that's okay, we
|
||||
* can specialize LLSDParam for such target types, explicitly specifying the
|
||||
* desired conversion -- that's part of what LLSDParam is all about. Turns out
|
||||
* we have to do that enough to make it worthwhile generalizing. Use a macro
|
||||
* because I need to specify one of the asReal, etc., explicit conversion
|
||||
* methods as well as a type. If I'm overlooking a clever way to implement
|
||||
* that using a template instead, feel free to reimplement.
|
||||
*/
|
||||
#define LLSDParam_for(T, AS) \
|
||||
template <> \
|
||||
class LLSDParam<T> \
|
||||
{ \
|
||||
public: \
|
||||
LLSDParam(const LLSD& value): \
|
||||
_value(value.AS()) \
|
||||
{} \
|
||||
\
|
||||
operator T() const { return _value; } \
|
||||
\
|
||||
private: \
|
||||
T _value; \
|
||||
}
|
||||
|
||||
LLSDParam_for(float, asReal);
|
||||
LLSDParam_for(LLUUID, asUUID);
|
||||
LLSDParam_for(LLDate, asDate);
|
||||
LLSDParam_for(LLURI, asURI);
|
||||
LLSDParam_for(LLSD::Binary, asBinary);
|
||||
|
||||
/**
|
||||
* LLSDParam<const char*> is an example of the kind of conversion you can
|
||||
* support with LLSDParam beyond native LLSD conversions. Normally you can't
|
||||
* pass an LLSD object to a function accepting const char* -- but you can
|
||||
* safely pass an LLSDParam<const char*>(yourLLSD).
|
||||
*/
|
||||
template <>
|
||||
class LLSDParam<const char*>
|
||||
{
|
||||
private:
|
||||
// The difference here is that we store a std::string rather than a const
|
||||
// char*. It's important that the LLSDParam object own the std::string.
|
||||
std::string _value;
|
||||
// We don't bother storing the incoming LLSD object, but we do have to
|
||||
// distinguish whether _value is an empty string because the LLSD object
|
||||
// contains an empty string or because it's isUndefined().
|
||||
bool _undefined;
|
||||
|
||||
public:
|
||||
LLSDParam(const LLSD& value):
|
||||
_value(value),
|
||||
_undefined(value.isUndefined())
|
||||
{}
|
||||
|
||||
// The const char* we retrieve is for storage owned by our _value member.
|
||||
// That's how we guarantee that the const char* is valid for the lifetime
|
||||
// of this LLSDParam object. Constructing your LLSDParam in the argument
|
||||
// list should ensure that the LLSDParam object will persist for the
|
||||
// duration of the function call.
|
||||
operator const char*() const
|
||||
{
|
||||
if (_undefined)
|
||||
{
|
||||
// By default, an isUndefined() LLSD object's asString() method
|
||||
// will produce an empty string. But for a function accepting
|
||||
// const char*, it's often important to be able to pass NULL, and
|
||||
// isUndefined() seems like the best way. If you want to pass an
|
||||
// empty string, you can still pass LLSD(""). Without this special
|
||||
// case, though, no LLSD value could pass NULL.
|
||||
return NULL;
|
||||
}
|
||||
return _value.c_str();
|
||||
}
|
||||
};
|
||||
|
||||
namespace llsd
|
||||
{
|
||||
|
||||
/*****************************************************************************
|
||||
* BOOST_FOREACH() helpers for LLSD
|
||||
*****************************************************************************/
|
||||
/// Usage: BOOST_FOREACH(LLSD item, inArray(someLLSDarray)) { ... }
|
||||
class inArray
|
||||
{
|
||||
public:
|
||||
inArray(const LLSD& array):
|
||||
_array(array)
|
||||
{}
|
||||
|
||||
typedef LLSD::array_const_iterator const_iterator;
|
||||
typedef LLSD::array_iterator iterator;
|
||||
|
||||
iterator begin() { return _array.beginArray(); }
|
||||
iterator end() { return _array.endArray(); }
|
||||
const_iterator begin() const { return _array.beginArray(); }
|
||||
const_iterator end() const { return _array.endArray(); }
|
||||
|
||||
private:
|
||||
LLSD _array;
|
||||
};
|
||||
|
||||
/// MapEntry is what you get from dereferencing an LLSD::map_[const_]iterator.
|
||||
typedef std::map<LLSD::String, LLSD>::value_type MapEntry;
|
||||
|
||||
/// Usage: BOOST_FOREACH([const] MapEntry& e, inMap(someLLSDmap)) { ... }
|
||||
class inMap
|
||||
{
|
||||
public:
|
||||
inMap(const LLSD& map):
|
||||
_map(map)
|
||||
{}
|
||||
|
||||
typedef LLSD::map_const_iterator const_iterator;
|
||||
typedef LLSD::map_iterator iterator;
|
||||
|
||||
iterator begin() { return _map.beginMap(); }
|
||||
iterator end() { return _map.endMap(); }
|
||||
const_iterator begin() const { return _map.beginMap(); }
|
||||
const_iterator end() const { return _map.endMap(); }
|
||||
|
||||
private:
|
||||
LLSD _map;
|
||||
};
|
||||
|
||||
} // namespace llsd
|
||||
|
||||
#endif // LL_LLSDUTIL_H
|
||||
|
||||
32
indra/llcommon/llsingleton.cpp
Normal file
32
indra/llcommon/llsingleton.cpp
Normal file
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* @file llsingleton.cpp
|
||||
* @author Brad Kittenbrink
|
||||
*
|
||||
* $LicenseInfo:firstyear=2009&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "llsingleton.h"
|
||||
|
||||
std::map<std::string, void *> * LLSingletonRegistry::sSingletonMap = NULL;
|
||||
|
||||
225
indra/llcommon/llsingleton.h
Normal file
225
indra/llcommon/llsingleton.h
Normal file
@@ -0,0 +1,225 @@
|
||||
/**
|
||||
* @file llsingleton.h
|
||||
*
|
||||
* $LicenseInfo:firstyear=2002&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
#ifndef LLSINGLETON_H
|
||||
#define LLSINGLETON_H
|
||||
|
||||
#include "llerror.h" // *TODO: eliminate this
|
||||
|
||||
#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.
|
||||
//
|
||||
// There are two ways to use LLSingleton. The first way is to inherit from it
|
||||
// while using the typename that you'd like to be static as the template
|
||||
// parameter, like so:
|
||||
//
|
||||
// class Foo: public LLSingleton<Foo>{};
|
||||
//
|
||||
// Foo& instance = Foo::instance();
|
||||
//
|
||||
// The second way is to use the singleton class directly, without inheritance:
|
||||
//
|
||||
// typedef LLSingleton<Foo> FooSingleton;
|
||||
//
|
||||
// Foo& instance = FooSingleton::instance();
|
||||
//
|
||||
// In this case, the class being managed as a singleton needs to provide an
|
||||
// initSingleton() method since the LLSingleton virtual method won't be
|
||||
// available
|
||||
//
|
||||
// As currently written, it is not thread-safe.
|
||||
|
||||
template <typename DERIVED_TYPE>
|
||||
class LLSingleton : private boost::noncopyable
|
||||
{
|
||||
|
||||
private:
|
||||
typedef enum e_init_state
|
||||
{
|
||||
UNINITIALIZED,
|
||||
CONSTRUCTING,
|
||||
INITIALIZING,
|
||||
INITIALIZED,
|
||||
DELETED
|
||||
} EInitState;
|
||||
|
||||
// stores pointer to singleton instance
|
||||
// and tracks initialization state of singleton
|
||||
struct SingletonInstanceData
|
||||
{
|
||||
EInitState mInitState;
|
||||
DERIVED_TYPE* mSingletonInstance;
|
||||
|
||||
SingletonInstanceData()
|
||||
: mSingletonInstance(NULL),
|
||||
mInitState(UNINITIALIZED)
|
||||
{}
|
||||
|
||||
~SingletonInstanceData()
|
||||
{
|
||||
if (mInitState != DELETED)
|
||||
{
|
||||
deleteSingleton();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
virtual ~LLSingleton()
|
||||
{
|
||||
SingletonInstanceData& data = getData();
|
||||
data.mSingletonInstance = NULL;
|
||||
data.mInitState = DELETED;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Immediately delete the singleton.
|
||||
*
|
||||
* A subsequent call to LLProxy::getInstance() will construct a new
|
||||
* instance of the class.
|
||||
*
|
||||
* LLSingletons are normally destroyed after main() has exited and the C++
|
||||
* runtime is cleaning up statically-constructed objects. Some classes
|
||||
* derived from LLSingleton have objects that are part of a runtime system
|
||||
* that is terminated before main() exits. Calling the destructor of those
|
||||
* objects after the termination of their respective systems can cause
|
||||
* crashes and other problems during termination of the project. Using this
|
||||
* method to destroy the singleton early can prevent these crashes.
|
||||
*
|
||||
* An example where this is needed is for a LLSingleton that has an APR
|
||||
* object as a member that makes APR calls on destruction. The APR system is
|
||||
* shut down explicitly before main() exits. This causes a crash on exit.
|
||||
* Using this method before the call to apr_terminate() and NOT calling
|
||||
* getInstance() again will prevent the crash.
|
||||
*/
|
||||
static void deleteSingleton()
|
||||
{
|
||||
delete getData().mSingletonInstance;
|
||||
getData().mSingletonInstance = NULL;
|
||||
getData().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();
|
||||
|
||||
if (data.mInitState == CONSTRUCTING)
|
||||
{
|
||||
llerrs << "Tried to access singleton " << typeid(DERIVED_TYPE).name() << " from singleton constructor!" << llendl;
|
||||
}
|
||||
|
||||
if (data.mInitState == DELETED)
|
||||
{
|
||||
llwarns << "Trying to access deleted singleton " << typeid(DERIVED_TYPE).name() << " creating new instance" << llendl;
|
||||
}
|
||||
|
||||
if (!data.mSingletonInstance)
|
||||
{
|
||||
data.mInitState = CONSTRUCTING;
|
||||
data.mSingletonInstance = new DERIVED_TYPE();
|
||||
data.mInitState = INITIALIZING;
|
||||
data.mSingletonInstance->initSingleton();
|
||||
data.mInitState = INITIALIZED;
|
||||
}
|
||||
|
||||
return data.mSingletonInstance;
|
||||
}
|
||||
|
||||
// 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 getData().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;
|
||||
}
|
||||
|
||||
private:
|
||||
virtual void initSingleton() {}
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -43,9 +43,10 @@
|
||||
|
||||
|
||||
// statics
|
||||
BOOL LLPerfBlock::sStatsEnabled = FALSE; // Flag for detailed information
|
||||
S32 LLPerfBlock::sStatsFlags = LLPerfBlock::LLSTATS_NO_OPTIONAL_STATS; // Control what is being recorded
|
||||
LLPerfBlock::stat_map_t LLPerfBlock::sStatMap; // Map full path string to LLStatTime objects, tracks all active objects
|
||||
std::string LLPerfBlock::sCurrentStatPath = ""; // Something like "/total_time/physics/physics step"
|
||||
LLStat::stat_map_t LLStat::sStatList;
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Live config file to trigger stats logging
|
||||
@@ -129,6 +130,7 @@ bool LLStatsConfigFile::loadFile()
|
||||
|
||||
F32 duration = 0.f;
|
||||
F32 interval = 0.f;
|
||||
S32 flags = LLPerfBlock::LLSTATS_BASIC_STATS;
|
||||
|
||||
const char * w = "duration";
|
||||
if (stats_config.has(w))
|
||||
@@ -140,8 +142,18 @@ bool LLStatsConfigFile::loadFile()
|
||||
{
|
||||
interval = (F32)stats_config[w].asReal();
|
||||
}
|
||||
w = "flags";
|
||||
if (stats_config.has(w))
|
||||
{
|
||||
flags = (S32)stats_config[w].asInteger();
|
||||
if (flags == LLPerfBlock::LLSTATS_NO_OPTIONAL_STATS &&
|
||||
duration > 0)
|
||||
{ // No flags passed in, but have a duration, so reset to basic stats
|
||||
flags = LLPerfBlock::LLSTATS_BASIC_STATS;
|
||||
}
|
||||
}
|
||||
|
||||
mStatsp->setReportPerformanceDuration( duration );
|
||||
mStatsp->setReportPerformanceDuration( duration, flags );
|
||||
mStatsp->setReportPerformanceInterval( interval );
|
||||
|
||||
if ( duration > 0 )
|
||||
@@ -253,13 +265,14 @@ void LLPerfStats::dumpIntervalPerformanceStats()
|
||||
}
|
||||
}
|
||||
|
||||
// Set length of performance stat recording
|
||||
void LLPerfStats::setReportPerformanceDuration( F32 seconds )
|
||||
// Set length of performance stat recording.
|
||||
// If turning stats on, caller must provide flags
|
||||
void LLPerfStats::setReportPerformanceDuration( F32 seconds, S32 flags /* = LLSTATS_NO_OPTIONAL_STATS */ )
|
||||
{
|
||||
if ( seconds <= 0.f )
|
||||
{
|
||||
mReportPerformanceStatEnd = 0.0;
|
||||
LLPerfBlock::setStatsEnabled( FALSE );
|
||||
LLPerfBlock::setStatsFlags(LLPerfBlock::LLSTATS_NO_OPTIONAL_STATS); // Make sure all recording is off
|
||||
mFrameStatsFile.close();
|
||||
LLPerfBlock::clearDynamicStats();
|
||||
}
|
||||
@@ -268,8 +281,8 @@ void LLPerfStats::setReportPerformanceDuration( F32 seconds )
|
||||
mReportPerformanceStatEnd = LLFrameTimer::getElapsedSeconds() + ((F64) seconds);
|
||||
// Clear failure flag to try and create the log file once
|
||||
mFrameStatsFileFailure = FALSE;
|
||||
LLPerfBlock::setStatsEnabled( TRUE );
|
||||
mSkipFirstFrameStats = TRUE; // Skip the first report (at the end of this frame)
|
||||
LLPerfBlock::setStatsFlags(flags);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -611,11 +624,26 @@ LLPerfBlock::LLPerfBlock(LLStatTime* stat ) : mPredefinedStat(stat), mDynamicSta
|
||||
}
|
||||
}
|
||||
|
||||
// Use this constructor for dynamically created LLStatTime objects (not pre-defined) with a multi-part key.
|
||||
// These are also turned on or off via the switch passed in
|
||||
LLPerfBlock::LLPerfBlock( const char* key1, const char* key2 ) : mPredefinedStat(NULL), mDynamicStat(NULL)
|
||||
// Use this constructor for normal, optional LLPerfBlock time slices
|
||||
LLPerfBlock::LLPerfBlock( const char* key ) : mPredefinedStat(NULL), mDynamicStat(NULL)
|
||||
{
|
||||
if (!sStatsEnabled) return;
|
||||
if ((sStatsFlags & LLSTATS_BASIC_STATS) == 0)
|
||||
{ // These are off unless the base set is enabled
|
||||
return;
|
||||
}
|
||||
|
||||
initDynamicStat(key);
|
||||
}
|
||||
|
||||
|
||||
// Use this constructor for dynamically created LLPerfBlock time slices
|
||||
// that are only enabled by specific control flags
|
||||
LLPerfBlock::LLPerfBlock( const char* key1, const char* key2, S32 flags ) : mPredefinedStat(NULL), mDynamicStat(NULL)
|
||||
{
|
||||
if ((sStatsFlags & flags) == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (NULL == key2 || strlen(key2) == 0)
|
||||
{
|
||||
@@ -629,10 +657,12 @@ LLPerfBlock::LLPerfBlock( const char* key1, const char* key2 ) : mPredefinedStat
|
||||
}
|
||||
}
|
||||
|
||||
// Set up the result data map if dynamic stats are enabled
|
||||
void LLPerfBlock::initDynamicStat(const std::string& key)
|
||||
{
|
||||
// Early exit if dynamic stats aren't enabled.
|
||||
if (!sStatsEnabled) return;
|
||||
if (sStatsFlags == LLSTATS_NO_OPTIONAL_STATS)
|
||||
return;
|
||||
|
||||
mLastPath = sCurrentStatPath; // Save and restore current path
|
||||
sCurrentStatPath += "/" + key; // Add key to current path
|
||||
@@ -713,7 +743,7 @@ void LLPerfBlock::addStatsToLLSDandReset( LLSD & stats,
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // WTF? Shouldn't have a NULL pointer in the map.
|
||||
{ // Shouldn't have a NULL pointer in the map.
|
||||
llwarns << "Unexpected NULL dynamic stat at '" << stats_full_path << "'" << llendl;
|
||||
}
|
||||
}
|
||||
@@ -725,14 +755,12 @@ void LLPerfBlock::addStatsToLLSDandReset( LLSD & stats,
|
||||
LLTimer LLStat::sTimer;
|
||||
LLFrameTimer LLStat::sFrameTimer;
|
||||
|
||||
LLStat::LLStat(const U32 num_bins, const BOOL use_frame_timer)
|
||||
void LLStat::init()
|
||||
{
|
||||
llassert(num_bins > 0);
|
||||
mUseFrameTimer = use_frame_timer;
|
||||
llassert(mNumBins > 0);
|
||||
mNumValues = 0;
|
||||
mLastValue = 0.f;
|
||||
mLastTime = 0.f;
|
||||
mNumBins = num_bins;
|
||||
mCurBin = (mNumBins-1);
|
||||
mNextBin = 0;
|
||||
mBins = new F32[mNumBins];
|
||||
@@ -746,6 +774,29 @@ LLStat::LLStat(const U32 num_bins, const BOOL use_frame_timer)
|
||||
mTime[i] = 0.0;
|
||||
mDT[i] = 0.f;
|
||||
}
|
||||
|
||||
if (!mName.empty())
|
||||
{
|
||||
stat_map_t::iterator iter = sStatList.find(mName);
|
||||
if (iter != sStatList.end())
|
||||
llwarns << "LLStat with duplicate name: " << mName << llendl;
|
||||
sStatList.insert(std::make_pair(mName, this));
|
||||
}
|
||||
}
|
||||
|
||||
LLStat::LLStat(const U32 num_bins, const BOOL use_frame_timer)
|
||||
: mUseFrameTimer(use_frame_timer),
|
||||
mNumBins(num_bins)
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
LLStat::LLStat(std::string name, U32 num_bins, BOOL use_frame_timer)
|
||||
: mUseFrameTimer(use_frame_timer),
|
||||
mNumBins(num_bins),
|
||||
mName(name)
|
||||
{
|
||||
init();
|
||||
}
|
||||
|
||||
LLStat::~LLStat()
|
||||
@@ -754,6 +805,15 @@ LLStat::~LLStat()
|
||||
delete[] mBeginTime;
|
||||
delete[] mTime;
|
||||
delete[] mDT;
|
||||
|
||||
if (!mName.empty())
|
||||
{
|
||||
// handle multiple entries with the same name
|
||||
stat_map_t::iterator iter = sStatList.find(mName);
|
||||
while (iter != sStatList.end() && iter->second != this)
|
||||
++iter;
|
||||
sStatList.erase(iter);
|
||||
}
|
||||
}
|
||||
|
||||
void LLStat::reset()
|
||||
|
||||
@@ -192,14 +192,23 @@ public:
|
||||
// Use this constructor for pre-defined LLStatTime objects
|
||||
LLPerfBlock(LLStatTime* stat);
|
||||
|
||||
// Use this constructor for dynamically created LLStatTime objects (not pre-defined) with a multi-part key
|
||||
LLPerfBlock( const char* key1, const char* key2 = NULL);
|
||||
// Use this constructor for normal, optional LLPerfBlock time slices
|
||||
LLPerfBlock( const char* key );
|
||||
|
||||
// Use this constructor for dynamically created LLPerfBlock time slices
|
||||
// that are only enabled by specific control flags
|
||||
LLPerfBlock( const char* key1, const char* key2, S32 flags = LLSTATS_BASIC_STATS );
|
||||
|
||||
~LLPerfBlock();
|
||||
|
||||
static void setStatsEnabled( BOOL enable ) { sStatsEnabled = enable; };
|
||||
static S32 getStatsEnabled() { return sStatsEnabled; };
|
||||
enum
|
||||
{ // Stats bitfield flags
|
||||
LLSTATS_NO_OPTIONAL_STATS = 0x00, // No optional stats gathering, just pre-defined LLStatTime objects
|
||||
LLSTATS_BASIC_STATS = 0x01, // Gather basic optional runtime stats
|
||||
LLSTATS_SCRIPT_FUNCTIONS = 0x02, // Include LSL function calls
|
||||
};
|
||||
static void setStatsFlags( S32 flags ) { sStatsFlags = flags; };
|
||||
static S32 getStatsFlags() { return sStatsFlags; };
|
||||
|
||||
static void clearDynamicStats(); // Reset maps to clear out dynamic objects
|
||||
static void addStatsToLLSDandReset( LLSD & stats, // Get current information and clear time bin
|
||||
@@ -213,7 +222,7 @@ private:
|
||||
LLStatTime * mPredefinedStat; // LLStatTime object to get data
|
||||
StatEntry * mDynamicStat; // StatEntryobject to get data
|
||||
|
||||
static BOOL sStatsEnabled; // Normally FALSE
|
||||
static S32 sStatsFlags; // Control what is being recorded
|
||||
static stat_map_t sStatMap; // Map full path string to LLStatTime objects
|
||||
static std::string sCurrentStatPath; // Something like "frame/physics/physics step"
|
||||
};
|
||||
@@ -236,7 +245,7 @@ public:
|
||||
BOOL frameStatsIsRunning() { return (mReportPerformanceStatEnd > 0.); };
|
||||
F32 getReportPerformanceInterval() const { return mReportPerformanceStatInterval; };
|
||||
void setReportPerformanceInterval( F32 interval ) { mReportPerformanceStatInterval = interval; };
|
||||
void setReportPerformanceDuration( F32 seconds );
|
||||
void setReportPerformanceDuration( F32 seconds, S32 flags = LLPerfBlock::LLSTATS_NO_OPTIONAL_STATS );
|
||||
void setProcessName(const std::string& process_name) { mProcessName = process_name; }
|
||||
void setProcessPID(S32 process_pid) { mProcessPID = process_pid; }
|
||||
|
||||
@@ -258,8 +267,15 @@ private:
|
||||
// ----------------------------------------------------------------------------
|
||||
class LL_COMMON_API LLStat
|
||||
{
|
||||
private:
|
||||
typedef std::multimap<std::string, LLStat*> stat_map_t;
|
||||
static stat_map_t sStatList;
|
||||
|
||||
void init();
|
||||
|
||||
public:
|
||||
LLStat(const U32 num_bins = 32, BOOL use_frame_timer = FALSE);
|
||||
LLStat(U32 num_bins = 32, BOOL use_frame_timer = FALSE);
|
||||
LLStat(std::string name, U32 num_bins = 32, BOOL use_frame_timer = FALSE);
|
||||
~LLStat();
|
||||
|
||||
void reset();
|
||||
@@ -322,8 +338,22 @@ private:
|
||||
F32 *mDT;
|
||||
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 = sStatList.find(name);
|
||||
if (iter != sStatList.end())
|
||||
return iter->second;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#endif // LL_STAT_
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
// skips spaces and tabs
|
||||
bool skip_whitespace(std::istream& input_stream)
|
||||
{
|
||||
char c = input_stream.peek();
|
||||
int c = input_stream.peek();
|
||||
while (('\t' == c || ' ' == c) && input_stream.good())
|
||||
{
|
||||
input_stream.get();
|
||||
@@ -57,7 +57,7 @@ bool skip_whitespace(std::istream& input_stream)
|
||||
// skips whitespace, newlines, and carriage returns
|
||||
bool skip_emptyspace(std::istream& input_stream)
|
||||
{
|
||||
char c = input_stream.peek();
|
||||
int c = input_stream.peek();
|
||||
while ( input_stream.good()
|
||||
&& ('\t' == c || ' ' == c || '\n' == c || '\r' == c) )
|
||||
{
|
||||
@@ -72,7 +72,7 @@ bool skip_comments_and_emptyspace(std::istream& input_stream)
|
||||
{
|
||||
while (skip_emptyspace(input_stream))
|
||||
{
|
||||
char c = input_stream.peek();
|
||||
int c = input_stream.peek();
|
||||
if ('#' == c )
|
||||
{
|
||||
while ('\n' != c && input_stream.good())
|
||||
@@ -90,7 +90,7 @@ bool skip_comments_and_emptyspace(std::istream& input_stream)
|
||||
|
||||
bool skip_line(std::istream& input_stream)
|
||||
{
|
||||
char c;
|
||||
int c;
|
||||
do
|
||||
{
|
||||
c = input_stream.get();
|
||||
@@ -100,7 +100,7 @@ bool skip_line(std::istream& input_stream)
|
||||
|
||||
bool skip_to_next_word(std::istream& input_stream)
|
||||
{
|
||||
char c = input_stream.peek();
|
||||
int c = input_stream.peek();
|
||||
while ( input_stream.good()
|
||||
&& ( (c >= 'a' && c <= 'z')
|
||||
|| (c >= 'A' && c <= 'Z')
|
||||
@@ -132,7 +132,7 @@ bool skip_to_end_of_next_keyword(const char* keyword, std::istream& input_stream
|
||||
while (input_stream.good())
|
||||
{
|
||||
skip_emptyspace(input_stream);
|
||||
char c = input_stream.get();
|
||||
int c = input_stream.get();
|
||||
if (keyword[0] != c)
|
||||
{
|
||||
skip_line(input_stream);
|
||||
@@ -181,7 +181,7 @@ bool skip_to_start_of_next_keyword(const char* keyword, std::istream& input_stre
|
||||
while (input_stream.good())
|
||||
{
|
||||
skip_emptyspace(input_stream);
|
||||
char c = input_stream.get();
|
||||
int c = input_stream.get();
|
||||
if (keyword[0] != c)
|
||||
{
|
||||
skip_line(input_stream);
|
||||
@@ -229,7 +229,7 @@ bool skip_to_start_of_next_keyword(const char* keyword, std::istream& input_stre
|
||||
bool get_word(std::string& output_string, std::istream& input_stream)
|
||||
{
|
||||
skip_emptyspace(input_stream);
|
||||
char c = input_stream.peek();
|
||||
int c = input_stream.peek();
|
||||
while ( !isspace(c)
|
||||
&& '\n' != c
|
||||
&& '\r' != c
|
||||
@@ -246,7 +246,7 @@ bool get_word(std::string& output_string, std::istream& input_stream, int n)
|
||||
{
|
||||
skip_emptyspace(input_stream);
|
||||
int char_count = 0;
|
||||
char c = input_stream.peek();
|
||||
int c = input_stream.peek();
|
||||
while (!isspace(c)
|
||||
&& '\n' != c
|
||||
&& '\r' != c
|
||||
@@ -265,7 +265,7 @@ bool get_word(std::string& output_string, std::istream& input_stream, int n)
|
||||
bool get_line(std::string& output_string, std::istream& input_stream)
|
||||
{
|
||||
output_string.clear();
|
||||
char c = input_stream.get();
|
||||
int c = input_stream.get();
|
||||
while (input_stream.good())
|
||||
{
|
||||
output_string += c;
|
||||
@@ -285,7 +285,7 @@ bool get_line(std::string& output_string, std::istream& input_stream, int n)
|
||||
{
|
||||
output_string.clear();
|
||||
int char_count = 0;
|
||||
char c = input_stream.get();
|
||||
int c = input_stream.get();
|
||||
while (input_stream.good() && char_count < n)
|
||||
{
|
||||
char_count++;
|
||||
|
||||
@@ -42,14 +42,17 @@ template <class Object> class LLStrider
|
||||
U8* mBytep;
|
||||
};
|
||||
U32 mSkip;
|
||||
U32 mTypeSize;
|
||||
public:
|
||||
|
||||
LLStrider() { mObjectp = NULL; mSkip = sizeof(Object); }
|
||||
LLStrider() { mObjectp = NULL; mTypeSize = mSkip = sizeof(Object); }
|
||||
~LLStrider() { }
|
||||
|
||||
const LLStrider<Object>& operator = (Object *first) { mObjectp = first; return *this;}
|
||||
void setStride (S32 skipBytes) { mSkip = (skipBytes ? skipBytes : sizeof(Object));}
|
||||
void setTypeSize (S32 typeBytes){ mTypeSize = (typeBytes ? typeBytes : sizeof(Object)); }
|
||||
|
||||
bool isStrided() const { return mTypeSize != mSkip; }
|
||||
void skip(const U32 index) { mBytep += mSkip*index;}
|
||||
U32 getSkip() const { return mSkip; }
|
||||
Object* get() { return mObjectp; }
|
||||
@@ -58,6 +61,71 @@ public:
|
||||
Object* operator ++(int) { Object* old = mObjectp; mBytep += mSkip; return old; }
|
||||
Object* operator +=(int i) { mBytep += mSkip*i; return mObjectp; }
|
||||
Object& operator[](U32 index) { return *(Object*)(mBytep + (mSkip * index)); }
|
||||
void assignArray(U8* __restrict source, const size_t elem_size, const size_t elem_count)
|
||||
{
|
||||
llassert_always(sizeof(Object) <= elem_size);
|
||||
|
||||
U8* __restrict dest = mBytep; //refer to dest instead of mBytep to benefit from __restrict hint
|
||||
const U32 bytes = elem_size * elem_count; //total bytes to copy from source to dest
|
||||
|
||||
//stride == sizeof(element) implies entire buffer is unstrided and thus memcpy-able, provided source buffer elements match in size.
|
||||
//Because LLStrider is often passed an LLVector3 even if the reprensentation is LLVector4 in the vertex buffer, mTypeSize is set to
|
||||
//the TRUE vbo datatype size via VertexBufferStrider::get
|
||||
if(!isStrided() && mTypeSize == elem_size)
|
||||
{
|
||||
if(bytes >= sizeof(LLVector4) * 4) //Should be able to pull at least 3 16byte blocks from this. Smaller isn't really beneficial.
|
||||
{
|
||||
U8* __restrict aligned_source = LL_NEXT_ALIGNED_ADDRESS(source);
|
||||
U8* __restrict aligned_dest = LL_NEXT_ALIGNED_ADDRESS(dest);
|
||||
const U32 source_offset = aligned_source - source; //Offset to first aligned location in source buffer.
|
||||
const U32 dest_offset = aligned_dest - dest; //Offset to first aligned location in dest buffer.
|
||||
llassert_always(source_offset < 16);
|
||||
llassert_always(dest_offset < 16);
|
||||
if(source_offset == dest_offset) //delta to aligned location matches between source and destination! _mm_*_ps should be viable.
|
||||
{
|
||||
const U32 end_offset = (bytes - source_offset) % sizeof(LLVector4); //buffers may not neatly end on a 16byte alignment boundary.
|
||||
const U32 aligned_bytes = bytes - source_offset - end_offset; //how many bytes to copy from aligned start to aligned end.
|
||||
|
||||
llassert_always(aligned_bytes > 0);
|
||||
|
||||
if(source_offset) //memcpy up to the aligned location if needed
|
||||
memcpy(dest,source,source_offset);
|
||||
LLVector4a::memcpyNonAliased16((F32*) aligned_dest, (F32*) aligned_source, aligned_bytes);
|
||||
if(end_offset) //memcpy to the very end if needed.
|
||||
memcpy(aligned_dest+aligned_bytes,aligned_source+aligned_bytes,end_offset);
|
||||
}
|
||||
else //buffers non-uniformly offset from aligned location. Using _mm_*u_ps.
|
||||
{
|
||||
U32 end = bytes/sizeof(LLVector4); //sizeof(LLVector4) = 16 bytes = 128 bits
|
||||
|
||||
llassert_always(end > 0);
|
||||
|
||||
__m128* dst = (__m128*) dest;
|
||||
__m128* src = (__m128*) source;
|
||||
|
||||
for (U32 i = 0; i < end; i++) //copy 128bit chunks
|
||||
{
|
||||
__m128 res = _mm_loadu_ps((F32*)&src[i]);
|
||||
_mm_storeu_ps((F32*)&dst[i], res);
|
||||
}
|
||||
end*=16;//Convert to real byte offset
|
||||
if(end < bytes) //just memcopy the rest
|
||||
memcpy(dest+end,source+end,bytes-end);
|
||||
}
|
||||
}
|
||||
else //Too small. just do a simple memcpy.
|
||||
memcpy(dest,source,bytes);
|
||||
}
|
||||
else
|
||||
{
|
||||
for(U32 i=0;i<elem_count;i++)
|
||||
{
|
||||
memcpy(dest,source,sizeof(Object));
|
||||
dest+=mSkip;
|
||||
source+=elem_size;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif // LL_LLSTRIDER_H
|
||||
|
||||
@@ -957,13 +957,18 @@ LLStringUtil::size_type LLStringUtil::getSubstitution(const std::string& instr,
|
||||
{
|
||||
const std::string delims (",");
|
||||
|
||||
// Find the first ]
|
||||
size_type pos2 = instr.find(']', start);
|
||||
// Find the first [
|
||||
size_type pos1 = instr.find('[', start);
|
||||
if (pos1 == std::string::npos)
|
||||
return std::string::npos;
|
||||
|
||||
//Find the first ] after the initial [
|
||||
size_type pos2 = instr.find(']', pos1);
|
||||
if (pos2 == std::string::npos)
|
||||
return std::string::npos;
|
||||
|
||||
// Find the last [ before ]
|
||||
size_type pos1 = instr.find_last_of('[', pos2-1);
|
||||
// Find the last [ before ] in case of nested [[]]
|
||||
pos1 = instr.find_last_of('[', pos2-1);
|
||||
if (pos1 == std::string::npos || pos1 < start)
|
||||
return std::string::npos;
|
||||
|
||||
|
||||
@@ -62,6 +62,21 @@
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#if !LL_DARWIN
|
||||
U32 ll_thread_local local_thread_ID = 0;
|
||||
#endif
|
||||
|
||||
U32 LLThread::sIDIter = 0;
|
||||
|
||||
LL_COMMON_API void assert_main_thread()
|
||||
{
|
||||
static U32 s_thread_id = LLThread::currentID();
|
||||
if (LLThread::currentID() != s_thread_id)
|
||||
{
|
||||
llerrs << "Illegal execution outside main thread." << llendl;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Handed to the APR thread creation function
|
||||
//
|
||||
@@ -73,31 +88,43 @@ void *APR_THREAD_FUNC LLThread::staticRun(apr_thread_t *apr_threadp, void *datap
|
||||
|
||||
LLThread *threadp = (LLThread *)datap;
|
||||
|
||||
// Set thread state to running
|
||||
threadp->mStatus = RUNNING;
|
||||
#if !LL_DARWIN
|
||||
local_thread_ID = threadp->mID;
|
||||
#endif
|
||||
|
||||
// Create a thread local data.
|
||||
AIThreadLocalData::create(threadp);
|
||||
LLThreadLocalData::create(threadp);
|
||||
|
||||
// Run the user supplied function
|
||||
threadp->run();
|
||||
|
||||
llinfos << "LLThread::staticRun() Exiting: " << threadp->mName << llendl;
|
||||
// Setting mStatus to STOPPED is done non-thread-safe, so it's
|
||||
// possible that the thread is deleted by another thread at
|
||||
// the moment it happens... therefore make a copy here.
|
||||
char const* volatile name = threadp->mName.c_str();
|
||||
|
||||
// We're done with the run function, this thread is done executing now.
|
||||
threadp->mStatus = STOPPED;
|
||||
|
||||
// Only now print this info [doing that before setting mStatus
|
||||
// to STOPPED makes it much more likely that another thread runs
|
||||
// after the LLCurl::Multi::run() function exits and we actually
|
||||
// change this variable (which really SHOULD have been inside
|
||||
// the critical area of the mSignal lock)].
|
||||
llinfos << "LLThread::staticRun() Exiting: " << name << llendl;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
LLThread::LLThread(std::string const& name) :
|
||||
mPaused(FALSE),
|
||||
mPaused(false),
|
||||
mName(name),
|
||||
mAPRThreadp(NULL),
|
||||
mStatus(STOPPED),
|
||||
mThreadLocalData(NULL)
|
||||
{
|
||||
mID = ++sIDIter;
|
||||
mRunCondition = new LLCondition;
|
||||
}
|
||||
|
||||
@@ -119,7 +146,7 @@ void LLThread::shutdown()
|
||||
// First, set the flag that indicates that we're ready to die
|
||||
setQuitting();
|
||||
|
||||
llinfos << "LLThread::~LLThread() Killing thread " << mName << " Status: " << mStatus << llendl;
|
||||
llinfos << "LLThread::shutdown() 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...
|
||||
@@ -142,20 +169,38 @@ void LLThread::shutdown()
|
||||
{
|
||||
// This thread just wouldn't stop, even though we gave it time
|
||||
llwarns << "LLThread::shutdown() exiting thread before clean exit!" << llendl;
|
||||
// Put a stake in its heart.
|
||||
apr_thread_exit(mAPRThreadp, -1);
|
||||
return;
|
||||
}
|
||||
mAPRThreadp = NULL;
|
||||
}
|
||||
|
||||
delete mRunCondition;
|
||||
mRunCondition = 0;
|
||||
}
|
||||
|
||||
void LLThread::start()
|
||||
{
|
||||
apr_thread_create(&mAPRThreadp, NULL, staticRun, (void *)this, tldata().mRootPool());
|
||||
llassert(isStopped());
|
||||
|
||||
// Set thread state to running
|
||||
mStatus = RUNNING;
|
||||
|
||||
// We won't bother joining
|
||||
apr_thread_detach(mAPRThreadp);
|
||||
apr_status_t status =
|
||||
apr_thread_create(&mAPRThreadp, NULL, staticRun, (void *)this, tldata().mRootPool());
|
||||
|
||||
if(status == APR_SUCCESS)
|
||||
{
|
||||
// We won't bother joining
|
||||
apr_thread_detach(mAPRThreadp);
|
||||
}
|
||||
else
|
||||
{
|
||||
mStatus = STOPPED;
|
||||
llwarns << "failed to start thread " << mName << llendl;
|
||||
ll_apr_warn_status(status);
|
||||
}
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
@@ -168,7 +213,7 @@ void LLThread::pause()
|
||||
if (!mPaused)
|
||||
{
|
||||
// this will cause the thread to stop execution as soon as checkPause() is called
|
||||
mPaused = 1; // Does not need to be atomic since this is only set/unset from the main thread
|
||||
mPaused = true; // Does not need to be atomic since this is only set/unset from the main thread
|
||||
}
|
||||
}
|
||||
|
||||
@@ -176,7 +221,7 @@ void LLThread::unpause()
|
||||
{
|
||||
if (mPaused)
|
||||
{
|
||||
mPaused = 0;
|
||||
mPaused = false;
|
||||
}
|
||||
|
||||
wake(); // wake up the thread if necessary
|
||||
@@ -256,14 +301,14 @@ void LLThread::wakeLocked()
|
||||
#ifdef SHOW_ASSERT
|
||||
// This allows the use of llassert(is_main_thread()) to assure the current thread is the main thread.
|
||||
static apr_os_thread_t main_thread_id;
|
||||
LL_COMMON_API bool is_main_thread() { return apr_os_thread_equal(main_thread_id, apr_os_thread_current()); }
|
||||
LL_COMMON_API bool is_main_thread(void) { return apr_os_thread_equal(main_thread_id, apr_os_thread_current()); }
|
||||
#endif
|
||||
|
||||
// The thread private handle to access the AIThreadLocalData instance.
|
||||
apr_threadkey_t* AIThreadLocalData::sThreadLocalDataKey;
|
||||
// The thread private handle to access the LLThreadLocalData instance.
|
||||
apr_threadkey_t* LLThreadLocalData::sThreadLocalDataKey;
|
||||
|
||||
//static
|
||||
void AIThreadLocalData::init(void)
|
||||
void LLThreadLocalData::init(void)
|
||||
{
|
||||
// Only do this once.
|
||||
if (sThreadLocalDataKey)
|
||||
@@ -271,13 +316,13 @@ void AIThreadLocalData::init(void)
|
||||
return;
|
||||
}
|
||||
|
||||
apr_status_t status = apr_threadkey_private_create(&sThreadLocalDataKey, &AIThreadLocalData::destroy, AIAPRRootPool::get()());
|
||||
apr_status_t status = apr_threadkey_private_create(&sThreadLocalDataKey, &LLThreadLocalData::destroy, LLAPRRootPool::get()());
|
||||
ll_apr_assert_status(status); // Or out of memory, or system-imposed limit on the
|
||||
// total number of keys per process {PTHREAD_KEYS_MAX}
|
||||
// total number of keys per process {PTHREAD_KEYS_MAX}
|
||||
// has been exceeded.
|
||||
|
||||
// Create the thread-local data for the main thread (this function is called by the main thread).
|
||||
AIThreadLocalData::create(NULL);
|
||||
LLThreadLocalData::create(NULL);
|
||||
|
||||
#ifdef SHOW_ASSERT
|
||||
// This function is called by the main thread.
|
||||
@@ -287,15 +332,15 @@ void AIThreadLocalData::init(void)
|
||||
|
||||
// This is called once for every thread when the thread is destructed.
|
||||
//static
|
||||
void AIThreadLocalData::destroy(void* thread_local_data)
|
||||
void LLThreadLocalData::destroy(void* thread_local_data)
|
||||
{
|
||||
delete reinterpret_cast<AIThreadLocalData*>(thread_local_data);
|
||||
delete static_cast<LLThreadLocalData*>(thread_local_data);
|
||||
}
|
||||
|
||||
//static
|
||||
void AIThreadLocalData::create(LLThread* threadp)
|
||||
void LLThreadLocalData::create(LLThread* threadp)
|
||||
{
|
||||
AIThreadLocalData* new_tld = new AIThreadLocalData;
|
||||
LLThreadLocalData* new_tld = new LLThreadLocalData;
|
||||
if (threadp)
|
||||
{
|
||||
threadp->mThreadLocalData = new_tld;
|
||||
@@ -305,36 +350,27 @@ void AIThreadLocalData::create(LLThread* threadp)
|
||||
}
|
||||
|
||||
//static
|
||||
AIThreadLocalData& AIThreadLocalData::tldata(void)
|
||||
LLThreadLocalData& LLThreadLocalData::tldata(void)
|
||||
{
|
||||
if (!sThreadLocalDataKey)
|
||||
AIThreadLocalData::init();
|
||||
{
|
||||
LLThreadLocalData::init();
|
||||
}
|
||||
|
||||
void* data;
|
||||
apr_status_t status = apr_threadkey_private_get(&data, sThreadLocalDataKey);
|
||||
llassert_always(status == APR_SUCCESS);
|
||||
return *static_cast<AIThreadLocalData*>(data);
|
||||
return *static_cast<LLThreadLocalData*>(data);
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
|
||||
bool LLMutexBase::isLocked()
|
||||
{
|
||||
if (!tryLock())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
apr_thread_mutex_unlock(mAPRMutexp);
|
||||
return false;
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
|
||||
LLCondition::LLCondition(AIAPRPool& parent) : LLMutex(parent)
|
||||
LLCondition::LLCondition(LLAPRPool& parent) : LLMutex(parent)
|
||||
{
|
||||
apr_thread_cond_create(&mAPRCondp, mPool());
|
||||
}
|
||||
|
||||
|
||||
LLCondition::~LLCondition()
|
||||
{
|
||||
apr_thread_cond_destroy(mAPRCondp);
|
||||
@@ -357,7 +393,45 @@ void LLCondition::broadcast()
|
||||
}
|
||||
|
||||
//============================================================================
|
||||
LLMutexBase::LLMutexBase() :
|
||||
mLockingThread(NO_THREAD),
|
||||
mCount(0)
|
||||
{
|
||||
}
|
||||
|
||||
void LLMutexBase::lock()
|
||||
{
|
||||
#if LL_DARWIN
|
||||
if (mLockingThread == LLThread::currentID())
|
||||
#else
|
||||
if (mLockingThread == local_thread_ID)
|
||||
#endif
|
||||
{ //redundant lock
|
||||
mCount++;
|
||||
return;
|
||||
}
|
||||
|
||||
apr_thread_mutex_lock(mAPRMutexp);
|
||||
|
||||
#if LL_DARWIN
|
||||
mLockingThread = LLThread::currentID();
|
||||
#else
|
||||
mLockingThread = local_thread_ID;
|
||||
#endif
|
||||
}
|
||||
|
||||
void LLMutexBase::unlock()
|
||||
{
|
||||
if (mCount > 0)
|
||||
{ //not the root unlock
|
||||
mCount--;
|
||||
return;
|
||||
}
|
||||
mLockingThread = NO_THREAD;
|
||||
|
||||
apr_thread_mutex_unlock(mAPRMutexp);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
//static
|
||||
|
||||
@@ -33,12 +33,11 @@
|
||||
#ifndef LL_LLTHREAD_H
|
||||
#define LL_LLTHREAD_H
|
||||
|
||||
#include "llapr.h"
|
||||
#include "llapp.h"
|
||||
#include "llapr.h"
|
||||
#include "llmemory.h"
|
||||
|
||||
#include "apr_thread_cond.h"
|
||||
#include "aiaprpool.h"
|
||||
#include "llaprpool.h"
|
||||
|
||||
#ifdef SHOW_ASSERT
|
||||
extern LL_COMMON_API bool is_main_thread(void);
|
||||
@@ -48,24 +47,33 @@ class LLThread;
|
||||
class LLMutex;
|
||||
class LLCondition;
|
||||
|
||||
class LL_COMMON_API AIThreadLocalData
|
||||
#if LL_WINDOWS
|
||||
#define ll_thread_local __declspec(thread)
|
||||
#else
|
||||
#define ll_thread_local __thread
|
||||
#endif
|
||||
|
||||
class LL_COMMON_API LLThreadLocalData
|
||||
{
|
||||
private:
|
||||
static apr_threadkey_t* sThreadLocalDataKey;
|
||||
|
||||
public:
|
||||
// Thread-local memory pool.
|
||||
AIAPRRootPool mRootPool;
|
||||
AIVolatileAPRPool mVolatileAPRPool;
|
||||
LLAPRRootPool mRootPool;
|
||||
LLVolatileAPRPool mVolatileAPRPool;
|
||||
|
||||
static void init(void);
|
||||
static void destroy(void* thread_local_data);
|
||||
static void create(LLThread* pthread);
|
||||
static AIThreadLocalData& tldata(void);
|
||||
static LLThreadLocalData& tldata(void);
|
||||
};
|
||||
|
||||
class LL_COMMON_API LLThread
|
||||
{
|
||||
private:
|
||||
static U32 sIDIter;
|
||||
|
||||
public:
|
||||
typedef enum e_thread_status
|
||||
{
|
||||
@@ -89,7 +97,7 @@ public:
|
||||
// Called from MAIN THREAD.
|
||||
void pause();
|
||||
void unpause();
|
||||
bool isPaused() { return isStopped() || mPaused == TRUE; }
|
||||
bool isPaused() { return isStopped() || mPaused; }
|
||||
|
||||
// Cause the thread to wake up and check its condition
|
||||
void wake();
|
||||
@@ -104,10 +112,12 @@ public:
|
||||
void start(void);
|
||||
|
||||
// Return thread-local data for the current thread.
|
||||
static AIThreadLocalData& tldata(void) { return AIThreadLocalData::tldata(); }
|
||||
static LLThreadLocalData& tldata(void) { return LLThreadLocalData::tldata(); }
|
||||
|
||||
U32 getID() const { return mID; }
|
||||
|
||||
private:
|
||||
BOOL mPaused;
|
||||
bool mPaused;
|
||||
|
||||
// static function passed to APR thread creation routine
|
||||
static void *APR_THREAD_FUNC staticRun(apr_thread_t *apr_threadp, void *datap);
|
||||
@@ -117,10 +127,11 @@ protected:
|
||||
LLCondition* mRunCondition;
|
||||
|
||||
apr_thread_t *mAPRThreadp;
|
||||
EThreadStatus mStatus;
|
||||
volatile EThreadStatus mStatus;
|
||||
U32 mID;
|
||||
|
||||
friend void AIThreadLocalData::create(LLThread* threadp);
|
||||
AIThreadLocalData* mThreadLocalData;
|
||||
friend void LLThreadLocalData::create(LLThread* threadp);
|
||||
LLThreadLocalData* mThreadLocalData;
|
||||
|
||||
void setQuitting();
|
||||
|
||||
@@ -148,37 +159,60 @@ protected:
|
||||
|
||||
//============================================================================
|
||||
|
||||
#define MUTEX_DEBUG (LL_DEBUG || LL_RELEASE_WITH_DEBUG_INFO)
|
||||
|
||||
#ifdef MUTEX_DEBUG
|
||||
// We really shouldn't be using recursive locks. Make sure of that in debug mode.
|
||||
#define MUTEX_FLAG APR_THREAD_MUTEX_UNNESTED
|
||||
#else
|
||||
// Use the fastest platform-optimal lock behavior (can be recursive or non-recursive).
|
||||
#define MUTEX_FLAG APR_THREAD_MUTEX_DEFAULT
|
||||
#endif
|
||||
|
||||
class LL_COMMON_API LLMutexBase
|
||||
{
|
||||
public:
|
||||
void lock() { apr_thread_mutex_lock(mAPRMutexp); }
|
||||
void unlock() { apr_thread_mutex_unlock(mAPRMutexp); }
|
||||
typedef enum
|
||||
{
|
||||
NO_THREAD = 0xFFFFFFFF
|
||||
} e_locking_thread;
|
||||
|
||||
LLMutexBase() ;
|
||||
|
||||
void lock(); //blocks
|
||||
void unlock();
|
||||
// Returns true if lock was obtained successfully.
|
||||
bool tryLock() { return !APR_STATUS_IS_EBUSY(apr_thread_mutex_trylock(mAPRMutexp)); }
|
||||
|
||||
bool isLocked(); // non-blocking, but does do a lock/unlock so not free
|
||||
// non-blocking, but does do a lock/unlock so not free
|
||||
bool isLocked() { bool is_not_locked = tryLock(); if (is_not_locked) unlock(); return !is_not_locked; }
|
||||
// get ID of locking thread
|
||||
U32 lockingThread() const { return mLockingThread; }
|
||||
|
||||
protected:
|
||||
// mAPRMutexp is initialized and uninitialized in the derived class.
|
||||
apr_thread_mutex_t* mAPRMutexp;
|
||||
mutable U32 mCount;
|
||||
mutable U32 mLockingThread;
|
||||
};
|
||||
|
||||
class LL_COMMON_API LLMutex : public LLMutexBase
|
||||
{
|
||||
public:
|
||||
LLMutex(AIAPRPool& parent = LLThread::tldata().mRootPool) : mPool(parent)
|
||||
LLMutex(LLAPRPool& parent = LLThread::tldata().mRootPool) : mPool(parent)
|
||||
{
|
||||
apr_thread_mutex_create(&mAPRMutexp, APR_THREAD_MUTEX_UNNESTED, mPool());
|
||||
apr_thread_mutex_create(&mAPRMutexp, MUTEX_FLAG, mPool());
|
||||
}
|
||||
~LLMutex()
|
||||
{
|
||||
llassert(!isLocked()); // better not be locked!
|
||||
//this assertion erroneously triggers whenever an LLCondition is destroyed
|
||||
//llassert(!isLocked()); // better not be locked!
|
||||
apr_thread_mutex_destroy(mAPRMutexp);
|
||||
mAPRMutexp = NULL;
|
||||
}
|
||||
|
||||
protected:
|
||||
AIAPRPool mPool;
|
||||
LLAPRPool mPool;
|
||||
private:
|
||||
// Disable copy construction, as si teh bomb!!! -SG
|
||||
LLMutex(const LLMutex&);
|
||||
@@ -194,7 +228,7 @@ class LL_COMMON_API LLMutexRootPool : public LLMutexBase
|
||||
public:
|
||||
LLMutexRootPool(void)
|
||||
{
|
||||
apr_thread_mutex_create(&mAPRMutexp, APR_THREAD_MUTEX_UNNESTED, mRootPool());
|
||||
apr_thread_mutex_create(&mAPRMutexp, MUTEX_FLAG, mRootPool());
|
||||
}
|
||||
~LLMutexRootPool()
|
||||
{
|
||||
@@ -208,7 +242,7 @@ public:
|
||||
}
|
||||
|
||||
protected:
|
||||
AIAPRRootPool mRootPool;
|
||||
LLAPRRootPool mRootPool;
|
||||
};
|
||||
#endif // APR_HAS_THREADS
|
||||
|
||||
@@ -216,7 +250,7 @@ protected:
|
||||
class LL_COMMON_API LLCondition : public LLMutex
|
||||
{
|
||||
public:
|
||||
LLCondition(AIAPRPool& parent = LLThread::tldata().mRootPool);
|
||||
LLCondition(LLAPRPool& parent = LLThread::tldata().mRootPool);
|
||||
~LLCondition();
|
||||
|
||||
void wait(); // blocks
|
||||
@@ -246,7 +280,7 @@ private:
|
||||
class AIRWLock
|
||||
{
|
||||
public:
|
||||
AIRWLock(AIAPRPool& parent = LLThread::tldata().mRootPool) :
|
||||
AIRWLock(LLAPRPool& parent = LLThread::tldata().mRootPool) :
|
||||
mWriterWaitingMutex(parent), mNoHoldersCondition(parent), mHoldersCount(0), mWriterIsWaiting(false) { }
|
||||
|
||||
private:
|
||||
@@ -350,6 +384,7 @@ void LLThread::unlockData()
|
||||
mRunCondition->unlock();
|
||||
}
|
||||
|
||||
|
||||
//============================================================================
|
||||
|
||||
// see llmemory.h for LLPointer<> definition
|
||||
|
||||
100
indra/llcommon/llthreadsafequeue.cpp
Normal file
100
indra/llcommon/llthreadsafequeue.cpp
Normal file
@@ -0,0 +1,100 @@
|
||||
/**
|
||||
* @file llthread.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 <apr_pools.h>
|
||||
#include <apr_queue.h>
|
||||
#include "llthreadsafequeue.h"
|
||||
|
||||
|
||||
|
||||
// LLThreadSafeQueueImplementation
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
LLThreadSafeQueueImplementation::LLThreadSafeQueueImplementation(unsigned int capacity):
|
||||
mQueue(0)
|
||||
{
|
||||
mPool.create();
|
||||
apr_status_t status = apr_queue_create(&mQueue, capacity, mPool());
|
||||
if(status != APR_SUCCESS) throw LLThreadSafeQueueError("failed to allocate queue");
|
||||
}
|
||||
|
||||
|
||||
LLThreadSafeQueueImplementation::~LLThreadSafeQueueImplementation()
|
||||
{
|
||||
if(mQueue != 0) {
|
||||
if(apr_queue_size(mQueue) != 0) llwarns <<
|
||||
"terminating queue which still contains " << apr_queue_size(mQueue) <<
|
||||
" elements;" << "memory will be leaked" << LL_ENDL;
|
||||
apr_queue_term(mQueue);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void LLThreadSafeQueueImplementation::pushFront(void * element)
|
||||
{
|
||||
apr_status_t status = apr_queue_push(mQueue, element);
|
||||
|
||||
if(status == APR_EINTR) {
|
||||
throw LLThreadSafeQueueInterrupt();
|
||||
} else if(status != APR_SUCCESS) {
|
||||
throw LLThreadSafeQueueError("push failed");
|
||||
} else {
|
||||
; // Success.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool LLThreadSafeQueueImplementation::tryPushFront(void * element){
|
||||
return apr_queue_trypush(mQueue, element) == APR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
void * LLThreadSafeQueueImplementation::popBack(void)
|
||||
{
|
||||
void * element;
|
||||
apr_status_t status = apr_queue_pop(mQueue, &element);
|
||||
|
||||
if(status == APR_EINTR) {
|
||||
throw LLThreadSafeQueueInterrupt();
|
||||
} else if(status != APR_SUCCESS) {
|
||||
throw LLThreadSafeQueueError("pop failed");
|
||||
} else {
|
||||
return element;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool LLThreadSafeQueueImplementation::tryPopBack(void *& element)
|
||||
{
|
||||
return apr_queue_trypop(mQueue, &element) == APR_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
size_t LLThreadSafeQueueImplementation::size()
|
||||
{
|
||||
return apr_queue_size(mQueue);
|
||||
}
|
||||
203
indra/llcommon/llthreadsafequeue.h
Normal file
203
indra/llcommon/llthreadsafequeue.h
Normal file
@@ -0,0 +1,203 @@
|
||||
/**
|
||||
* @file llthreadsafequeue.h
|
||||
* @brief Base classes for thread, mutex and condition handling.
|
||||
*
|
||||
* $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_LLTHREADSAFEQUEUE_H
|
||||
#define LL_LLTHREADSAFEQUEUE_H
|
||||
|
||||
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#include "llaprpool.h"
|
||||
|
||||
|
||||
class LLThreadSafeQueueImplementation; // See below.
|
||||
|
||||
|
||||
//
|
||||
// A general queue exception.
|
||||
//
|
||||
class LL_COMMON_API LLThreadSafeQueueError:
|
||||
public std::runtime_error
|
||||
{
|
||||
public:
|
||||
LLThreadSafeQueueError(std::string const & message):
|
||||
std::runtime_error(message)
|
||||
{
|
||||
; // No op.
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// An exception raised when blocking operations are interrupted.
|
||||
//
|
||||
class LL_COMMON_API LLThreadSafeQueueInterrupt:
|
||||
public LLThreadSafeQueueError
|
||||
{
|
||||
public:
|
||||
LLThreadSafeQueueInterrupt(void):
|
||||
LLThreadSafeQueueError("queue operation interrupted")
|
||||
{
|
||||
; // No op.
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct apr_queue_t; // From apr_queue.h
|
||||
|
||||
|
||||
//
|
||||
// Implementation details.
|
||||
//
|
||||
class LL_COMMON_API LLThreadSafeQueueImplementation
|
||||
{
|
||||
public:
|
||||
LLThreadSafeQueueImplementation(unsigned int capacity);
|
||||
~LLThreadSafeQueueImplementation();
|
||||
void pushFront(void * element);
|
||||
bool tryPushFront(void * element);
|
||||
void * popBack(void);
|
||||
bool tryPopBack(void *& element);
|
||||
size_t size();
|
||||
|
||||
private:
|
||||
LLAPRPool mPool; // The pool used for mQueue.
|
||||
apr_queue_t * mQueue;
|
||||
};
|
||||
|
||||
|
||||
//
|
||||
// Implements a thread safe FIFO.
|
||||
//
|
||||
template<typename ElementT>
|
||||
class LLThreadSafeQueue
|
||||
{
|
||||
public:
|
||||
typedef ElementT value_type;
|
||||
|
||||
// Constructor.
|
||||
LLThreadSafeQueue(unsigned int capacity = 1024);
|
||||
|
||||
// Add an element to the front of queue (will block if the queue has
|
||||
// reached capacity).
|
||||
//
|
||||
// This call will raise an interrupt error if the queue is deleted while
|
||||
// the caller is blocked.
|
||||
void pushFront(ElementT const & element);
|
||||
|
||||
// Try to add an element to the front ofqueue without blocking. Returns
|
||||
// true only if the element was actually added.
|
||||
bool tryPushFront(ElementT const & element);
|
||||
|
||||
// Pop the element at the end of the queue (will block if the queue is
|
||||
// empty).
|
||||
//
|
||||
// This call will raise an interrupt error if the queue is deleted while
|
||||
// the caller is blocked.
|
||||
ElementT popBack(void);
|
||||
|
||||
// Pop an element from the end of the queue if there is one available.
|
||||
// Returns true only if an element was popped.
|
||||
bool tryPopBack(ElementT & element);
|
||||
|
||||
// Returns the size of the queue.
|
||||
size_t size();
|
||||
|
||||
private:
|
||||
LLThreadSafeQueueImplementation mImplementation;
|
||||
};
|
||||
|
||||
|
||||
|
||||
// LLThreadSafeQueue
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
template<typename ElementT>
|
||||
LLThreadSafeQueue<ElementT>::LLThreadSafeQueue(unsigned int capacity) :
|
||||
mImplementation(capacity)
|
||||
{
|
||||
; // No op.
|
||||
}
|
||||
|
||||
|
||||
template<typename ElementT>
|
||||
void LLThreadSafeQueue<ElementT>::pushFront(ElementT const & element)
|
||||
{
|
||||
ElementT * elementCopy = new ElementT(element);
|
||||
try {
|
||||
mImplementation.pushFront(elementCopy);
|
||||
} catch (LLThreadSafeQueueInterrupt) {
|
||||
delete elementCopy;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template<typename ElementT>
|
||||
bool LLThreadSafeQueue<ElementT>::tryPushFront(ElementT const & element)
|
||||
{
|
||||
ElementT * elementCopy = new ElementT(element);
|
||||
bool result = mImplementation.tryPushFront(elementCopy);
|
||||
if(!result) delete elementCopy;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
template<typename ElementT>
|
||||
ElementT LLThreadSafeQueue<ElementT>::popBack(void)
|
||||
{
|
||||
ElementT * element = reinterpret_cast<ElementT *> (mImplementation.popBack());
|
||||
ElementT result(*element);
|
||||
delete element;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
template<typename ElementT>
|
||||
bool LLThreadSafeQueue<ElementT>::tryPopBack(ElementT & element)
|
||||
{
|
||||
void * storedElement;
|
||||
bool result = mImplementation.tryPopBack(storedElement);
|
||||
if(result) {
|
||||
ElementT * elementPtr = reinterpret_cast<ElementT *>(storedElement);
|
||||
element = *elementPtr;
|
||||
delete elementPtr;
|
||||
} else {
|
||||
; // No op.
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
template<typename ElementT>
|
||||
size_t LLThreadSafeQueue<ElementT>::size(void)
|
||||
{
|
||||
return mImplementation.size();
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
@@ -36,6 +36,8 @@
|
||||
|
||||
#include "u64.h"
|
||||
|
||||
#include "lldate.h"
|
||||
|
||||
#if LL_WINDOWS
|
||||
# define WIN32_LEAN_AND_MEAN
|
||||
# include <winsock2.h>
|
||||
|
||||
@@ -39,8 +39,6 @@
|
||||
#include <limits.h>
|
||||
|
||||
#include "stdtypes.h"
|
||||
#include "llpreprocessor.h"
|
||||
#include "lldate.h"
|
||||
|
||||
#include <string>
|
||||
#include <list>
|
||||
@@ -55,8 +53,6 @@ const U32 USEC_PER_HOUR = USEC_PER_MIN * MIN_PER_HOUR;
|
||||
const U32 SEC_PER_HOUR = SEC_PER_MIN * MIN_PER_HOUR;
|
||||
const F64 SEC_PER_USEC = 1.0 / (F64) USEC_PER_SEC;
|
||||
|
||||
LL_COMMON_API U64 totalTime(); // Returns current system time in microseconds
|
||||
|
||||
class LL_COMMON_API LLTimer
|
||||
{
|
||||
public:
|
||||
@@ -175,4 +171,5 @@ LL_COMMON_API void secondsToTimecodeString(F32 current_time, std::string& tcstri
|
||||
LL_COMMON_API void timeToFormattedString(time_t time, std::string format, std::string ×tr);
|
||||
LL_COMMON_API void timeStructToFormattedString(struct tm * time, std::string format, std::string ×tr);
|
||||
|
||||
U64 LL_COMMON_API totalTime(); // Returns current system time in microseconds
|
||||
#endif
|
||||
|
||||
705
indra/llcommon/lltreeiterators.h
Normal file
705
indra/llcommon/lltreeiterators.h
Normal file
@@ -0,0 +1,705 @@
|
||||
/**
|
||||
* @file lltreeiterators.h
|
||||
* @author Nat Goodspeed
|
||||
* @date 2008-08-19
|
||||
* @brief This file defines iterators useful for traversing arbitrary node
|
||||
* classes, potentially polymorphic, linked into strict tree
|
||||
* structures.
|
||||
*
|
||||
* Dereferencing any one of these iterators actually yields a @em
|
||||
* pointer to the node in question. For example, given an
|
||||
* LLLinkedIter<MyNode> <tt>li</tt>, <tt>*li</tt> gets you a pointer
|
||||
* to MyNode, and <tt>**li</tt> gets you the MyNode instance itself.
|
||||
* More commonly, instead of writing <tt>li->member</tt>, you write
|
||||
* <tt>(*li)->member</tt> -- as you would if you were traversing an
|
||||
* STL container of MyNode pointers.
|
||||
*
|
||||
* It would certainly be possible to build these iterators so that
|
||||
* <tt>*iterator</tt> would return a reference to the node itself
|
||||
* rather than a pointer to the node, and for many purposes it would
|
||||
* even be more convenient. However, that would be insufficiently
|
||||
* flexible. If you want to use an iterator range to (e.g.) initialize
|
||||
* a std::vector collecting results -- you rarely want to actually @em
|
||||
* copy the nodes in question. You're much more likely to want to copy
|
||||
* <i>pointers to</i> the traversed nodes. Hence these iterators
|
||||
* produce pointers.
|
||||
*
|
||||
* Though you specify the actual NODE class as the template parameter,
|
||||
* these iterators internally use LLPtrTo<> to discover whether to
|
||||
* store and return an LLPointer<NODE> or a simple NODE*.
|
||||
*
|
||||
* By strict tree structures, we mean that each child must have
|
||||
* exactly one parent. This forbids a child claiming any ancestor as a
|
||||
* child of its own. Child nodes with multiple parents will be visited
|
||||
* once for each parent. Cycles in the graph will result in either an
|
||||
* infinite loop or an out-of-memory crash. You Have Been Warned.
|
||||
*
|
||||
* $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$
|
||||
*/
|
||||
|
||||
#if ! defined(LL_LLTREEITERATORS_H)
|
||||
#define LL_LLTREEITERATORS_H
|
||||
|
||||
#include "llptrto.h"
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
#include <boost/iterator/iterator_facade.hpp>
|
||||
#include <boost/function.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
|
||||
namespace LLTreeIter
|
||||
{
|
||||
/// Discriminator between LLTreeUpIter and LLTreeDownIter
|
||||
enum RootIter { UP, DOWN };
|
||||
/// Discriminator between LLTreeDFSIter, LLTreeDFSPostIter and LLTreeBFSIter
|
||||
enum WalkIter { DFS_PRE, DFS_POST, BFS };
|
||||
}
|
||||
|
||||
/**
|
||||
* LLBaseIter defines some machinery common to all these iterators. We use
|
||||
* boost::iterator_facade to define the iterator boilerplate: the conventional
|
||||
* operators and methods necessary to implement a standards-conforming
|
||||
* iterator. That allows us to specify the actual iterator semantics in terms
|
||||
* of equal(), dereference() and increment() methods.
|
||||
*/
|
||||
template <class SELFTYPE, class NODE>
|
||||
class LLBaseIter: public boost::iterator_facade<SELFTYPE,
|
||||
// use pointer type as the
|
||||
// reference type
|
||||
typename LLPtrTo<NODE>::type,
|
||||
boost::forward_traversal_tag>
|
||||
{
|
||||
protected:
|
||||
/// LLPtrTo<NODE>::type is either NODE* or LLPointer<NODE>, as appropriate
|
||||
typedef typename LLPtrTo<NODE>::type ptr_type;
|
||||
/// function that advances from this node to next accepts a node pointer
|
||||
/// and returns another
|
||||
typedef boost::function<ptr_type(const ptr_type&)> func_type;
|
||||
typedef SELFTYPE self_type;
|
||||
};
|
||||
|
||||
/// Functor returning NULL, suitable for an end-iterator's 'next' functor
|
||||
template <class NODE>
|
||||
typename LLPtrTo<NODE>::type LLNullNextFunctor(const typename LLPtrTo<NODE>::type&)
|
||||
{
|
||||
return typename LLPtrTo<NODE>::type();
|
||||
}
|
||||
|
||||
/**
|
||||
* LLLinkedIter is an iterator over an intrusive singly-linked list. The
|
||||
* beginning of the list is represented by LLLinkedIter(list head); the end is
|
||||
* represented by LLLinkedIter().
|
||||
*
|
||||
* The begin LLLinkedIter must be instantiated with a functor to extract the
|
||||
* 'next' pointer from the current node. Supposing that the link pointer is @c
|
||||
* public, something like:
|
||||
*
|
||||
* @code
|
||||
* NODE* mNext;
|
||||
* @endcode
|
||||
*
|
||||
* you can use (e.g.) <tt>boost::bind(&NODE::mNext, _1)</tt> for the purpose.
|
||||
* Alternatively, you can bind whatever accessor method is normally used to
|
||||
* advance to the next node, e.g. for:
|
||||
*
|
||||
* @code
|
||||
* NODE* next() const;
|
||||
* @endcode
|
||||
*
|
||||
* you can use <tt>boost::bind(&NODE::next, _1)</tt>.
|
||||
*/
|
||||
template <class NODE>
|
||||
class LLLinkedIter: public LLBaseIter<LLLinkedIter<NODE>, NODE>
|
||||
{
|
||||
typedef LLBaseIter<LLLinkedIter<NODE>, NODE> super;
|
||||
protected:
|
||||
/// some methods need to return a reference to self
|
||||
typedef typename super::self_type self_type;
|
||||
typedef typename super::ptr_type ptr_type;
|
||||
typedef typename super::func_type func_type;
|
||||
public:
|
||||
/// Instantiate an LLLinkedIter to start a range, or to end a range before
|
||||
/// a particular list entry. Pass a functor to extract the 'next' pointer
|
||||
/// from the current node.
|
||||
LLLinkedIter(const ptr_type& entry, const func_type& nextfunc):
|
||||
mCurrent(entry),
|
||||
mNextFunc(nextfunc)
|
||||
{}
|
||||
/// Instantiate an LLLinkedIter to end a range at the end of the list
|
||||
LLLinkedIter():
|
||||
mCurrent(),
|
||||
mNextFunc(LLNullNextFunctor<NODE>)
|
||||
{}
|
||||
|
||||
private:
|
||||
/// leverage boost::iterator_facade
|
||||
friend class boost::iterator_core_access;
|
||||
|
||||
/// advance
|
||||
void increment()
|
||||
{
|
||||
mCurrent = mNextFunc(mCurrent);
|
||||
}
|
||||
/// equality
|
||||
bool equal(const self_type& that) const { return this->mCurrent == that.mCurrent; }
|
||||
/// dereference
|
||||
ptr_type& dereference() const { return const_cast<ptr_type&>(mCurrent); }
|
||||
|
||||
ptr_type mCurrent;
|
||||
func_type mNextFunc;
|
||||
};
|
||||
|
||||
/**
|
||||
* LLTreeUpIter walks from the node in hand to the root of the tree. The term
|
||||
* "up" is applied to a tree visualized with the root at the top.
|
||||
*
|
||||
* LLTreeUpIter is an alias for LLLinkedIter, since any linked tree that you
|
||||
* can navigate that way at all contains parent pointers.
|
||||
*/
|
||||
template <class NODE>
|
||||
class LLTreeUpIter: public LLLinkedIter<NODE>
|
||||
{
|
||||
typedef LLLinkedIter<NODE> super;
|
||||
public:
|
||||
/// Instantiate an LLTreeUpIter to start from a particular tree node, or
|
||||
/// to end a parent traversal before reaching a particular ancestor. Pass
|
||||
/// a functor to extract the 'parent' pointer from the current node.
|
||||
LLTreeUpIter(const typename super::ptr_type& node,
|
||||
const typename super::func_type& parentfunc):
|
||||
super(node, parentfunc)
|
||||
{}
|
||||
/// Instantiate an LLTreeUpIter to end a range at the root of the tree
|
||||
LLTreeUpIter():
|
||||
super()
|
||||
{}
|
||||
};
|
||||
|
||||
/**
|
||||
* LLTreeDownIter walks from the root of the tree to the node in hand. The
|
||||
* term "down" is applied to a tree visualized with the root at the top.
|
||||
*
|
||||
* Though you instantiate the begin() LLTreeDownIter with a pointer to some
|
||||
* node at an arbitrary location in the tree, the root will be the first node
|
||||
* you dereference and the passed node will be the last node you dereference.
|
||||
*
|
||||
* On construction, LLTreeDownIter walks from the current node to the root,
|
||||
* capturing the path. Then in use, it replays that walk in reverse. As with
|
||||
* all traversals of interesting data structures, it is actively dangerous to
|
||||
* modify the tree during an LLTreeDownIter walk.
|
||||
*/
|
||||
template <class NODE>
|
||||
class LLTreeDownIter: public LLBaseIter<LLTreeDownIter<NODE>, NODE>
|
||||
{
|
||||
typedef LLBaseIter<LLTreeDownIter<NODE>, NODE> super;
|
||||
typedef typename super::self_type self_type;
|
||||
protected:
|
||||
typedef typename super::ptr_type ptr_type;
|
||||
typedef typename super::func_type func_type;
|
||||
private:
|
||||
typedef std::vector<ptr_type> list_type;
|
||||
public:
|
||||
/// Instantiate an LLTreeDownIter to end at a particular tree node. Pass a
|
||||
/// functor to extract the 'parent' pointer from the current node.
|
||||
LLTreeDownIter(const ptr_type& node,
|
||||
const func_type& parentfunc)
|
||||
{
|
||||
for (ptr_type n = node; n; n = parentfunc(n))
|
||||
mParents.push_back(n);
|
||||
}
|
||||
/// Instantiate an LLTreeDownIter representing "here", the end of the loop
|
||||
LLTreeDownIter() {}
|
||||
|
||||
private:
|
||||
/// leverage boost::iterator_facade
|
||||
friend class boost::iterator_core_access;
|
||||
|
||||
/// advance
|
||||
void increment()
|
||||
{
|
||||
mParents.pop_back();
|
||||
}
|
||||
/// equality
|
||||
bool equal(const self_type& that) const { return this->mParents == that.mParents; }
|
||||
/// implement dereference/indirection operators
|
||||
ptr_type& dereference() const { return const_cast<ptr_type&>(mParents.back()); }
|
||||
|
||||
list_type mParents;
|
||||
};
|
||||
|
||||
/**
|
||||
* When you want to select between LLTreeUpIter and LLTreeDownIter with a
|
||||
* compile-time discriminator, use LLTreeRootIter with an LLTreeIter::RootIter
|
||||
* template arg.
|
||||
*/
|
||||
template <LLTreeIter::RootIter DISCRIM, class NODE>
|
||||
class LLTreeRootIter
|
||||
{
|
||||
enum { use_a_valid_LLTreeIter_RootIter_value = false };
|
||||
public:
|
||||
/// Bogus constructors for default (unrecognized discriminator) case
|
||||
template <typename TYPE1, typename TYPE2>
|
||||
LLTreeRootIter(TYPE1, TYPE2)
|
||||
{
|
||||
BOOST_STATIC_ASSERT(use_a_valid_LLTreeIter_RootIter_value);
|
||||
}
|
||||
LLTreeRootIter()
|
||||
{
|
||||
BOOST_STATIC_ASSERT(use_a_valid_LLTreeIter_RootIter_value);
|
||||
}
|
||||
};
|
||||
|
||||
/// Specialize for LLTreeIter::UP
|
||||
template <class NODE>
|
||||
class LLTreeRootIter<LLTreeIter::UP, NODE>: public LLTreeUpIter<NODE>
|
||||
{
|
||||
typedef LLTreeUpIter<NODE> super;
|
||||
public:
|
||||
/// forward begin ctor
|
||||
LLTreeRootIter(const typename super::ptr_type& node,
|
||||
const typename super::func_type& parentfunc):
|
||||
super(node, parentfunc)
|
||||
{}
|
||||
/// forward end ctor
|
||||
LLTreeRootIter():
|
||||
super()
|
||||
{}
|
||||
};
|
||||
|
||||
/// Specialize for LLTreeIter::DOWN
|
||||
template <class NODE>
|
||||
class LLTreeRootIter<LLTreeIter::DOWN, NODE>: public LLTreeDownIter<NODE>
|
||||
{
|
||||
typedef LLTreeDownIter<NODE> super;
|
||||
public:
|
||||
/// forward begin ctor
|
||||
LLTreeRootIter(const typename super::ptr_type& node,
|
||||
const typename super::func_type& parentfunc):
|
||||
super(node, parentfunc)
|
||||
{}
|
||||
/// forward end ctor
|
||||
LLTreeRootIter():
|
||||
super()
|
||||
{}
|
||||
};
|
||||
|
||||
/**
|
||||
* Instantiated with a tree node, typically the root, LLTreeDFSIter "flattens"
|
||||
* a depth-first tree walk through that node and all its descendants.
|
||||
*
|
||||
* The begin() LLTreeDFSIter must be instantiated with functors to obtain from
|
||||
* a given node begin() and end() iterators for that node's children. For this
|
||||
* reason, you must specify the type of the node's child iterator as an
|
||||
* additional template parameter.
|
||||
*
|
||||
* Specifically, the begin functor must return an iterator whose dereferenced
|
||||
* value is a @em pointer to a child tree node. For instance, if each node
|
||||
* tracks its children in an STL container of node* pointers, you can simply
|
||||
* return that container's begin() iterator.
|
||||
*
|
||||
* Alternatively, if a node tracks its children with a classic linked list,
|
||||
* write a functor returning LLLinkedIter<NODE>.
|
||||
*
|
||||
* The end() LLTreeDFSIter must, of course, match the begin() iterator's
|
||||
* template parameters, but is constructed without runtime parameters.
|
||||
*/
|
||||
template <class NODE, typename CHILDITER>
|
||||
class LLTreeDFSIter: public LLBaseIter<LLTreeDFSIter<NODE, CHILDITER>, NODE>
|
||||
{
|
||||
typedef LLBaseIter<LLTreeDFSIter<NODE, CHILDITER>, NODE> super;
|
||||
typedef typename super::self_type self_type;
|
||||
protected:
|
||||
typedef typename super::ptr_type ptr_type;
|
||||
// The func_type is different for this: from a NODE pointer, we must
|
||||
// obtain a CHILDITER.
|
||||
typedef boost::function<CHILDITER(const ptr_type&)> func_type;
|
||||
private:
|
||||
typedef std::vector<ptr_type> list_type;
|
||||
public:
|
||||
/// Instantiate an LLTreeDFSIter to start a depth-first walk. Pass
|
||||
/// functors to extract the 'child begin' and 'child end' iterators from
|
||||
/// each node.
|
||||
LLTreeDFSIter(const ptr_type& node, const func_type& beginfunc, const func_type& endfunc)
|
||||
: mBeginFunc(beginfunc),
|
||||
mEndFunc(endfunc),
|
||||
mSkipChildren(false)
|
||||
{
|
||||
// Only push back this node if it's non-NULL!
|
||||
if (node)
|
||||
mPending.push_back(node);
|
||||
}
|
||||
/// Instantiate an LLTreeDFSIter to mark the end of the walk
|
||||
LLTreeDFSIter() : mSkipChildren(false) {}
|
||||
|
||||
/// flags iterator logic to skip traversing children of current node on next increment
|
||||
void skipDescendants(bool skip = true) { mSkipChildren = skip; }
|
||||
|
||||
private:
|
||||
/// leverage boost::iterator_facade
|
||||
friend class boost::iterator_core_access;
|
||||
|
||||
/// advance
|
||||
/// This implementation is due to http://en.wikipedia.org/wiki/Depth-first_search
|
||||
void increment()
|
||||
{
|
||||
// Capture the node we were just looking at
|
||||
ptr_type current = mPending.back();
|
||||
// Remove it from mPending so we don't process it again later
|
||||
mPending.pop_back();
|
||||
if (!mSkipChildren)
|
||||
{
|
||||
// Add all its children to mPending
|
||||
addChildren(current);
|
||||
}
|
||||
// reset flag after each step
|
||||
mSkipChildren = false;
|
||||
}
|
||||
/// equality
|
||||
bool equal(const self_type& that) const { return this->mPending == that.mPending; }
|
||||
/// implement dereference/indirection operators
|
||||
ptr_type& dereference() const { return const_cast<ptr_type&>(mPending.back()); }
|
||||
|
||||
/// Add the direct children of the specified node to mPending
|
||||
void addChildren(const ptr_type& node)
|
||||
{
|
||||
// If we just use push_back() for each child in turn, we'll end up
|
||||
// processing children in reverse order. We don't want to assume
|
||||
// CHILDITER is reversible: some of the linked trees we'll be
|
||||
// processing manage their children using singly-linked lists. So
|
||||
// figure out how many children there are, grow mPending by that size
|
||||
// and reverse-copy the children into the new space.
|
||||
CHILDITER chi = mBeginFunc(node), chend = mEndFunc(node);
|
||||
// grow mPending by the number of children
|
||||
mPending.resize(mPending.size() + std::distance(chi, chend));
|
||||
// reverse-copy the children into the newly-expanded space
|
||||
std::copy(chi, chend, mPending.rbegin());
|
||||
}
|
||||
|
||||
/// list of the nodes yet to be processed
|
||||
list_type mPending;
|
||||
/// functor to extract begin() child iterator
|
||||
func_type mBeginFunc;
|
||||
/// functor to extract end() child iterator
|
||||
func_type mEndFunc;
|
||||
/// flag which controls traversal of children (skip children of current node if true)
|
||||
bool mSkipChildren;
|
||||
};
|
||||
|
||||
/**
|
||||
* Instantiated with a tree node, typically the root, LLTreeDFSPostIter
|
||||
* "flattens" a depth-first tree walk through that node and all its
|
||||
* descendants. Whereas LLTreeDFSIter visits each node before visiting any of
|
||||
* its children, LLTreeDFSPostIter visits all of a node's children before
|
||||
* visiting the node itself.
|
||||
*
|
||||
* The begin() LLTreeDFSPostIter must be instantiated with functors to obtain
|
||||
* from a given node begin() and end() iterators for that node's children. For
|
||||
* this reason, you must specify the type of the node's child iterator as an
|
||||
* additional template parameter.
|
||||
*
|
||||
* Specifically, the begin functor must return an iterator whose dereferenced
|
||||
* value is a @em pointer to a child tree node. For instance, if each node
|
||||
* tracks its children in an STL container of node* pointers, you can simply
|
||||
* return that container's begin() iterator.
|
||||
*
|
||||
* Alternatively, if a node tracks its children with a classic linked list,
|
||||
* write a functor returning LLLinkedIter<NODE>.
|
||||
*
|
||||
* The end() LLTreeDFSPostIter must, of course, match the begin() iterator's
|
||||
* template parameters, but is constructed without runtime parameters.
|
||||
*/
|
||||
template <class NODE, typename CHILDITER>
|
||||
class LLTreeDFSPostIter: public LLBaseIter<LLTreeDFSPostIter<NODE, CHILDITER>, NODE>
|
||||
{
|
||||
typedef LLBaseIter<LLTreeDFSPostIter<NODE, CHILDITER>, NODE> super;
|
||||
typedef typename super::self_type self_type;
|
||||
protected:
|
||||
typedef typename super::ptr_type ptr_type;
|
||||
// The func_type is different for this: from a NODE pointer, we must
|
||||
// obtain a CHILDITER.
|
||||
typedef boost::function<CHILDITER(const ptr_type&)> func_type;
|
||||
private:
|
||||
// Upon reaching a given node in our pending list, we need to know whether
|
||||
// we've already pushed that node's children, so we must associate a bool
|
||||
// with each node pointer.
|
||||
typedef std::vector< std::pair<ptr_type, bool> > list_type;
|
||||
public:
|
||||
/// Instantiate an LLTreeDFSPostIter to start a depth-first walk. Pass
|
||||
/// functors to extract the 'child begin' and 'child end' iterators from
|
||||
/// each node.
|
||||
LLTreeDFSPostIter(const ptr_type& node, const func_type& beginfunc, const func_type& endfunc)
|
||||
: mBeginFunc(beginfunc),
|
||||
mEndFunc(endfunc),
|
||||
mSkipAncestors(false)
|
||||
{
|
||||
if (! node)
|
||||
return;
|
||||
mPending.push_back(typename list_type::value_type(node, false));
|
||||
makeCurrent();
|
||||
}
|
||||
/// Instantiate an LLTreeDFSPostIter to mark the end of the walk
|
||||
LLTreeDFSPostIter() : mSkipAncestors(false) {}
|
||||
|
||||
/// flags iterator logic to skip traversing ancestors of current node on next increment
|
||||
void skipAncestors(bool skip = true) { mSkipAncestors = skip; }
|
||||
|
||||
private:
|
||||
/// leverage boost::iterator_facade
|
||||
friend class boost::iterator_core_access;
|
||||
|
||||
/// advance
|
||||
/// This implementation is due to http://en.wikipedia.org/wiki/Depth-first_search
|
||||
void increment()
|
||||
{
|
||||
// Pop the previous current node
|
||||
mPending.pop_back();
|
||||
makeCurrent();
|
||||
}
|
||||
/// equality
|
||||
bool equal(const self_type& that) const { return this->mPending == that.mPending; }
|
||||
/// implement dereference/indirection operators
|
||||
ptr_type& dereference() const { return const_cast<ptr_type&>(mPending.back().first); }
|
||||
|
||||
struct isOpen
|
||||
{
|
||||
bool operator()(const typename list_type::value_type& item)
|
||||
{
|
||||
return item.second;
|
||||
}
|
||||
};
|
||||
|
||||
/// Call this each time we change mPending.back() -- that is, every time
|
||||
/// we're about to change the value returned by dereference(). If we
|
||||
/// haven't yet pushed the new node's children, do so now.
|
||||
void makeCurrent()
|
||||
{
|
||||
if (mSkipAncestors)
|
||||
{
|
||||
mPending.erase(std::remove_if(mPending.begin(), mPending.end(), isOpen()), mPending.end());
|
||||
mSkipAncestors = false;
|
||||
}
|
||||
|
||||
// Once we've popped the last node, this becomes a no-op.
|
||||
if (mPending.empty())
|
||||
return;
|
||||
// Here mPending.back() holds the node pointer we're proposing to
|
||||
// dereference next. Have we pushed that node's children yet?
|
||||
if (mPending.back().second)
|
||||
return; // if so, it's okay to visit this node now
|
||||
// We haven't yet pushed this node's children. Do so now. Remember
|
||||
// that we did -- while the node in question is still back().
|
||||
mPending.back().second = true;
|
||||
addChildren(mPending.back().first);
|
||||
// Now, because we've just changed mPending.back(), make that new node
|
||||
// current.
|
||||
makeCurrent();
|
||||
}
|
||||
|
||||
/// Add the direct children of the specified node to mPending
|
||||
void addChildren(const ptr_type& node)
|
||||
{
|
||||
// If we just use push_back() for each child in turn, we'll end up
|
||||
// processing children in reverse order. We don't want to assume
|
||||
// CHILDITER is reversible: some of the linked trees we'll be
|
||||
// processing manage their children using singly-linked lists. So
|
||||
// figure out how many children there are, grow mPending by that size
|
||||
// and reverse-copy the children into the new space.
|
||||
CHILDITER chi = mBeginFunc(node), chend = mEndFunc(node);
|
||||
// grow mPending by the number of children
|
||||
mPending.resize(mPending.size() + std::distance(chi, chend));
|
||||
// Reverse-copy the children into the newly-expanded space. We can't
|
||||
// just use std::copy() because the source is a ptr_type, whereas the
|
||||
// dest is a pair of (ptr_type, bool).
|
||||
for (typename list_type::reverse_iterator pi = mPending.rbegin(); chi != chend; ++chi, ++pi)
|
||||
{
|
||||
pi->first = *chi; // copy the child pointer
|
||||
pi->second = false; // we haven't yet pushed this child's chldren
|
||||
}
|
||||
}
|
||||
|
||||
/// list of the nodes yet to be processed
|
||||
list_type mPending;
|
||||
/// functor to extract begin() child iterator
|
||||
func_type mBeginFunc;
|
||||
/// functor to extract end() child iterator
|
||||
func_type mEndFunc;
|
||||
/// flags logic to skip traversal of ancestors of current node
|
||||
bool mSkipAncestors;
|
||||
};
|
||||
|
||||
/**
|
||||
* Instantiated with a tree node, typically the root, LLTreeBFSIter "flattens"
|
||||
* a breadth-first tree walk through that node and all its descendants.
|
||||
*
|
||||
* The begin() LLTreeBFSIter must be instantiated with functors to obtain from
|
||||
* a given node the begin() and end() iterators of that node's children. For
|
||||
* this reason, you must specify the type of the node's child iterator as an
|
||||
* additional template parameter.
|
||||
*
|
||||
* Specifically, the begin functor must return an iterator whose dereferenced
|
||||
* value is a @em pointer to a child tree node. For instance, if each node
|
||||
* tracks its children in an STL container of node* pointers, you can simply
|
||||
* return that container's begin() iterator.
|
||||
*
|
||||
* Alternatively, if a node tracks its children with a classic linked list,
|
||||
* write a functor returning LLLinkedIter<NODE>.
|
||||
*
|
||||
* The end() LLTreeBFSIter must, of course, match the begin() iterator's
|
||||
* template parameters, but is constructed without runtime parameters.
|
||||
*/
|
||||
template <class NODE, typename CHILDITER>
|
||||
class LLTreeBFSIter: public LLBaseIter<LLTreeBFSIter<NODE, CHILDITER>, NODE>
|
||||
{
|
||||
typedef LLBaseIter<LLTreeBFSIter<NODE, CHILDITER>, NODE> super;
|
||||
typedef typename super::self_type self_type;
|
||||
protected:
|
||||
typedef typename super::ptr_type ptr_type;
|
||||
// The func_type is different for this: from a NODE pointer, we must
|
||||
// obtain a CHILDITER.
|
||||
typedef boost::function<CHILDITER(const ptr_type&)> func_type;
|
||||
private:
|
||||
// We need a FIFO queue rather than a LIFO stack. Use a deque rather than
|
||||
// a vector, since vector can't implement pop_front() efficiently.
|
||||
typedef std::deque<ptr_type> list_type;
|
||||
public:
|
||||
/// Instantiate an LLTreeBFSIter to start a depth-first walk. Pass
|
||||
/// functors to extract the 'child begin' and 'child end' iterators from
|
||||
/// each node.
|
||||
LLTreeBFSIter(const ptr_type& node, const func_type& beginfunc, const func_type& endfunc):
|
||||
mBeginFunc(beginfunc),
|
||||
mEndFunc(endfunc)
|
||||
{
|
||||
if (node)
|
||||
mPending.push_back(node);
|
||||
}
|
||||
/// Instantiate an LLTreeBFSIter to mark the end of the walk
|
||||
LLTreeBFSIter() {}
|
||||
|
||||
private:
|
||||
/// leverage boost::iterator_facade
|
||||
friend class boost::iterator_core_access;
|
||||
|
||||
/// advance
|
||||
/// This implementation is due to http://en.wikipedia.org/wiki/Breadth-first_search
|
||||
void increment()
|
||||
{
|
||||
// Capture the node we were just looking at
|
||||
ptr_type current = mPending.front();
|
||||
// Remove it from mPending so we don't process it again later
|
||||
mPending.pop_front();
|
||||
// Add all its children to mPending
|
||||
CHILDITER chend = mEndFunc(current);
|
||||
for (CHILDITER chi = mBeginFunc(current); chi != chend; ++chi)
|
||||
mPending.push_back(*chi);
|
||||
}
|
||||
/// equality
|
||||
bool equal(const self_type& that) const { return this->mPending == that.mPending; }
|
||||
/// implement dereference/indirection operators
|
||||
ptr_type& dereference() const { return const_cast<ptr_type&>(mPending.front()); }
|
||||
|
||||
/// list of the nodes yet to be processed
|
||||
list_type mPending;
|
||||
/// functor to extract begin() child iterator
|
||||
func_type mBeginFunc;
|
||||
/// functor to extract end() child iterator
|
||||
func_type mEndFunc;
|
||||
};
|
||||
|
||||
/**
|
||||
* When you want to select between LLTreeDFSIter, LLTreeDFSPostIter and
|
||||
* LLTreeBFSIter with a compile-time discriminator, use LLTreeWalkIter with an
|
||||
* LLTreeIter::WalkIter template arg.
|
||||
*/
|
||||
template <LLTreeIter::WalkIter DISCRIM, class NODE, typename CHILDITER>
|
||||
class LLTreeWalkIter
|
||||
{
|
||||
enum { use_a_valid_LLTreeIter_WalkIter_value = false };
|
||||
public:
|
||||
/// Bogus constructors for default (unrecognized discriminator) case
|
||||
template <typename TYPE1, typename TYPE2>
|
||||
LLTreeWalkIter(TYPE1, TYPE2)
|
||||
{
|
||||
BOOST_STATIC_ASSERT(use_a_valid_LLTreeIter_WalkIter_value);
|
||||
}
|
||||
LLTreeWalkIter()
|
||||
{
|
||||
BOOST_STATIC_ASSERT(use_a_valid_LLTreeIter_WalkIter_value);
|
||||
}
|
||||
};
|
||||
|
||||
/// Specialize for LLTreeIter::DFS_PRE
|
||||
template <class NODE, typename CHILDITER>
|
||||
class LLTreeWalkIter<LLTreeIter::DFS_PRE, NODE, CHILDITER>:
|
||||
public LLTreeDFSIter<NODE, CHILDITER>
|
||||
{
|
||||
typedef LLTreeDFSIter<NODE, CHILDITER> super;
|
||||
public:
|
||||
/// forward begin ctor
|
||||
LLTreeWalkIter(const typename super::ptr_type& node,
|
||||
const typename super::func_type& beginfunc,
|
||||
const typename super::func_type& endfunc):
|
||||
super(node, beginfunc, endfunc)
|
||||
{}
|
||||
/// forward end ctor
|
||||
LLTreeWalkIter():
|
||||
super()
|
||||
{}
|
||||
};
|
||||
|
||||
/// Specialize for LLTreeIter::DFS_POST
|
||||
template <class NODE, typename CHILDITER>
|
||||
class LLTreeWalkIter<LLTreeIter::DFS_POST, NODE, CHILDITER>:
|
||||
public LLTreeDFSPostIter<NODE, CHILDITER>
|
||||
{
|
||||
typedef LLTreeDFSPostIter<NODE, CHILDITER> super;
|
||||
public:
|
||||
/// forward begin ctor
|
||||
LLTreeWalkIter(const typename super::ptr_type& node,
|
||||
const typename super::func_type& beginfunc,
|
||||
const typename super::func_type& endfunc):
|
||||
super(node, beginfunc, endfunc)
|
||||
{}
|
||||
/// forward end ctor
|
||||
LLTreeWalkIter():
|
||||
super()
|
||||
{}
|
||||
};
|
||||
|
||||
/// Specialize for LLTreeIter::BFS
|
||||
template <class NODE, typename CHILDITER>
|
||||
class LLTreeWalkIter<LLTreeIter::BFS, NODE, CHILDITER>:
|
||||
public LLTreeBFSIter<NODE, CHILDITER>
|
||||
{
|
||||
typedef LLTreeBFSIter<NODE, CHILDITER> super;
|
||||
public:
|
||||
/// forward begin ctor
|
||||
LLTreeWalkIter(const typename super::ptr_type& node,
|
||||
const typename super::func_type& beginfunc,
|
||||
const typename super::func_type& endfunc):
|
||||
super(node, beginfunc, endfunc)
|
||||
{}
|
||||
/// forward end ctor
|
||||
LLTreeWalkIter():
|
||||
super()
|
||||
{}
|
||||
};
|
||||
|
||||
#endif /* ! defined(LL_LLTREEITERATORS_H) */
|
||||
@@ -202,9 +202,9 @@ void LLWorkerThread::WorkRequest::finishRequest(bool completed)
|
||||
|
||||
LLWorkerClass::LLWorkerClass(LLWorkerThread* workerthread, const std::string& name)
|
||||
: mWorkerThread(workerthread),
|
||||
mRequestPriority(LLWorkerThread::PRIORITY_NORMAL),
|
||||
mWorkerClassName(name),
|
||||
mRequestHandle(LLWorkerThread::nullHandle()),
|
||||
mRequestPriority(LLWorkerThread::PRIORITY_NORMAL),
|
||||
mWorkFlags(0)
|
||||
{
|
||||
if (!mWorkerThread)
|
||||
|
||||
@@ -109,6 +109,7 @@ const U64 GP_LAND_ALLOW_FLY = 0x1 << 24; // Bypass Fly Restriction
|
||||
const U64 GP_LAND_ALLOW_CREATE = 0x1 << 25; // Bypass Create/Edit Objects Restriction
|
||||
const U64 GP_LAND_ALLOW_LANDMARK = 0x1 << 26; // Bypass Landmark Restriction
|
||||
const U64 GP_LAND_ALLOW_SET_HOME = 0x1 << 28; // Bypass Set Home Point Restriction
|
||||
const U64 GP_LAND_ALLOW_HOLD_EVENT = 0x1LL << 41; // Allowed to hold events on group-owned land
|
||||
|
||||
// Parcel Access
|
||||
const U64 GP_LAND_MANAGE_ALLOWED = 0x1 << 29; // Manage Allowed List
|
||||
|
||||
107
indra/llcommon/stringize.h
Normal file
107
indra/llcommon/stringize.h
Normal file
@@ -0,0 +1,107 @@
|
||||
/**
|
||||
* @file stringize.h
|
||||
* @author Nat Goodspeed
|
||||
* @date 2008-12-17
|
||||
* @brief stringize(item) template function and STRINGIZE(expression) macro
|
||||
*
|
||||
* $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$
|
||||
*/
|
||||
|
||||
#if ! defined(LL_STRINGIZE_H)
|
||||
#define LL_STRINGIZE_H
|
||||
|
||||
#include <sstream>
|
||||
#include <boost/lambda/lambda.hpp>
|
||||
|
||||
/**
|
||||
* stringize(item) encapsulates an idiom we use constantly, using
|
||||
* operator<<(std::ostringstream&, TYPE) followed by std::ostringstream::str()
|
||||
* to render a string expressing some item.
|
||||
*/
|
||||
template <typename T>
|
||||
std::string stringize(const T& item)
|
||||
{
|
||||
std::ostringstream out;
|
||||
out << item;
|
||||
return out.str();
|
||||
}
|
||||
|
||||
/**
|
||||
* stringize_f(functor)
|
||||
*/
|
||||
template <typename Functor>
|
||||
std::string stringize_f(Functor const & f)
|
||||
{
|
||||
std::ostringstream out;
|
||||
f(out);
|
||||
return out.str();
|
||||
}
|
||||
|
||||
/**
|
||||
* STRINGIZE(item1 << item2 << item3 ...) effectively expands to the
|
||||
* following:
|
||||
* @code
|
||||
* std::ostringstream out;
|
||||
* out << item1 << item2 << item3 ... ;
|
||||
* return out.str();
|
||||
* @endcode
|
||||
*/
|
||||
#define STRINGIZE(EXPRESSION) (stringize_f(boost::lambda::_1 << EXPRESSION))
|
||||
|
||||
|
||||
/**
|
||||
* destringize(str)
|
||||
* defined for symmetry with stringize
|
||||
* *NOTE - this has distinct behavior from boost::lexical_cast<T> regarding
|
||||
* leading/trailing whitespace and handling of bad_lexical_cast exceptions
|
||||
*/
|
||||
template <typename T>
|
||||
T destringize(std::string const & str)
|
||||
{
|
||||
T val;
|
||||
std::istringstream in(str);
|
||||
in >> val;
|
||||
return val;
|
||||
}
|
||||
|
||||
/**
|
||||
* destringize_f(str, functor)
|
||||
*/
|
||||
template <typename Functor>
|
||||
void destringize_f(std::string const & str, Functor const & f)
|
||||
{
|
||||
std::istringstream in(str);
|
||||
f(in);
|
||||
}
|
||||
|
||||
/**
|
||||
* DESTRINGIZE(str, item1 >> item2 >> item3 ...) effectively expands to the
|
||||
* following:
|
||||
* @code
|
||||
* std::istringstream in(str);
|
||||
* in >> item1 >> item2 >> item3 ... ;
|
||||
* @endcode
|
||||
*/
|
||||
#define DESTRINGIZE(STR, EXPRESSION) (destringize_f((STR), (boost::lambda::_1 >> EXPRESSION)))
|
||||
|
||||
|
||||
#endif /* ! defined(LL_STRINGIZE_H) */
|
||||
@@ -89,7 +89,8 @@ LLCrashLogger::LLCrashLogger() :
|
||||
mCrashBehavior(CRASH_BEHAVIOR_ASK),
|
||||
mCrashInPreviousExec(false),
|
||||
mSentCrashLogs(false),
|
||||
mCrashHost("")
|
||||
mCrashHost(""),
|
||||
mCrashSettings("CrashSettings")
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@@ -138,8 +138,7 @@ void LLImageBase::sanityCheck()
|
||||
// virtual
|
||||
void LLImageBase::deleteData()
|
||||
{
|
||||
if(mData)
|
||||
delete[] mData;
|
||||
delete[] mData;
|
||||
mData = NULL;
|
||||
mDataSize = 0;
|
||||
}
|
||||
@@ -154,7 +153,7 @@ U8* LLImageBase::allocateData(S32 size)
|
||||
size = mWidth * mHeight * mComponents;
|
||||
if (size <= 0)
|
||||
{
|
||||
llerrs << llformat("LLImageBase::allocateData called with bad dimensions: %dx%dx%d",mWidth,mHeight,mComponents) << llendl;
|
||||
llerrs << llformat("LLImageBase::allocateData called with bad dimensions: %dx%dx%d",mWidth,mHeight,(S32)mComponents) << llendl;
|
||||
}
|
||||
}
|
||||
else if (size <= 0 || (size > 4096*4096*16 && !mAllowOverSize))
|
||||
@@ -1299,28 +1298,7 @@ bool LLImageRaw::createFromFile(const std::string &filename, bool j2c_lowest_mip
|
||||
return false;
|
||||
}
|
||||
|
||||
LLPointer<LLImageFormatted> image;
|
||||
switch(codec)
|
||||
{
|
||||
//case IMG_CODEC_RGB:
|
||||
case IMG_CODEC_BMP:
|
||||
image = new LLImageBMP();
|
||||
break;
|
||||
case IMG_CODEC_TGA:
|
||||
image = new LLImageTGA();
|
||||
break;
|
||||
case IMG_CODEC_JPEG:
|
||||
image = new LLImageJPEG();
|
||||
break;
|
||||
case IMG_CODEC_J2C:
|
||||
image = new LLImageJ2C();
|
||||
break;
|
||||
case IMG_CODEC_DXT:
|
||||
image = new LLImageDXT();
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
LLPointer<LLImageFormatted> image = LLImageFormatted::createFromType(codec);
|
||||
llassert(image.notNull());
|
||||
|
||||
U8 *buffer = image->allocateData(length);
|
||||
@@ -1602,8 +1580,7 @@ BOOL LLImageFormatted::load(const std::string &filename)
|
||||
resetLastError();
|
||||
|
||||
S32 file_size = 0;
|
||||
LLAPRFile infile ;
|
||||
infile.open(filename, LL_APR_RB, LLAPRFile::global, &file_size);
|
||||
LLAPRFile infile(filename, LL_APR_RB, &file_size);
|
||||
apr_file_t* apr_file = infile.getFileHandle();
|
||||
if (!apr_file)
|
||||
{
|
||||
@@ -1638,8 +1615,7 @@ BOOL LLImageFormatted::save(const std::string &filename)
|
||||
{
|
||||
resetLastError();
|
||||
|
||||
LLAPRFile outfile ;
|
||||
outfile.open(filename, LL_APR_WB, LLAPRFile::global);
|
||||
LLAPRFile outfile(filename, LL_APR_WB);
|
||||
if (!outfile.getFileHandle())
|
||||
{
|
||||
setLastError("Unable to open file for writing", filename);
|
||||
|
||||
@@ -47,7 +47,7 @@ typedef const char* (*EngineInfoLLImageJ2CFunction)();
|
||||
CreateLLImageJ2CFunction j2cimpl_create_func;
|
||||
DestroyLLImageJ2CFunction j2cimpl_destroy_func;
|
||||
EngineInfoLLImageJ2CFunction j2cimpl_engineinfo_func;
|
||||
AIAPRPool j2cimpl_dso_memory_pool;
|
||||
LLAPRPool j2cimpl_dso_memory_pool;
|
||||
apr_dso_handle_t *j2cimpl_dso_handle;
|
||||
|
||||
//Declare the prototype for theses functions here, their functionality
|
||||
@@ -473,8 +473,7 @@ BOOL LLImageJ2C::loadAndValidate(const std::string &filename)
|
||||
resetLastError();
|
||||
|
||||
S32 file_size = 0;
|
||||
LLAPRFile infile ;
|
||||
infile.open(filename, LL_APR_RB, LLAPRFile::global, &file_size);
|
||||
LLAPRFile infile(filename, LL_APR_RB, &file_size);
|
||||
apr_file_t* apr_file = infile.getFileHandle() ;
|
||||
if (!apr_file)
|
||||
{
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
#ifndef LL_LLECONOMY_H
|
||||
#define LL_LLECONOMY_H
|
||||
|
||||
#include "llmemory.h"
|
||||
#include "llsingleton.h"
|
||||
|
||||
class LLMessageSystem;
|
||||
class LLVector3;
|
||||
|
||||
@@ -31,10 +31,10 @@
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "llinventory.h"
|
||||
|
||||
#include "lldbstrings.h"
|
||||
#include "llinventorydefines.h"
|
||||
#include "llxorcipher.h"
|
||||
#include "llsd.h"
|
||||
#include "message.h"
|
||||
@@ -1120,7 +1120,7 @@ bool LLInventoryItem::fromLLSD(const LLSD& sd)
|
||||
{
|
||||
if (sd[w].isString())
|
||||
{
|
||||
mType = LLAssetType::lookup(sd[w].asString().c_str());
|
||||
mType = LLAssetType::lookup(sd[w].asString());
|
||||
}
|
||||
else if (sd[w].isInteger())
|
||||
{
|
||||
@@ -1425,26 +1425,13 @@ void LLInventoryItem::unpackBinaryBucket(U8* bin_bucket, S32 bin_bucket_size)
|
||||
setCreationDate(now);
|
||||
}
|
||||
|
||||
// returns TRUE if a should appear before b
|
||||
BOOL item_dictionary_sort( LLInventoryItem* a, LLInventoryItem* b )
|
||||
{
|
||||
return (LLStringUtil::compareDict( a->getName().c_str(), b->getName().c_str() ) < 0);
|
||||
}
|
||||
|
||||
// returns TRUE if a should appear before b
|
||||
BOOL item_date_sort( LLInventoryItem* a, LLInventoryItem* b )
|
||||
{
|
||||
return a->getCreationDate() < b->getCreationDate();
|
||||
}
|
||||
|
||||
|
||||
///----------------------------------------------------------------------------
|
||||
/// Class LLInventoryCategory
|
||||
///----------------------------------------------------------------------------
|
||||
|
||||
LLInventoryCategory::LLInventoryCategory(const LLUUID& uuid,
|
||||
const LLUUID& parent_uuid,
|
||||
LLAssetType::EType preferred_type,
|
||||
LLFolderType::EType preferred_type,
|
||||
const std::string& name) :
|
||||
LLInventoryObject(uuid, parent_uuid, LLAssetType::AT_CATEGORY, name),
|
||||
mPreferredType(preferred_type)
|
||||
@@ -1452,7 +1439,7 @@ LLInventoryCategory::LLInventoryCategory(const LLUUID& uuid,
|
||||
}
|
||||
|
||||
LLInventoryCategory::LLInventoryCategory() :
|
||||
mPreferredType(LLAssetType::AT_NONE)
|
||||
mPreferredType(LLFolderType::FT_NONE)
|
||||
{
|
||||
mType = LLAssetType::AT_CATEGORY;
|
||||
}
|
||||
@@ -1474,12 +1461,12 @@ void LLInventoryCategory::copyCategory(const LLInventoryCategory* other)
|
||||
mPreferredType = other->mPreferredType;
|
||||
}
|
||||
|
||||
LLAssetType::EType LLInventoryCategory::getPreferredType() const
|
||||
LLFolderType::EType LLInventoryCategory::getPreferredType() const
|
||||
{
|
||||
return mPreferredType;
|
||||
}
|
||||
|
||||
void LLInventoryCategory::setPreferredType(LLAssetType::EType type)
|
||||
void LLInventoryCategory::setPreferredType(LLFolderType::EType type)
|
||||
{
|
||||
mPreferredType = type;
|
||||
}
|
||||
@@ -1525,13 +1512,13 @@ bool LLInventoryCategory::fromLLSD(const LLSD& sd)
|
||||
if (sd.has(w))
|
||||
{
|
||||
S8 type = (U8)sd[w].asInteger();
|
||||
mPreferredType = static_cast<LLAssetType::EType>(type);
|
||||
mPreferredType = static_cast<LLFolderType::EType>(type);
|
||||
}
|
||||
w = INV_ASSET_TYPE_LABEL_WS;
|
||||
if (sd.has(w))
|
||||
{
|
||||
S8 type = (U8)sd[w].asInteger();
|
||||
mPreferredType = static_cast<LLAssetType::EType>(type);
|
||||
mPreferredType = static_cast<LLFolderType::EType>(type);
|
||||
}
|
||||
|
||||
w = INV_NAME_LABEL;
|
||||
@@ -1553,7 +1540,7 @@ void LLInventoryCategory::unpackMessage(LLMessageSystem* msg,
|
||||
msg->getUUIDFast(block, _PREHASH_ParentID, mParentUUID, block_num);
|
||||
S8 type;
|
||||
msg->getS8Fast(block, _PREHASH_Type, type, block_num);
|
||||
mPreferredType = static_cast<LLAssetType::EType>(type);
|
||||
mPreferredType = static_cast<LLFolderType::EType>(type);
|
||||
msg->getStringFast(block, _PREHASH_Name, mName, block_num);
|
||||
LLStringUtil::replaceNonstandardASCII(mName, ' ');
|
||||
}
|
||||
@@ -1602,7 +1589,7 @@ BOOL LLInventoryCategory::importFile(LLFILE* fp)
|
||||
}
|
||||
else if(0 == strcmp("pref_type", keyword))
|
||||
{
|
||||
mPreferredType = LLAssetType::lookup(valuestr);
|
||||
mPreferredType = LLFolderType::lookup(valuestr);
|
||||
}
|
||||
else if(0 == strcmp("name", keyword))
|
||||
{
|
||||
@@ -1634,7 +1621,7 @@ BOOL LLInventoryCategory::exportFile(LLFILE* fp, BOOL) const
|
||||
mParentUUID.toString(uuid_str);
|
||||
fprintf(fp, "\t\tparent_id\t%s\n", uuid_str.c_str());
|
||||
fprintf(fp, "\t\ttype\t%s\n", LLAssetType::lookup(mType));
|
||||
fprintf(fp, "\t\tpref_type\t%s\n", LLAssetType::lookup(mPreferredType));
|
||||
fprintf(fp, "\t\tpref_type\t%s\n", LLFolderType::lookup(mPreferredType).c_str());
|
||||
fprintf(fp, "\t\tname\t%s|\n", mName.c_str());
|
||||
fprintf(fp,"\t}\n");
|
||||
return TRUE;
|
||||
@@ -1681,7 +1668,7 @@ BOOL LLInventoryCategory::importLegacyStream(std::istream& input_stream)
|
||||
}
|
||||
else if(0 == strcmp("pref_type", keyword))
|
||||
{
|
||||
mPreferredType = LLAssetType::lookup(valuestr);
|
||||
mPreferredType = LLFolderType::lookup(valuestr);
|
||||
}
|
||||
else if(0 == strcmp("name", keyword))
|
||||
{
|
||||
@@ -1713,7 +1700,7 @@ BOOL LLInventoryCategory::exportLegacyStream(std::ostream& output_stream, BOOL)
|
||||
mParentUUID.toString(uuid_str);
|
||||
output_stream << "\t\tparent_id\t" << uuid_str << "\n";
|
||||
output_stream << "\t\ttype\t" << LLAssetType::lookup(mType) << "\n";
|
||||
output_stream << "\t\tpref_type\t" << LLAssetType::lookup(mPreferredType) << "\n";
|
||||
output_stream << "\t\tpref_type\t" << LLFolderType::lookup(mPreferredType) << "\n";
|
||||
output_stream << "\t\tname\t" << mName.c_str() << "|\n";
|
||||
output_stream << "\t}\n";
|
||||
return TRUE;
|
||||
@@ -1793,10 +1780,10 @@ LLSD ll_create_sd_from_inventory_category(LLPointer<LLInventoryCategory> cat)
|
||||
rv[INV_PARENT_ID_LABEL] = cat->getParentUUID();
|
||||
rv[INV_NAME_LABEL] = cat->getName();
|
||||
rv[INV_ASSET_TYPE_LABEL] = LLAssetType::lookup(cat->getType());
|
||||
if(LLAssetType::AT_NONE != cat->getPreferredType())
|
||||
if(LLFolderType::lookupIsProtectedType(cat->getPreferredType()))
|
||||
{
|
||||
rv[INV_PREFERRED_TYPE_LABEL] =
|
||||
LLAssetType::lookup(cat->getPreferredType());
|
||||
LLFolderType::lookup(cat->getPreferredType()).c_str();
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
@@ -1810,7 +1797,7 @@ LLPointer<LLInventoryCategory> ll_create_category_from_sd(const LLSD& sd_cat)
|
||||
rv->setType(
|
||||
LLAssetType::lookup(sd_cat[INV_ASSET_TYPE_LABEL].asString()));
|
||||
rv->setPreferredType(
|
||||
LLAssetType::lookup(
|
||||
LLFolderType::lookup(
|
||||
sd_cat[INV_PREFERRED_TYPE_LABEL].asString()));
|
||||
return rv;
|
||||
}
|
||||
|
||||
@@ -33,12 +33,12 @@
|
||||
#ifndef LL_LLINVENTORY_H
|
||||
#define LL_LLINVENTORY_H
|
||||
|
||||
#include "llassetstorage.h"
|
||||
#include "lldarray.h"
|
||||
#include "llfoldertype.h"
|
||||
#include "llinventorytype.h"
|
||||
#include "llinventorydefines.h"
|
||||
#include "llmemtype.h"
|
||||
#include "llpermissions.h"
|
||||
#include "llrefcount.h"
|
||||
#include "llsaleinfo.h"
|
||||
#include "llsd.h"
|
||||
#include "lluuid.h"
|
||||
@@ -242,10 +242,6 @@ protected:
|
||||
time_t mCreationDate; // seconds from 1/1/1970, UTC
|
||||
};
|
||||
|
||||
BOOL item_dictionary_sort(LLInventoryItem* a,LLInventoryItem* b);
|
||||
BOOL item_date_sort(LLInventoryItem* a, LLInventoryItem* b);
|
||||
|
||||
|
||||
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Class LLInventoryCategory
|
||||
//
|
||||
@@ -265,7 +261,7 @@ public:
|
||||
public:
|
||||
MEM_TYPE_NEW(LLMemType::MTYPE_INVENTORY);
|
||||
LLInventoryCategory(const LLUUID& uuid, const LLUUID& parent_uuid,
|
||||
LLAssetType::EType preferred_type,
|
||||
LLFolderType::EType preferred_type,
|
||||
const std::string& name);
|
||||
LLInventoryCategory();
|
||||
LLInventoryCategory(const LLInventoryCategory* other);
|
||||
@@ -277,8 +273,8 @@ protected:
|
||||
// Accessors And Mutators
|
||||
//--------------------------------------------------------------------
|
||||
public:
|
||||
LLAssetType::EType getPreferredType() const;
|
||||
void setPreferredType(LLAssetType::EType type);
|
||||
LLFolderType::EType getPreferredType() const;
|
||||
void setPreferredType(LLFolderType::EType type);
|
||||
LLSD asLLSD() const;
|
||||
bool fromLLSD(const LLSD& sd);
|
||||
|
||||
@@ -302,91 +298,16 @@ public:
|
||||
// Member Variables
|
||||
//--------------------------------------------------------------------
|
||||
protected:
|
||||
LLAssetType::EType mPreferredType; // Type that this category was "meant" to hold (although it may hold any type).
|
||||
LLFolderType::EType mPreferredType; // Type that this category was "meant" to hold (although it may hold any type).
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Useful bits
|
||||
// Convertors
|
||||
//
|
||||
// These functions convert between structured data and an inventory
|
||||
// item, appropriate for serialization.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// This functor tests if an item is transferrable and returns true if
|
||||
// it is. Derived from unary_function<> so that the object can be used
|
||||
// in stl-compliant adaptable predicates (eg, not1<>). You might want
|
||||
// to use this in std::partition() or similar logic.
|
||||
struct IsItemTransferable : public std::unary_function<LLInventoryItem*, bool>
|
||||
{
|
||||
LLUUID mDestID;
|
||||
IsItemTransferable(const LLUUID& dest_id) : mDestID(dest_id) {}
|
||||
bool operator()(const LLInventoryItem* item) const
|
||||
{
|
||||
return (item->getPermissions().allowTransferTo(mDestID)) ? true:false;
|
||||
}
|
||||
};
|
||||
|
||||
// This functor is used to set the owner and group of inventory items,
|
||||
// for example, in a simple std::for_each() loop. Note that the call
|
||||
// to setOwnerAndGroup can fail if authority_id != LLUUID::null.
|
||||
struct SetItemOwnerAndGroup
|
||||
{
|
||||
LLUUID mAuthorityID;
|
||||
LLUUID mOwnerID;
|
||||
LLUUID mGroupID;
|
||||
SetItemOwnerAndGroup(const LLUUID& authority_id,
|
||||
const LLUUID& owner_id,
|
||||
const LLUUID& group_id) :
|
||||
mAuthorityID(authority_id), mOwnerID(owner_id), mGroupID(group_id) {}
|
||||
void operator()(LLInventoryItem* item) const
|
||||
{
|
||||
LLPermissions perm = item->getPermissions();
|
||||
bool is_atomic = (LLAssetType::AT_OBJECT == item->getType()) ? false : true;
|
||||
perm.setOwnerAndGroup(mAuthorityID, mOwnerID, mGroupID, is_atomic);
|
||||
// If no owner id is set, this is equivalent to a deed action.
|
||||
// Clear 'share with group'.
|
||||
if (mOwnerID.isNull())
|
||||
{
|
||||
perm.setMaskGroup(PERM_NONE);
|
||||
}
|
||||
item->setPermissions(perm);
|
||||
}
|
||||
};
|
||||
|
||||
// This functor is used to unset the share with group, everyone perms, and
|
||||
// for sale info for objects being sold through contents.
|
||||
struct SetNotForSale
|
||||
{
|
||||
LLUUID mAgentID;
|
||||
LLUUID mGroupID;
|
||||
SetNotForSale(const LLUUID& agent_id,
|
||||
const LLUUID& group_id) :
|
||||
mAgentID(agent_id), mGroupID(group_id) {}
|
||||
void operator()(LLInventoryItem* item) const
|
||||
{
|
||||
// Clear group & everyone permissions.
|
||||
LLPermissions perm = item->getPermissions();
|
||||
perm.setGroupBits(mAgentID, mGroupID, FALSE, PERM_MODIFY | PERM_MOVE | PERM_COPY);
|
||||
perm.setEveryoneBits(mAgentID, mGroupID, FALSE, PERM_MOVE | PERM_COPY);
|
||||
item->setPermissions(perm);
|
||||
|
||||
// Mark group & everyone permissions for overwrite on the next
|
||||
// rez if it is an object.
|
||||
if(LLAssetType::AT_OBJECT == item->getType())
|
||||
{
|
||||
U32 flags = item->getFlags();
|
||||
flags |= LLInventoryItemFlags::II_FLAGS_OBJECT_PERM_OVERWRITE_GROUP;
|
||||
flags |= LLInventoryItemFlags::II_FLAGS_OBJECT_PERM_OVERWRITE_EVERYONE;
|
||||
item->setFlags(flags);
|
||||
}
|
||||
|
||||
// Clear for sale info.
|
||||
item->setSaleInfo(LLSaleInfo::DEFAULT);
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::list<LLPointer<LLInventoryObject> > InventoryObjectList;
|
||||
|
||||
// These functions convert between structured data and an inventroy
|
||||
// item, appropriate for serialization.
|
||||
LLSD ll_create_sd_from_inventory_item(LLPointer<LLInventoryItem> item);
|
||||
LLPointer<LLInventoryItem> ll_create_item_from_sd(const LLSD& sd_item);
|
||||
LLSD ll_create_sd_from_inventory_category(LLPointer<LLInventoryCategory> cat);
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "llinventorytype.h"
|
||||
#include "lldictionary.h"
|
||||
#include "llmemory.h"
|
||||
#include "llsingleton.h"
|
||||
|
||||
static const std::string empty_string;
|
||||
|
||||
@@ -122,7 +123,7 @@ DEFAULT_ASSET_FOR_INV_TYPE[LLAssetType::AT_COUNT] =
|
||||
LLInventoryType::IT_NONE, // AT_FAVORITE
|
||||
LLInventoryType::IT_NONE, // AT_LINK
|
||||
LLInventoryType::IT_NONE, // AT_LINK_FOLDER
|
||||
LLInventoryType::IT_NONE, // FT_ENSEMBLE_START
|
||||
/*LLInventoryType::IT_NONE, // FT_ENSEMBLE_START
|
||||
LLInventoryType::IT_NONE, //
|
||||
LLInventoryType::IT_NONE, //
|
||||
LLInventoryType::IT_NONE, //
|
||||
@@ -144,7 +145,7 @@ DEFAULT_ASSET_FOR_INV_TYPE[LLAssetType::AT_COUNT] =
|
||||
LLInventoryType::IT_NONE, // FT_ENSEMBLE_END
|
||||
LLInventoryType::IT_NONE, // AT_CURRENT_OUTFIT
|
||||
LLInventoryType::IT_NONE, // AT_OUTFIT
|
||||
LLInventoryType::IT_NONE // AT_MY_OUTFITS
|
||||
LLInventoryType::IT_NONE // AT_MY_OUTFITS*/
|
||||
};
|
||||
|
||||
// static
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
#ifndef LL_NOTECARD_H
|
||||
#define LL_NOTECARD_H
|
||||
|
||||
#include "llmemory.h"
|
||||
#include "llpointer.h"
|
||||
#include "llinventory.h"
|
||||
|
||||
class LLNotecard
|
||||
|
||||
@@ -177,7 +177,7 @@ void LLParcel::init(const LLUUID &owner_id,
|
||||
mSaleTimerExpires.stop();
|
||||
mGraceExtension = 0;
|
||||
//mExpireAction = STEA_REVERT;
|
||||
mRecordTransaction = FALSE;
|
||||
//mRecordTransaction = FALSE;
|
||||
|
||||
mAuctionID = 0;
|
||||
mInEscrow = false;
|
||||
@@ -452,7 +452,7 @@ BOOL LLParcel::allowTerraformBy(const LLUUID &agent_id) const
|
||||
|
||||
bool LLParcel::isAgentBlockedFromParcel(LLParcel* parcelp,
|
||||
const LLUUID& agent_id,
|
||||
const std::vector<LLUUID>& group_ids,
|
||||
const uuid_vec_t& group_ids,
|
||||
const BOOL is_agent_identified,
|
||||
const BOOL is_agent_transacted,
|
||||
const BOOL is_agent_ageverified)
|
||||
|
||||
@@ -38,8 +38,8 @@
|
||||
#include "lluuid.h"
|
||||
#include "llparcelflags.h"
|
||||
#include "llpermissions.h"
|
||||
#include "v3math.h"
|
||||
#include "lltimer.h"
|
||||
#include "v3math.h"
|
||||
|
||||
// Grid out of which parcels taken is stepped every 4 meters.
|
||||
const F32 PARCEL_GRID_STEP_METERS = 4.f;
|
||||
@@ -136,9 +136,15 @@ class LLSD;
|
||||
class LLAccessEntry
|
||||
{
|
||||
public:
|
||||
LLUUID mID;
|
||||
S32 mTime;
|
||||
U32 mFlags;
|
||||
LLAccessEntry()
|
||||
: mID(),
|
||||
mTime(0),
|
||||
mFlags(0)
|
||||
{}
|
||||
|
||||
LLUUID mID; // Agent ID
|
||||
S32 mTime; // Time (unix seconds) when entry expires
|
||||
U32 mFlags; // Not used - currently should always be zero
|
||||
};
|
||||
|
||||
typedef std::map<LLUUID,LLAccessEntry>::iterator access_map_iterator;
|
||||
@@ -427,13 +433,10 @@ public:
|
||||
void completeSale(U32& type, U8& flags, LLUUID& to_id);
|
||||
void clearSale();
|
||||
|
||||
// this function returns TRUE if the parcel needs conversion to a
|
||||
// lease from a non-owned-status state.
|
||||
BOOL getRecordTransaction() const { return mRecordTransaction; }
|
||||
void setRecordTransaction(BOOL record) { mRecordTransaction = record; }
|
||||
|
||||
BOOL isMediaResetTimerExpired(const U64& time);
|
||||
|
||||
|
||||
// more accessors
|
||||
U32 getParcelFlags() const { return mParcelFlags; }
|
||||
|
||||
@@ -468,7 +471,9 @@ public:
|
||||
{ return (mParcelFlags & PF_ALLOW_FLY) ? TRUE : FALSE; }
|
||||
|
||||
BOOL getAllowLandmark() const
|
||||
{ return (mParcelFlags & PF_ALLOW_LANDMARK) ? TRUE : FALSE; }
|
||||
{ return TRUE; }
|
||||
//Perhaps revert for opensim?
|
||||
//{ return (mParcelFlags & PF_ALLOW_LANDMARK) ? TRUE : FALSE; }
|
||||
|
||||
BOOL getAllowGroupScripts() const
|
||||
{ return (mParcelFlags & PF_ALLOW_GROUP_SCRIPTS) ? TRUE : FALSE; }
|
||||
@@ -594,6 +599,7 @@ public:
|
||||
BOOL getPreviouslyGroupOwned() const { return mPreviouslyGroupOwned; }
|
||||
BOOL getSellWithObjects() const { return (mParcelFlags & PF_SELL_PARCEL_OBJECTS) ? TRUE : FALSE; }
|
||||
|
||||
|
||||
protected:
|
||||
LLUUID mID;
|
||||
LLUUID mOwnerID;
|
||||
@@ -613,8 +619,6 @@ protected:
|
||||
LLTimer mMediaResetTimer;
|
||||
|
||||
S32 mGraceExtension;
|
||||
BOOL mRecordTransaction;
|
||||
|
||||
|
||||
// This value is non-zero if there is an auction associated with
|
||||
// the parcel.
|
||||
@@ -667,7 +671,6 @@ protected:
|
||||
BOOL mRegionDenyAnonymousOverride;
|
||||
BOOL mRegionDenyAgeUnverifiedOverride;
|
||||
|
||||
|
||||
public:
|
||||
// HACK, make private
|
||||
S32 mLocalID;
|
||||
|
||||
@@ -132,5 +132,7 @@ const S32 PARCEL_DETAILS_DESC = 1;
|
||||
const S32 PARCEL_DETAILS_OWNER = 2;
|
||||
const S32 PARCEL_DETAILS_GROUP = 3;
|
||||
const S32 PARCEL_DETAILS_AREA = 4;
|
||||
const S32 PARCEL_DETAILS_ID = 5;
|
||||
const S32 PARCEL_DETAILS_SEE_AVATARS = 6;
|
||||
|
||||
#endif
|
||||
|
||||
@@ -30,8 +30,8 @@
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "linden_common.h"
|
||||
#include <iostream>
|
||||
#include "linden_common.h"
|
||||
|
||||
#include "llsaleinfo.h"
|
||||
|
||||
|
||||
@@ -17,13 +17,16 @@ set(llmath_SOURCE_FILES
|
||||
llcamera.cpp
|
||||
llcoordframe.cpp
|
||||
llline.cpp
|
||||
llmatrix3a.cpp
|
||||
llmodularmath.cpp
|
||||
llperlin.cpp
|
||||
llquaternion.cpp
|
||||
llrect.cpp
|
||||
llsphere.cpp
|
||||
llvector4a.cpp
|
||||
llvolume.cpp
|
||||
llvolumemgr.cpp
|
||||
llvolumeoctree.cpp
|
||||
llsdutil_math.cpp
|
||||
m3math.cpp
|
||||
m4math.cpp
|
||||
@@ -53,21 +56,32 @@ set(llmath_HEADER_FILES
|
||||
llinterp.h
|
||||
llline.h
|
||||
llmath.h
|
||||
llmatrix3a.h
|
||||
llmatrix3a.inl
|
||||
llmodularmath.h
|
||||
lloctree.h
|
||||
llperlin.h
|
||||
llplane.h
|
||||
llquantize.h
|
||||
llquaternion.h
|
||||
llquaternion2.h
|
||||
llquaternion2.inl
|
||||
llrect.h
|
||||
llsimdmath.h
|
||||
llsimdtypes.h
|
||||
llsimdtypes.inl
|
||||
llsphere.h
|
||||
lltreenode.h
|
||||
llvector4a.h
|
||||
llvector4a.inl
|
||||
llvector4logical.h
|
||||
llv4math.h
|
||||
llv4matrix3.h
|
||||
llv4matrix4.h
|
||||
llv4vector3.h
|
||||
llvolume.h
|
||||
llvolumemgr.h
|
||||
llvolumeoctree.h
|
||||
llsdutil_math.h
|
||||
m3math.h
|
||||
m4math.h
|
||||
|
||||
@@ -54,28 +54,20 @@ LLCalc* LLCalc::sInstance = NULL;
|
||||
|
||||
LLCalc::LLCalc() : mLastErrorPos(0)
|
||||
{
|
||||
// mUserVariables = new calc_map_t;
|
||||
mVariables = new calc_map_t;
|
||||
mConstants = new calc_map_t;
|
||||
|
||||
// Init table of constants
|
||||
(*mConstants)["PI"] = F_PI;
|
||||
(*mConstants)["TWO_PI"] = F_TWO_PI;
|
||||
(*mConstants)["PI_BY_TWO"] = F_PI_BY_TWO;
|
||||
(*mConstants)["SQRT2"] = F_SQRT2;
|
||||
(*mConstants)["DEG_TO_RAD"] = DEG_TO_RAD;
|
||||
(*mConstants)["RAD_TO_DEG"] = RAD_TO_DEG;
|
||||
(*mConstants)["GRAVITY"] = GRAVITY;
|
||||
(*mConstants)["ALMOST_ZERO"] = F_ALMOST_ZERO;
|
||||
(*mConstants)["ALMOST_ONE"] = F_ALMOST_ONE;
|
||||
(*mConstants)["THE_ANSWER"] = 42;
|
||||
mConstants["PI"] = F_PI;
|
||||
mConstants["TWO_PI"] = F_TWO_PI;
|
||||
mConstants["PI_BY_TWO"] = F_PI_BY_TWO;
|
||||
mConstants["SQRT_TWO_PI"] = F_SQRT_TWO_PI;
|
||||
mConstants["SQRT2"] = F_SQRT2;
|
||||
mConstants["SQRT3"] = F_SQRT3;
|
||||
mConstants["DEG_TO_RAD"] = DEG_TO_RAD;
|
||||
mConstants["RAD_TO_DEG"] = RAD_TO_DEG;
|
||||
mConstants["GRAVITY"] = GRAVITY;
|
||||
}
|
||||
|
||||
LLCalc::~LLCalc()
|
||||
{
|
||||
delete mConstants;
|
||||
delete mVariables;
|
||||
// delete mUserVariables;
|
||||
}
|
||||
|
||||
//static
|
||||
@@ -94,17 +86,17 @@ LLCalc* LLCalc::getInstance()
|
||||
|
||||
void LLCalc::setVar(const std::string& name, const F32& value)
|
||||
{
|
||||
(*mVariables)[name] = value;
|
||||
mVariables[name] = value;
|
||||
}
|
||||
|
||||
void LLCalc::clearVar(const std::string& name)
|
||||
{
|
||||
mVariables->erase(name);
|
||||
mVariables.erase(name);
|
||||
}
|
||||
|
||||
void LLCalc::clearAllVariables()
|
||||
{
|
||||
mVariables->clear();
|
||||
mVariables.clear();
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -123,7 +115,7 @@ bool LLCalc::evalString(const std::string& expression, F32& result)
|
||||
std::string expr_upper = expression;
|
||||
LLStringUtil::toUpper(expr_upper);
|
||||
|
||||
LLCalcParser calc(result, mConstants, mVariables);
|
||||
LLCalcParser calc(result, &mConstants, &mVariables);
|
||||
|
||||
mLastErrorPos = 0;
|
||||
std::string::iterator start = expr_upper.begin();
|
||||
|
||||
@@ -69,8 +69,8 @@ public:
|
||||
private:
|
||||
std::string::size_type mLastErrorPos;
|
||||
|
||||
calc_map_t* mConstants;
|
||||
calc_map_t* mVariables;
|
||||
calc_map_t mConstants;
|
||||
calc_map_t mVariables;
|
||||
|
||||
// *TODO: Add support for storing user defined variables, and stored functions.
|
||||
// Will need UI work, and a means to save them between sessions.
|
||||
|
||||
@@ -73,7 +73,9 @@ struct LLCalcParser : grammar<LLCalcParser>
|
||||
(str_p("SQRT") >> '(' >> expression[unary_func.value = bind(&LLCalcParser::_sqrt)(self,arg1)]) |
|
||||
(str_p("LOG") >> '(' >> expression[unary_func.value = bind(&LLCalcParser::_log)(self,arg1)]) |
|
||||
(str_p("EXP") >> '(' >> expression[unary_func.value = bind(&LLCalcParser::_exp)(self,arg1)]) |
|
||||
(str_p("ABS") >> '(' >> expression[unary_func.value = bind(&LLCalcParser::_fabs)(self,arg1)])
|
||||
(str_p("ABS") >> '(' >> expression[unary_func.value = bind(&LLCalcParser::_fabs)(self,arg1)]) |
|
||||
(str_p("FLR") >> '(' >> expression[unary_func.value = bind(&LLCalcParser::_floor)(self,arg1)]) |
|
||||
(str_p("CEIL") >> '(' >> expression[unary_func.value = bind(&LLCalcParser::_ceil)(self,arg1)])
|
||||
) >> assert_syntax(ch_p(')'))
|
||||
;
|
||||
|
||||
@@ -118,7 +120,8 @@ struct LLCalcParser : grammar<LLCalcParser>
|
||||
term =
|
||||
power[term.value = arg1] >>
|
||||
*(('*' >> assert_syntax(power[term.value *= arg1])) |
|
||||
('/' >> assert_syntax(power[term.value /= arg1]))
|
||||
('/' >> assert_syntax(power[term.value /= arg1])) |
|
||||
('%' >> assert_syntax(power[term.value = bind(&fmodf)(term.value, arg1)]))
|
||||
)
|
||||
;
|
||||
|
||||
@@ -153,7 +156,9 @@ private:
|
||||
F32 _sqrt(const F32& a) const { return sqrt(a); }
|
||||
F32 _log(const F32& a) const { return log(a); }
|
||||
F32 _exp(const F32& a) const { return exp(a); }
|
||||
F32 _fabs(const F32& a) const { return fabs(a) * RAD_TO_DEG; }
|
||||
F32 _fabs(const F32& a) const { return fabs(a); }
|
||||
F32 _floor(const F32& a) const { return llfloor(a); }
|
||||
F32 _ceil(const F32& a) const { return llceil(a); }
|
||||
|
||||
F32 _atan2(const F32& a,const F32& b) const { return atan2(a,b); }
|
||||
|
||||
|
||||
@@ -92,7 +92,7 @@ F32 LLCamera::getMaxView() const
|
||||
|
||||
// ---------------- LLCamera::setFoo() member functions ----------------
|
||||
|
||||
void LLCamera::setUserClipPlane(LLPlane const& plane)
|
||||
void LLCamera::setUserClipPlane(const LLPlane& plane)
|
||||
{
|
||||
mPlaneCount = 7;
|
||||
mAgentPlanes[6] = plane;
|
||||
@@ -168,166 +168,91 @@ size_t LLCamera::readFrustumFromBuffer(const char *buffer)
|
||||
|
||||
// ---------------- test methods ----------------
|
||||
|
||||
S32 LLCamera::AABBInFrustum(const LLVector3 ¢er, const LLVector3& radius)
|
||||
S32 LLCamera::AABBInFrustum(const LLVector4a ¢er, const LLVector4a& radius)
|
||||
{
|
||||
static const LLVector3 scaler[] = {
|
||||
LLVector3(-1,-1,-1),
|
||||
LLVector3( 1,-1,-1),
|
||||
LLVector3(-1, 1,-1),
|
||||
LLVector3( 1, 1,-1),
|
||||
LLVector3(-1,-1, 1),
|
||||
LLVector3( 1,-1, 1),
|
||||
LLVector3(-1, 1, 1),
|
||||
LLVector3( 1, 1, 1)
|
||||
static const LLVector4a scaler[] = {
|
||||
LLVector4a(-1,-1,-1),
|
||||
LLVector4a( 1,-1,-1),
|
||||
LLVector4a(-1, 1,-1),
|
||||
LLVector4a( 1, 1,-1),
|
||||
LLVector4a(-1,-1, 1),
|
||||
LLVector4a( 1,-1, 1),
|
||||
LLVector4a(-1, 1, 1),
|
||||
LLVector4a( 1, 1, 1)
|
||||
};
|
||||
|
||||
U8 mask = 0;
|
||||
S32 result = 2;
|
||||
|
||||
/*if (radius.magVecSquared() > mFrustumCornerDist * mFrustumCornerDist)
|
||||
{ //box is larger than frustum, check frustum quads against box planes
|
||||
|
||||
static const LLVector3 dir[] =
|
||||
{
|
||||
LLVector3(1, 0, 0),
|
||||
LLVector3(-1, 0, 0),
|
||||
LLVector3(0, 1, 0),
|
||||
LLVector3(0, -1, 0),
|
||||
LLVector3(0, 0, 1),
|
||||
LLVector3(0, 0, -1)
|
||||
};
|
||||
|
||||
U32 quads[] =
|
||||
{
|
||||
0, 1, 2, 3,
|
||||
0, 1, 5, 4,
|
||||
2, 3, 7, 6,
|
||||
3, 0, 7, 4,
|
||||
1, 2, 6, 4,
|
||||
4, 5, 6, 7
|
||||
};
|
||||
|
||||
result = 0;
|
||||
|
||||
BOOL total_inside = TRUE;
|
||||
for (U32 i = 0; i < 6; i++)
|
||||
{
|
||||
LLVector3 p = center + radius.scaledVec(dir[i]);
|
||||
F32 d = -p*dir[i];
|
||||
|
||||
for (U32 j = 0; j < 6; j++)
|
||||
{ //for each quad
|
||||
F32 dist = mAgentFrustum[quads[j*4+0]]*dir[i] + d;
|
||||
if (dist > 0)
|
||||
{ //at least one frustum point is outside the AABB
|
||||
total_inside = FALSE;
|
||||
for (U32 k = 1; k < 4; k++)
|
||||
{ //for each other point on quad
|
||||
if ( mAgentFrustum[quads[j*4+k]]*dir[i]+d <= 0.f)
|
||||
{ //quad is straddling some plane of AABB
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (U32 k = 1; k < 4; k++)
|
||||
{
|
||||
if (mAgentFrustum[quads[j*4+k]]*dir[i]+d > 0.f)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (total_inside)
|
||||
{
|
||||
result = 1;
|
||||
}
|
||||
}
|
||||
else*/
|
||||
bool result = false;
|
||||
LLVector4a rscale, maxp, minp;
|
||||
LLSimdScalar d;
|
||||
for (U32 i = 0; i < mPlaneCount; i++)
|
||||
{
|
||||
for (U32 i = 0; i < mPlaneCount; i++)
|
||||
mask = mPlaneMask[i];
|
||||
if (mask != 0xff)
|
||||
{
|
||||
mask = mPlaneMask[i];
|
||||
if (mask == 0xff)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
LLPlane p = mAgentPlanes[i];
|
||||
LLVector3 n = LLVector3(p);
|
||||
float d = p.mV[3];
|
||||
LLVector3 rscale = radius.scaledVec(scaler[mask]);
|
||||
|
||||
LLVector3 minp = center - rscale;
|
||||
LLVector3 maxp = center + rscale;
|
||||
|
||||
if (n * minp > -d)
|
||||
const LLPlane& p(mAgentPlanes[i]);
|
||||
p.getAt<3>(d);
|
||||
rscale.setMul(radius, scaler[mask]);
|
||||
minp.setSub(center, rscale);
|
||||
d = -d;
|
||||
if (p.dot3(minp).getF32() > d)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (n * maxp > -d)
|
||||
|
||||
if(!result)
|
||||
{
|
||||
result = 1;
|
||||
maxp.setAdd(center, rscale);
|
||||
result = (p.dot3(maxp).getF32() > d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
return result?1:2;
|
||||
}
|
||||
|
||||
S32 LLCamera::AABBInFrustumNoFarClip(const LLVector3 ¢er, const LLVector3& radius)
|
||||
|
||||
S32 LLCamera::AABBInFrustumNoFarClip(const LLVector4a& center, const LLVector4a& radius)
|
||||
{
|
||||
static const LLVector3 scaler[] = {
|
||||
LLVector3(-1,-1,-1),
|
||||
LLVector3( 1,-1,-1),
|
||||
LLVector3(-1, 1,-1),
|
||||
LLVector3( 1, 1,-1),
|
||||
LLVector3(-1,-1, 1),
|
||||
LLVector3( 1,-1, 1),
|
||||
LLVector3(-1, 1, 1),
|
||||
LLVector3( 1, 1, 1)
|
||||
static const LLVector4a scaler[] = {
|
||||
LLVector4a(-1,-1,-1),
|
||||
LLVector4a( 1,-1,-1),
|
||||
LLVector4a(-1, 1,-1),
|
||||
LLVector4a( 1, 1,-1),
|
||||
LLVector4a(-1,-1, 1),
|
||||
LLVector4a( 1,-1, 1),
|
||||
LLVector4a(-1, 1, 1),
|
||||
LLVector4a( 1, 1, 1)
|
||||
};
|
||||
|
||||
U8 mask = 0;
|
||||
S32 result = 2;
|
||||
|
||||
bool result = false;
|
||||
LLVector4a rscale, maxp, minp;
|
||||
LLSimdScalar d;
|
||||
for (U32 i = 0; i < mPlaneCount; i++)
|
||||
{
|
||||
if (i == 5)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
mask = mPlaneMask[i];
|
||||
if (mask == 0xff)
|
||||
if ((i != 5) && (mask != 0xff))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
LLPlane p = mAgentPlanes[i];
|
||||
LLVector3 n = LLVector3(p);
|
||||
float d = p.mV[3];
|
||||
LLVector3 rscale = radius.scaledVec(scaler[mask]);
|
||||
|
||||
LLVector3 minp = center - rscale;
|
||||
LLVector3 maxp = center + rscale;
|
||||
|
||||
if (n * minp > -d)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (n * maxp > -d)
|
||||
{
|
||||
result = 1;
|
||||
const LLPlane& p(mAgentPlanes[i]);
|
||||
p.getAt<3>(d);
|
||||
rscale.setMul(radius, scaler[mask]);
|
||||
minp.setSub(center, rscale);
|
||||
d = -d;
|
||||
if (p.dot3(minp).getF32() > d)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(!result)
|
||||
{
|
||||
maxp.setAdd(center, rscale);
|
||||
result = (p.dot3(maxp).getF32() > d);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return result?1:2;
|
||||
}
|
||||
|
||||
int LLCamera::sphereInFrustumQuick(const LLVector3 &sphere_center, const F32 radius)
|
||||
@@ -715,9 +640,10 @@ void LLCamera::calculateWorldFrustumPlanes()
|
||||
F32 d;
|
||||
LLVector3 center = mOrigin - mXAxis*mNearPlane;
|
||||
mWorldPlanePos = center;
|
||||
LLVector3 pnorm;
|
||||
for (int p=0; p<4; p++)
|
||||
{
|
||||
LLVector3 pnorm = LLVector3(mLocalPlanes[p]);
|
||||
mLocalPlanes[p].getVector3(pnorm);
|
||||
LLVector3 norm = rotateToAbsolute(pnorm);
|
||||
norm.normVec();
|
||||
d = -(center * norm);
|
||||
@@ -727,13 +653,15 @@ void LLCamera::calculateWorldFrustumPlanes()
|
||||
LLVector3 zaxis(0, 0, 1.0f);
|
||||
F32 yaw = getYaw();
|
||||
{
|
||||
LLVector3 tnorm = LLVector3(mLocalPlanes[PLANE_LEFT]);
|
||||
LLVector3 tnorm;
|
||||
mLocalPlanes[PLANE_LEFT].getVector3(tnorm);
|
||||
tnorm.rotVec(yaw, zaxis);
|
||||
d = -(mOrigin * tnorm);
|
||||
mHorizPlanes[HORIZ_PLANE_LEFT] = LLPlane(tnorm, d);
|
||||
}
|
||||
{
|
||||
LLVector3 tnorm = LLVector3(mLocalPlanes[PLANE_RIGHT]);
|
||||
LLVector3 tnorm;
|
||||
mLocalPlanes[PLANE_RIGHT].getVector3(tnorm);
|
||||
tnorm.rotVec(yaw, zaxis);
|
||||
d = -(mOrigin * tnorm);
|
||||
mHorizPlanes[HORIZ_PLANE_RIGHT] = LLPlane(tnorm, d);
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
#include "llmath.h"
|
||||
#include "llcoordframe.h"
|
||||
#include "llplane.h"
|
||||
#include "llvector4a.h"
|
||||
|
||||
const F32 DEFAULT_FIELD_OF_VIEW = 60.f * DEG_TO_RAD;
|
||||
const F32 DEFAULT_ASPECT_RATIO = 640.f / 480.f;
|
||||
@@ -143,7 +144,7 @@ public:
|
||||
virtual ~LLCamera();
|
||||
|
||||
|
||||
void setUserClipPlane(LLPlane const& plane);
|
||||
void setUserClipPlane(const LLPlane& plane);
|
||||
void disableUserClipPlane();
|
||||
virtual void setView(F32 vertical_fov_rads);
|
||||
void setViewHeightInPixels(S32 height);
|
||||
@@ -191,8 +192,8 @@ public:
|
||||
S32 sphereInFrustum(const LLVector3 ¢er, const F32 radius) const;
|
||||
S32 pointInFrustum(const LLVector3 &point) const { return sphereInFrustum(point, 0.0f); }
|
||||
S32 sphereInFrustumFull(const LLVector3 ¢er, const F32 radius) const { return sphereInFrustum(center, radius); }
|
||||
S32 AABBInFrustum(const LLVector3 ¢er, const LLVector3& radius);
|
||||
S32 AABBInFrustumNoFarClip(const LLVector3 ¢er, const LLVector3& radius);
|
||||
S32 AABBInFrustum(const LLVector4a& center, const LLVector4a& radius);
|
||||
S32 AABBInFrustumNoFarClip(const LLVector4a& center, const LLVector4a& radius);
|
||||
|
||||
//does a quick 'n dirty sphere-sphere check
|
||||
S32 sphereInFrustumQuick(const LLVector3 &sphere_center, const F32 radius);
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
// So, let's define _USE_MATH_DEFINES before including math.h
|
||||
#define _USE_MATH_DEFINES
|
||||
#endif
|
||||
|
||||
#include "math.h"
|
||||
|
||||
// Class from which different types of interpolators can be derived
|
||||
|
||||
@@ -35,10 +35,10 @@
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdlib>
|
||||
#include <complex>
|
||||
#include <vector>
|
||||
#include "lldefs.h"
|
||||
#include "llstl.h" // *TODO: Remove when LLString is gone
|
||||
#include "llstring.h" // *TODO: Remove when LLString is gone
|
||||
//#include "llstl.h" // *TODO: Remove when LLString is gone
|
||||
//#include "llstring.h" // *TODO: Remove when LLString is gone
|
||||
// lltut.h uses is_approx_equal_fraction(). This was moved to its own header
|
||||
// file in llcommon so we can use lltut.h for llcommon tests without making
|
||||
// llcommon depend on llmath.
|
||||
@@ -61,32 +61,11 @@
|
||||
#endif
|
||||
|
||||
// Single Precision Floating Point Routines
|
||||
#ifndef sqrtf
|
||||
#define sqrtf(x) ((F32)sqrt((F64)(x)))
|
||||
#endif
|
||||
#ifndef fsqrtf
|
||||
#define fsqrtf(x) sqrtf(x)
|
||||
#endif
|
||||
|
||||
#ifndef cosf
|
||||
#define cosf(x) ((F32)cos((F64)(x)))
|
||||
#endif
|
||||
#ifndef sinf
|
||||
#define sinf(x) ((F32)sin((F64)(x)))
|
||||
#endif
|
||||
#ifndef tanf
|
||||
// (There used to be more defined here, but they appeared to be redundant and
|
||||
// were breaking some other includes. Removed by Falcon, reviewed by Andrew, 11/25/09)
|
||||
/*#ifndef tanf
|
||||
#define tanf(x) ((F32)tan((F64)(x)))
|
||||
#endif
|
||||
#ifndef acosf
|
||||
#define acosf(x) ((F32)acos((F64)(x)))
|
||||
#endif
|
||||
|
||||
#ifndef powf
|
||||
#define powf(x,y) ((F32)pow((F64)(x),(F64)(y)))
|
||||
#endif
|
||||
#ifndef expf
|
||||
#define expf(x) ((F32)exp((F64)(x)))
|
||||
#endif
|
||||
#endif*/
|
||||
|
||||
const F32 GRAVITY = -9.8f;
|
||||
|
||||
@@ -206,7 +185,7 @@ inline S32 llfloor( F32 f )
|
||||
}
|
||||
return result;
|
||||
#else
|
||||
return (S32)floorf(f);
|
||||
return (S32)floor(f);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -537,6 +516,12 @@ inline void ll_remove_outliers(std::vector<VEC_TYPE>& data, F32 k)
|
||||
VEC_TYPE Q1 = data[data.size()/4];
|
||||
VEC_TYPE Q3 = data[data.size()-data.size()/4-1];
|
||||
|
||||
if ((F32)(Q3-Q1) < 1.f)
|
||||
{
|
||||
// not enough variation to detect outliers
|
||||
return;
|
||||
}
|
||||
|
||||
VEC_TYPE min = (VEC_TYPE) ((F32) Q1-k * (F32) (Q3-Q1));
|
||||
VEC_TYPE max = (VEC_TYPE) ((F32) Q3+k * (F32) (Q3-Q1));
|
||||
|
||||
@@ -562,4 +547,7 @@ inline void ll_remove_outliers(std::vector<VEC_TYPE>& data, F32 k)
|
||||
data.erase(data.begin(), data.begin()+i);
|
||||
}
|
||||
}
|
||||
|
||||
// Include simd math header
|
||||
#include "llsimdmath.h"
|
||||
#endif
|
||||
|
||||
134
indra/llmath/llmatrix3a.cpp
Normal file
134
indra/llmath/llmatrix3a.cpp
Normal file
@@ -0,0 +1,134 @@
|
||||
/**
|
||||
* @file llvector4a.cpp
|
||||
* @brief SIMD vector implementation
|
||||
*
|
||||
* $LicenseInfo:firstyear=2010&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "llmath.h"
|
||||
|
||||
static LL_ALIGN_16(const F32 M_IDENT_3A[12]) =
|
||||
{ 1.f, 0.f, 0.f, 0.f, // Column 1
|
||||
0.f, 1.f, 0.f, 0.f, // Column 2
|
||||
0.f, 0.f, 1.f, 0.f }; // Column 3
|
||||
|
||||
extern const LLMatrix3a LL_M3A_IDENTITY = *reinterpret_cast<const LLMatrix3a*> (M_IDENT_3A);
|
||||
|
||||
void LLMatrix3a::setMul( const LLMatrix3a& lhs, const LLMatrix3a& rhs )
|
||||
{
|
||||
const LLVector4a col0 = lhs.getColumn(0);
|
||||
const LLVector4a col1 = lhs.getColumn(1);
|
||||
const LLVector4a col2 = lhs.getColumn(2);
|
||||
|
||||
for ( int i = 0; i < 3; i++ )
|
||||
{
|
||||
LLVector4a xxxx = _mm_load_ss( rhs.mColumns[i].getF32ptr() );
|
||||
xxxx.splat<0>( xxxx );
|
||||
xxxx.mul( col0 );
|
||||
|
||||
{
|
||||
LLVector4a yyyy = _mm_load_ss( rhs.mColumns[i].getF32ptr() + 1 );
|
||||
yyyy.splat<0>( yyyy );
|
||||
yyyy.mul( col1 );
|
||||
xxxx.add( yyyy );
|
||||
}
|
||||
|
||||
{
|
||||
LLVector4a zzzz = _mm_load_ss( rhs.mColumns[i].getF32ptr() + 2 );
|
||||
zzzz.splat<0>( zzzz );
|
||||
zzzz.mul( col2 );
|
||||
xxxx.add( zzzz );
|
||||
}
|
||||
|
||||
xxxx.store4a( mColumns[i].getF32ptr() );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*static */void LLMatrix3a::batchTransform( const LLMatrix3a& xform, const LLVector4a* src, int numVectors, LLVector4a* dst )
|
||||
{
|
||||
const LLVector4a col0 = xform.getColumn(0);
|
||||
const LLVector4a col1 = xform.getColumn(1);
|
||||
const LLVector4a col2 = xform.getColumn(2);
|
||||
const LLVector4a* maxAddr = src + numVectors;
|
||||
|
||||
if ( numVectors & 0x1 )
|
||||
{
|
||||
LLVector4a xxxx = _mm_load_ss( (const F32*)src );
|
||||
LLVector4a yyyy = _mm_load_ss( (const F32*)src + 1 );
|
||||
LLVector4a zzzz = _mm_load_ss( (const F32*)src + 2 );
|
||||
xxxx.splat<0>( xxxx );
|
||||
yyyy.splat<0>( yyyy );
|
||||
zzzz.splat<0>( zzzz );
|
||||
xxxx.mul( col0 );
|
||||
yyyy.mul( col1 );
|
||||
zzzz.mul( col2 );
|
||||
xxxx.add( yyyy );
|
||||
xxxx.add( zzzz );
|
||||
xxxx.store4a( (F32*)dst );
|
||||
src++;
|
||||
dst++;
|
||||
}
|
||||
|
||||
|
||||
numVectors >>= 1;
|
||||
while ( src < maxAddr )
|
||||
{
|
||||
_mm_prefetch( (const char*)(src + 32 ), _MM_HINT_NTA );
|
||||
_mm_prefetch( (const char*)(dst + 32), _MM_HINT_NTA );
|
||||
LLVector4a xxxx = _mm_load_ss( (const F32*)src );
|
||||
LLVector4a xxxx1= _mm_load_ss( (const F32*)(src + 1) );
|
||||
|
||||
xxxx.splat<0>( xxxx );
|
||||
xxxx1.splat<0>( xxxx1 );
|
||||
xxxx.mul( col0 );
|
||||
xxxx1.mul( col0 );
|
||||
|
||||
{
|
||||
LLVector4a yyyy = _mm_load_ss( (const F32*)src + 1 );
|
||||
LLVector4a yyyy1 = _mm_load_ss( (const F32*)(src + 1) + 1);
|
||||
yyyy.splat<0>( yyyy );
|
||||
yyyy1.splat<0>( yyyy1 );
|
||||
yyyy.mul( col1 );
|
||||
yyyy1.mul( col1 );
|
||||
xxxx.add( yyyy );
|
||||
xxxx1.add( yyyy1 );
|
||||
}
|
||||
|
||||
{
|
||||
LLVector4a zzzz = _mm_load_ss( (const F32*)(src) + 2 );
|
||||
LLVector4a zzzz1 = _mm_load_ss( (const F32*)(++src) + 2 );
|
||||
zzzz.splat<0>( zzzz );
|
||||
zzzz1.splat<0>( zzzz1 );
|
||||
zzzz.mul( col2 );
|
||||
zzzz1.mul( col2 );
|
||||
xxxx.add( zzzz );
|
||||
xxxx1.add( zzzz1 );
|
||||
}
|
||||
|
||||
xxxx.store4a(dst->getF32ptr());
|
||||
src++;
|
||||
dst++;
|
||||
|
||||
xxxx1.store4a((F32*)dst++);
|
||||
}
|
||||
}
|
||||
128
indra/llmath/llmatrix3a.h
Normal file
128
indra/llmath/llmatrix3a.h
Normal file
@@ -0,0 +1,128 @@
|
||||
/**
|
||||
* @file llmatrix3a.h
|
||||
* @brief LLMatrix3a class header file - memory aligned and vectorized 3x3 matrix
|
||||
*
|
||||
* $LicenseInfo:firstyear=2010&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#ifndef LL_LLMATRIX3A_H
|
||||
#define LL_LLMATRIX3A_H
|
||||
|
||||
/////////////////////////////
|
||||
// LLMatrix3a, LLRotation
|
||||
/////////////////////////////
|
||||
// This class stores a 3x3 (technically 4x3) matrix in column-major order
|
||||
/////////////////////////////
|
||||
/////////////////////////////
|
||||
// These classes are intentionally minimal right now. If you need additional
|
||||
// functionality, please contact someone with SSE experience (e.g., Falcon or
|
||||
// Huseby).
|
||||
/////////////////////////////
|
||||
|
||||
// LLMatrix3a is the base class for LLRotation, which should be used instead any time you're dealing with a
|
||||
// rotation matrix.
|
||||
class LLMatrix3a
|
||||
{
|
||||
public:
|
||||
|
||||
// Utility function for quickly transforming an array of LLVector4a's
|
||||
// For transforming a single LLVector4a, see LLVector4a::setRotated
|
||||
static void batchTransform( const LLMatrix3a& xform, const LLVector4a* src, int numVectors, LLVector4a* dst );
|
||||
|
||||
// Utility function to obtain the identity matrix
|
||||
static inline const LLMatrix3a& getIdentity();
|
||||
|
||||
//////////////////////////
|
||||
// Ctors
|
||||
//////////////////////////
|
||||
|
||||
// Ctor
|
||||
LLMatrix3a() {}
|
||||
|
||||
// Ctor for setting by columns
|
||||
inline LLMatrix3a( const LLVector4a& c0, const LLVector4a& c1, const LLVector4a& c2 );
|
||||
|
||||
//////////////////////////
|
||||
// Get/Set
|
||||
//////////////////////////
|
||||
|
||||
// Loads from an LLMatrix3
|
||||
inline void loadu(const LLMatrix3& src);
|
||||
|
||||
// Set rows
|
||||
inline void setRows(const LLVector4a& r0, const LLVector4a& r1, const LLVector4a& r2);
|
||||
|
||||
// Set columns
|
||||
inline void setColumns(const LLVector4a& c0, const LLVector4a& c1, const LLVector4a& c2);
|
||||
|
||||
// Get the read-only access to a specified column. Valid columns are 0-2, but the
|
||||
// function is unchecked. You've been warned.
|
||||
inline const LLVector4a& getColumn(const U32 column) const;
|
||||
|
||||
/////////////////////////
|
||||
// Matrix modification
|
||||
/////////////////////////
|
||||
|
||||
// Set this matrix to the product of lhs and rhs ( this = lhs * rhs )
|
||||
void setMul( const LLMatrix3a& lhs, const LLMatrix3a& rhs );
|
||||
|
||||
// Set this matrix to the transpose of src
|
||||
inline void setTranspose(const LLMatrix3a& src);
|
||||
|
||||
// Set this matrix to a*w + b*(1-w)
|
||||
inline void setLerp(const LLMatrix3a& a, const LLMatrix3a& b, F32 w);
|
||||
|
||||
/////////////////////////
|
||||
// Matrix inspection
|
||||
/////////////////////////
|
||||
|
||||
// Sets all 4 elements in 'dest' to the determinant of this matrix.
|
||||
// If you will be using the determinant in subsequent ops with LLVector4a, use this version
|
||||
inline void getDeterminant( LLVector4a& dest ) const;
|
||||
|
||||
// Returns the determinant as an LLSimdScalar. Use this if you will be using the determinant
|
||||
// primary for scalar operations.
|
||||
inline LLSimdScalar getDeterminant() const;
|
||||
|
||||
// Returns nonzero if rows 0-2 and colums 0-2 contain no NaN or INF values. Row 3 is ignored
|
||||
inline LLBool32 isFinite() const;
|
||||
|
||||
// Returns true if this matrix is equal to 'rhs' up to 'tolerance'
|
||||
inline bool isApproximatelyEqual( const LLMatrix3a& rhs, F32 tolerance = F_APPROXIMATELY_ZERO ) const;
|
||||
|
||||
protected:
|
||||
|
||||
LLVector4a mColumns[3];
|
||||
|
||||
};
|
||||
|
||||
class LLRotation : public LLMatrix3a
|
||||
{
|
||||
public:
|
||||
|
||||
LLRotation() {}
|
||||
|
||||
// Returns true if this rotation is orthonormal with det ~= 1
|
||||
inline bool isOkRotation() const;
|
||||
};
|
||||
|
||||
#endif
|
||||
119
indra/llmath/llmatrix3a.inl
Normal file
119
indra/llmath/llmatrix3a.inl
Normal file
@@ -0,0 +1,119 @@
|
||||
/**
|
||||
* @file llmatrix3a.inl
|
||||
* @brief LLMatrix3a inline definitions
|
||||
*
|
||||
* $LicenseInfo:firstyear=2010&license=viewerlgpl$
|
||||
* Second Life Viewer Source Code
|
||||
* Copyright (C) 2010, Linden Research, Inc.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation;
|
||||
* version 2.1 of the License only.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
|
||||
* $/LicenseInfo$
|
||||
*/
|
||||
|
||||
#include "llmatrix3a.h"
|
||||
#include "m3math.h"
|
||||
|
||||
inline LLMatrix3a::LLMatrix3a( const LLVector4a& c0, const LLVector4a& c1, const LLVector4a& c2 )
|
||||
{
|
||||
setColumns( c0, c1, c2 );
|
||||
}
|
||||
|
||||
inline void LLMatrix3a::loadu(const LLMatrix3& src)
|
||||
{
|
||||
mColumns[0].load3(src.mMatrix[0]);
|
||||
mColumns[1].load3(src.mMatrix[1]);
|
||||
mColumns[2].load3(src.mMatrix[2]);
|
||||
}
|
||||
|
||||
inline void LLMatrix3a::setRows(const LLVector4a& r0, const LLVector4a& r1, const LLVector4a& r2)
|
||||
{
|
||||
mColumns[0] = r0;
|
||||
mColumns[1] = r1;
|
||||
mColumns[2] = r2;
|
||||
setTranspose( *this );
|
||||
}
|
||||
|
||||
inline void LLMatrix3a::setColumns(const LLVector4a& c0, const LLVector4a& c1, const LLVector4a& c2)
|
||||
{
|
||||
mColumns[0] = c0;
|
||||
mColumns[1] = c1;
|
||||
mColumns[2] = c2;
|
||||
}
|
||||
|
||||
inline void LLMatrix3a::setTranspose(const LLMatrix3a& src)
|
||||
{
|
||||
const LLQuad srcCol0 = src.mColumns[0];
|
||||
const LLQuad srcCol1 = src.mColumns[1];
|
||||
const LLQuad unpacklo = _mm_unpacklo_ps( srcCol0, srcCol1 );
|
||||
mColumns[0] = _mm_movelh_ps( unpacklo, src.mColumns[2] );
|
||||
mColumns[1] = _mm_shuffle_ps( _mm_movehl_ps( srcCol0, unpacklo ), src.mColumns[2], _MM_SHUFFLE(0, 1, 1, 0) );
|
||||
mColumns[2] = _mm_shuffle_ps( _mm_unpackhi_ps( srcCol0, srcCol1 ), src.mColumns[2], _MM_SHUFFLE(0, 2, 1, 0) );
|
||||
}
|
||||
|
||||
inline const LLVector4a& LLMatrix3a::getColumn(const U32 column) const
|
||||
{
|
||||
llassert( column < 3 );
|
||||
return mColumns[column];
|
||||
}
|
||||
|
||||
inline void LLMatrix3a::setLerp(const LLMatrix3a& a, const LLMatrix3a& b, F32 w)
|
||||
{
|
||||
mColumns[0].setLerp( a.mColumns[0], b.mColumns[0], w );
|
||||
mColumns[1].setLerp( a.mColumns[1], b.mColumns[1], w );
|
||||
mColumns[2].setLerp( a.mColumns[2], b.mColumns[2], w );
|
||||
}
|
||||
|
||||
inline LLBool32 LLMatrix3a::isFinite() const
|
||||
{
|
||||
return mColumns[0].isFinite3() && mColumns[1].isFinite3() && mColumns[2].isFinite3();
|
||||
}
|
||||
|
||||
inline void LLMatrix3a::getDeterminant( LLVector4a& dest ) const
|
||||
{
|
||||
LLVector4a col1xcol2; col1xcol2.setCross3( mColumns[1], mColumns[2] );
|
||||
dest.setAllDot3( col1xcol2, mColumns[0] );
|
||||
}
|
||||
|
||||
inline LLSimdScalar LLMatrix3a::getDeterminant() const
|
||||
{
|
||||
LLVector4a col1xcol2; col1xcol2.setCross3( mColumns[1], mColumns[2] );
|
||||
return col1xcol2.dot3( mColumns[0] );
|
||||
}
|
||||
|
||||
inline bool LLMatrix3a::isApproximatelyEqual( const LLMatrix3a& rhs, F32 tolerance /*= F_APPROXIMATELY_ZERO*/ ) const
|
||||
{
|
||||
return rhs.getColumn(0).equals3(mColumns[0], tolerance)
|
||||
&& rhs.getColumn(1).equals3(mColumns[1], tolerance)
|
||||
&& rhs.getColumn(2).equals3(mColumns[2], tolerance);
|
||||
}
|
||||
|
||||
inline const LLMatrix3a& LLMatrix3a::getIdentity()
|
||||
{
|
||||
extern const LLMatrix3a LL_M3A_IDENTITY;
|
||||
return LL_M3A_IDENTITY;
|
||||
}
|
||||
|
||||
inline bool LLRotation::isOkRotation() const
|
||||
{
|
||||
LLMatrix3a transpose; transpose.setTranspose( *this );
|
||||
LLMatrix3a product; product.setMul( *this, transpose );
|
||||
|
||||
LLSimdScalar detMinusOne = getDeterminant() - 1.f;
|
||||
|
||||
return product.isApproximatelyEqual( LLMatrix3a::getIdentity() ) && (detMinusOne.getAbs() < F_APPROXIMATELY_ZERO);
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user