From 1f187b09ee6be70e9d1e3f2b451aff4b9aa300df Mon Sep 17 00:00:00 2001 From: Shyotl Date: Sat, 27 Aug 2011 01:57:10 -0500 Subject: [PATCH] LLCommon cleanup and updating to V2 (V3 now, I guess.) --- indra/cmake/LLCommon.cmake | 5 + indra/llaudio/llvorbisencode.cpp | 6 +- indra/llcharacter/llbvhloader.cpp | 2 +- indra/llcharacter/llcharacter.h | 2 +- indra/llcharacter/lljointstate.h | 2 +- indra/llcharacter/llpose.cpp | 2 - indra/llcharacter/llpose.h | 2 + indra/llcharacter/llstatemachine.cpp | 2 +- indra/llcommon/CMakeLists.txt | 2 + indra/llcommon/llapr.cpp | 4 + indra/llcommon/llapr.h | 5 +- indra/llcommon/llassettype.cpp | 1 + indra/llcommon/llfoldertype.cpp | 6 + indra/llcommon/llfoldertype.h | 9 +- indra/llcommon/llinstancetracker.h | 2 +- indra/llcommon/llkeythrottle.h | 56 ++ indra/llcommon/llmortician.cpp | 6 - indra/llcommon/llmortician.h | 1 - indra/llcommon/llpreprocessor.h | 33 +- indra/llcommon/llqueuedthread.cpp | 3 +- indra/llcommon/llsd.cpp | 12 +- indra/llcommon/llsdserialize.cpp | 2 +- indra/llcommon/llsdserialize.h | 3 +- indra/llcommon/llsdserialize_xml.cpp | 35 +- indra/llcommon/llsdutil.cpp | 375 ++++++++++++ indra/llcommon/llsdutil.h | 342 ++++++++++- indra/llcommon/llsingleton.h | 20 +- indra/llcommon/llstat.cpp | 92 ++- indra/llcommon/llstat.h | 46 +- indra/llcommon/llstreamtools.cpp | 22 +- indra/llcommon/lltimer.cpp | 2 + indra/llcommon/lltimer.h | 5 +- indra/llcommon/lltreeiterators.h | 705 ++++++++++++++++++++++ indra/llinventory/lleconomy.h | 2 +- indra/llinventory/llinventory.h | 84 +-- indra/llinventory/llinventorytype.cpp | 1 + indra/llinventory/llnotecard.h | 2 +- indra/llinventory/llparcel.cpp | 2 +- indra/llinventory/llparcel.h | 11 +- indra/llinventory/llparcelflags.h | 2 + indra/llinventory/llsaleinfo.cpp | 2 +- indra/newview/llassetuploadresponders.cpp | 1 + indra/newview/llfloaterbulkpermission.cpp | 1 + indra/newview/llfloaterbuy.cpp | 1 + indra/newview/llfloaterbuycontents.cpp | 1 + indra/newview/llfloaterproperties.cpp | 1 + indra/newview/llinventorybridge.cpp | 1 + indra/newview/llinventoryview.cpp | 1 + indra/newview/llpanelcontents.cpp | 1 + indra/newview/llpanelgroupnotices.cpp | 1 + indra/newview/llpanelinventory.cpp | 1 + indra/newview/llpreview.cpp | 1 + indra/newview/llpreviewgesture.cpp | 1 + indra/newview/llpreviewnotecard.cpp | 1 + indra/newview/llpreviewscript.cpp | 1 + indra/newview/lltooldraganddrop.cpp | 1 + indra/newview/lltracker.cpp | 1 + indra/newview/llviewerinventory.cpp | 1 + indra/newview/llviewermenu.cpp | 1 + indra/newview/llviewermessage.cpp | 1 + indra/newview/llviewerobject.cpp | 1 + indra/newview/llviewerobjectbackup.cpp | 1 + indra/newview/llviewertexteditor.cpp | 1 + 63 files changed, 1750 insertions(+), 190 deletions(-) create mode 100644 indra/llcommon/lltreeiterators.h diff --git a/indra/cmake/LLCommon.cmake b/indra/cmake/LLCommon.cmake index 222d1fac8..beac1d012 100644 --- a/indra/cmake/LLCommon.cmake +++ b/indra/cmake/LLCommon.cmake @@ -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) diff --git a/indra/llaudio/llvorbisencode.cpp b/indra/llaudio/llvorbisencode.cpp index 443b57698..2fcaf97a8 100644 --- a/indra/llaudio/llvorbisencode.cpp +++ b/indra/llaudio/llvorbisencode.cpp @@ -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 diff --git a/indra/llcharacter/llbvhloader.cpp b/indra/llcharacter/llbvhloader.cpp index 12bcffac2..8c7878936 100644 --- a/indra/llcharacter/llbvhloader.cpp +++ b/indra/llcharacter/llbvhloader.cpp @@ -226,7 +226,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); + infile.open(path, LL_APR_R); apr_file_t *fp = infile.getFileHandle(); if (!fp) return E_ST_NO_XLT_FILE; diff --git a/indra/llcharacter/llcharacter.h b/indra/llcharacter/llcharacter.h index 7d30b006d..d435a4cca 100644 --- a/indra/llcharacter/llcharacter.h +++ b/indra/llcharacter/llcharacter.h @@ -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; diff --git a/indra/llcharacter/lljointstate.h b/indra/llcharacter/lljointstate.h index 16ad0e120..e40cf2673 100644 --- a/indra/llcharacter/lljointstate.h +++ b/indra/llcharacter/lljointstate.h @@ -37,7 +37,7 @@ // Header Files //----------------------------------------------------------------------------- #include "lljoint.h" -#include "llmemory.h" +#include "llrefcount.h" //----------------------------------------------------------------------------- // class LLJointState diff --git a/indra/llcharacter/llpose.cpp b/indra/llcharacter/llpose.cpp index b770b05a7..7f08f3e58 100644 --- a/indra/llcharacter/llpose.cpp +++ b/indra/llcharacter/llpose.cpp @@ -163,8 +163,6 @@ void LLPose::setWeight(F32 weight) // there was a crash here // llassert_always(iter->second.notNull()); - if(!iter->second) //uhoh... - continue; iter->second->setWeight(weight); } mWeight = weight; diff --git a/indra/llcharacter/llpose.h b/indra/llcharacter/llpose.h index 80487bd12..2b976b219 100644 --- a/indra/llcharacter/llpose.h +++ b/indra/llcharacter/llpose.h @@ -40,6 +40,8 @@ #include "lljointstate.h" #include "lljoint.h" #include "llmap.h" +#include "llpointer.h" + #include #include diff --git a/indra/llcharacter/llstatemachine.cpp b/indra/llcharacter/llstatemachine.cpp index cc74d9ccf..e6fa4d798 100644 --- a/indra/llcharacter/llstatemachine.cpp +++ b/indra/llcharacter/llstatemachine.cpp @@ -211,7 +211,7 @@ LLFSMState* LLStateDiagram::getState(U32 state_id) BOOL LLStateDiagram::saveDotFile(const std::string& filename) { LLAPRFile outfile ; - outfile.open(filename, LL_APR_W, LLAPRFile::global); + outfile.open(filename, LL_APR_W); apr_file_t* dot_file = outfile.getFileHandle() ; if (!dot_file) diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index c72b4d277..99f00a2c5 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -196,6 +196,7 @@ set(llcommon_HEADER_FILES llsys.h llthread.h lltimer.h + lltreeiterators.h lluri.h lluuid.h lluuidhashmap.h @@ -232,6 +233,7 @@ target_link_libraries( ${EXPAT_LIBRARIES} ${ZLIB_LIBRARIES} ${WINDOWS_LIBRARIES} + ${BOOST_REGEX_LIBRARY} ${CWDEBUG_LIBRARIES} ${CORESERVICES_LIBRARY} ) diff --git a/indra/llcommon/llapr.cpp b/indra/llcommon/llapr.cpp index d2169d65e..fb07621cb 100644 --- a/indra/llcommon/llapr.cpp +++ b/indra/llcommon/llapr.cpp @@ -191,6 +191,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::global : LLAPRFile::local); +} // File I/O S32 LLAPRFile::read(void *buf, S32 nbytes) { diff --git a/indra/llcommon/llapr.h b/indra/llcommon/llapr.h index ded15f531..a9c0543c2 100644 --- a/indra/llcommon/llapr.h +++ b/indra/llcommon/llapr.h @@ -150,10 +150,11 @@ public: }; LLAPRFile() ; - LLAPRFile(const std::string& filename, apr_int32_t flags, access_t access_type); + LLAPRFile(const std::string& filename, apr_int32_t flags, access_t access_type = LLAPRFile::global); ~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 = LLAPRFile::global, 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 diff --git a/indra/llcommon/llassettype.cpp b/indra/llcommon/llassettype.cpp index c2b3779db..6aea07fd0 100644 --- a/indra/llcommon/llassettype.cpp +++ b/indra/llcommon/llassettype.cpp @@ -35,6 +35,7 @@ #include "llassettype.h" #include "lldictionary.h" #include "llmemory.h" +#include "llsingleton.h" ///---------------------------------------------------------------------------- /// Class LLAssetType diff --git a/indra/llcommon/llfoldertype.cpp b/indra/llcommon/llfoldertype.cpp index 76e0d2bc9..280606b4f 100644 --- a/indra/llcommon/llfoldertype.cpp +++ b/indra/llcommon/llfoldertype.cpp @@ -36,6 +36,7 @@ #include "llfoldertype.h" #include "lldictionary.h" #include "llmemory.h" +#include "llsingleton.h" ///---------------------------------------------------------------------------- /// Class LLFolderType @@ -95,7 +96,12 @@ LLFolderDictionary::LLFolderDictionary() 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)); }; diff --git a/indra/llcommon/llfoldertype.h b/indra/llcommon/llfoldertype.h index e0ce9fa3f..7e7cfa2b9 100644 --- a/indra/llcommon/llfoldertype.h +++ b/indra/llcommon/llfoldertype.h @@ -87,9 +87,14 @@ public: FT_OUTFIT = 47, FT_MY_OUTFITS = 48, - FT_INBOX = 49, + FT_MESH = 49, - FT_COUNT = 50, + FT_INBOX = 50, + FT_OUTBOX = 51, + + FT_BASIC_ROOT = 52, + + FT_COUNT, FT_NONE = -1 }; diff --git a/indra/llcommon/llinstancetracker.h b/indra/llcommon/llinstancetracker.h index 30f26952a..46c72455a 100644 --- a/indra/llcommon/llinstancetracker.h +++ b/indra/llcommon/llinstancetracker.h @@ -99,7 +99,7 @@ public: public: typedef boost::iterator_facade super_t; - key_iter(typename InstanceMap::iterator& it) + key_iter(typename InstanceMap::iterator it) : mIterator(it) { ++sIterationNestDepth; diff --git a/indra/llcommon/llkeythrottle.h b/indra/llcommon/llkeythrottle.h index 873f50a65..4ac689163 100644 --- a/indra/llcommon/llkeythrottle.h +++ b/indra/llcommon/llkeythrottle.h @@ -118,6 +118,62 @@ public: THROTTLE_BLOCKED, // rate exceed, block key }; + F64 getActionCount(const T& id) + { + U64 now = 0; + if ( mIsRealtime ) + { + now = LLKeyThrottleImpl::getTime(); + } + else + { + now = LLKeyThrottleImpl::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::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::EntryMap; + m.currMap = new typename LLKeyThrottleImpl::EntryMap; + + m.startTime = now; + } + } + + U32 prevCount = 0; + + typename LLKeyThrottleImpl::EntryMap::const_iterator prev = m.prevMap->find(id); + if (prev != m.prevMap->end()) + { + prevCount = prev->second.count; + } + + typename LLKeyThrottleImpl::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) { diff --git a/indra/llcommon/llmortician.cpp b/indra/llcommon/llmortician.cpp index 2909f4514..c800b654b 100644 --- a/indra/llcommon/llmortician.cpp +++ b/indra/llcommon/llmortician.cpp @@ -74,9 +74,3 @@ void LLMortician::setZealous(BOOL b) { sDestroyImmediate = b; } - -// static -BOOL LLMortician::getZealous() -{ - return sDestroyImmediate; -} diff --git a/indra/llcommon/llmortician.h b/indra/llcommon/llmortician.h index 55a101a97..59d284182 100644 --- a/indra/llcommon/llmortician.h +++ b/indra/llcommon/llmortician.h @@ -46,7 +46,6 @@ public: // sets destroy immediate true static void setZealous(BOOL b); - static BOOL getZealous(); private: static BOOL sDestroyImmediate; diff --git a/indra/llcommon/llpreprocessor.h b/indra/llcommon/llpreprocessor.h index df49757a6..a956718e6 100644 --- a/indra/llcommon/llpreprocessor.h +++ b/indra/llcommon/llpreprocessor.h @@ -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 diff --git a/indra/llcommon/llqueuedthread.cpp b/indra/llcommon/llqueuedthread.cpp index c88909eb2..2325efc38 100644 --- a/indra/llcommon/llqueuedthread.cpp +++ b/indra/llcommon/llqueuedthread.cpp @@ -31,8 +31,9 @@ #include "linden_common.h" #include "llqueuedthread.h" + #include "llstl.h" -#include "lltimer.h" +#include "lltimer.h" // ms_sleep() //============================================================================ diff --git a/indra/llcommon/llsd.cpp b/indra/llcommon/llsd.cpp index ba7901cdb..7086e4248 100644 --- a/indra/llcommon/llsd.cpp +++ b/indra/llcommon/llsd.cpp @@ -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(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(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); } diff --git a/indra/llcommon/llsdserialize.cpp b/indra/llcommon/llsdserialize.cpp index cc0307a7a..28700faae 100644 --- a/indra/llcommon/llsdserialize.cpp +++ b/indra/llcommon/llsdserialize.cpp @@ -34,7 +34,7 @@ #include "linden_common.h" #include "llsdserialize.h" -#include "llmemory.h" +#include "llpointer.h" #include "llstreamtools.h" // for fullread #include diff --git a/indra/llcommon/llsdserialize.h b/indra/llcommon/llsdserialize.h index aed844fee..6f657b464 100644 --- a/indra/llcommon/llsdserialize.h +++ b/indra/llcommon/llsdserialize.h @@ -36,8 +36,9 @@ #define LL_LLSDSERIALIZE_H #include +#include "llpointer.h" +#include "llrefcount.h" #include "llsd.h" -#include "llmemory.h" /** * @class LLSDParser diff --git a/indra/llcommon/llsdserialize_xml.cpp b/indra/llcommon/llsdserialize_xml.cpp index 33206b46d..9bc17e0aa 100644 --- a/indra/llcommon/llsdserialize_xml.cpp +++ b/indra/llcommon/llsdserialize_xml.cpp @@ -37,6 +37,7 @@ #include #include "apr_base64.h" +#include 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 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; diff --git a/indra/llcommon/llsdutil.cpp b/indra/llcommon/llsdutil.cpp index aa0e0f369..2c91b68ef 100644 --- a/indra/llcommon/llsdutil.cpp +++ b/indra/llcommon/llsdutil.cpp @@ -46,6 +46,12 @@ #endif #include "llsdserialize.h" +#include "stringize.h" +#include "is_approx_equal_fraction.h" + +#include +#include +#include // 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 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(""); + } + +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 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 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 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 + } +} diff --git a/indra/llcommon/llsdutil.h b/indra/llcommon/llsdutil.h index bb5765539..f57cab3e0 100644 --- a/indra/llcommon/llsdutil.h +++ b/indra/llcommon/llsdutil.h @@ -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 LLSD llsd_copy_array(Input iter, Input end) @@ -85,4 +146,283 @@ template 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 + * LLSDArray()("text")(17)(3.14) 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 + * LLSDMap()("alpha", "abc")("number", 17)("pi", 3.14) 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(someLLSD), ...); + * @endcode + */ +template +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 \ +{ \ +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 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(yourLLSD). + */ +template <> +class LLSDParam +{ +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::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 diff --git a/indra/llcommon/llsingleton.h b/indra/llcommon/llsingleton.h index 7aee1bb85..00757be27 100644 --- a/indra/llcommon/llsingleton.h +++ b/indra/llcommon/llsingleton.h @@ -100,12 +100,6 @@ private: DELETED } EInitState; - static void deleteSingleton() - { - delete getData().mSingletonInstance; - getData().mSingletonInstance = NULL; - } - // stores pointer to singleton instance // and tracks initialization state of singleton struct SingletonInstanceData @@ -120,7 +114,11 @@ private: ~SingletonInstanceData() { - deleteSingleton(); + SingletonInstanceData& data = getData(); + if (data.mInitState != DELETED) + { + deleteSingleton(); + } } }; @@ -132,6 +130,14 @@ public: data.mInitState = DELETED; } + // Can be used to control when the singleton is deleted. Not normally needed. + static void deleteSingleton() + { + delete getData().mSingletonInstance; + getData().mSingletonInstance = NULL; + getData().mInitState = DELETED; + } + static SingletonInstanceData& getData() { // this is static to cache the lookup results diff --git a/indra/llcommon/llstat.cpp b/indra/llcommon/llstat.cpp index 0583a0539..40ae67c51 100644 --- a/indra/llcommon/llstat.cpp +++ b/indra/llcommon/llstat.cpp @@ -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() diff --git a/indra/llcommon/llstat.h b/indra/llcommon/llstat.h index 797e82b9e..bd73c9a6b 100644 --- a/indra/llcommon/llstat.h +++ b/indra/llcommon/llstat.h @@ -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 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_ diff --git a/indra/llcommon/llstreamtools.cpp b/indra/llcommon/llstreamtools.cpp index b60220830..4ed2df58e 100644 --- a/indra/llcommon/llstreamtools.cpp +++ b/indra/llcommon/llstreamtools.cpp @@ -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++; diff --git a/indra/llcommon/lltimer.cpp b/indra/llcommon/lltimer.cpp index 34e19f83f..1762b3b00 100644 --- a/indra/llcommon/lltimer.cpp +++ b/indra/llcommon/lltimer.cpp @@ -36,6 +36,8 @@ #include "u64.h" +#include "lldate.h" + #if LL_WINDOWS # define WIN32_LEAN_AND_MEAN # include diff --git a/indra/llcommon/lltimer.h b/indra/llcommon/lltimer.h index 68f06fdce..478585e54 100644 --- a/indra/llcommon/lltimer.h +++ b/indra/llcommon/lltimer.h @@ -39,8 +39,6 @@ #include #include "stdtypes.h" -#include "llpreprocessor.h" -#include "lldate.h" #include #include @@ -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 diff --git a/indra/llcommon/lltreeiterators.h b/indra/llcommon/lltreeiterators.h new file mode 100644 index 000000000..ba861ae70 --- /dev/null +++ b/indra/llcommon/lltreeiterators.h @@ -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 li, *li gets you a pointer + * to MyNode, and **li gets you the MyNode instance itself. + * More commonly, instead of writing li->member, you write + * (*li)->member -- as you would if you were traversing an + * STL container of MyNode pointers. + * + * It would certainly be possible to build these iterators so that + * *iterator 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 + * pointers to 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 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 +#include +#include +#include +#include + +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 LLBaseIter: public boost::iterator_facade::type, + boost::forward_traversal_tag> +{ +protected: + /// LLPtrTo::type is either NODE* or LLPointer, as appropriate + typedef typename LLPtrTo::type ptr_type; + /// function that advances from this node to next accepts a node pointer + /// and returns another + typedef boost::function func_type; + typedef SELFTYPE self_type; +}; + +/// Functor returning NULL, suitable for an end-iterator's 'next' functor +template +typename LLPtrTo::type LLNullNextFunctor(const typename LLPtrTo::type&) +{ + return typename LLPtrTo::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.) boost::bind(&NODE::mNext, _1) 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 boost::bind(&NODE::next, _1). + */ +template +class LLLinkedIter: public LLBaseIter, NODE> +{ + typedef LLBaseIter, 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) + {} + +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(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 LLTreeUpIter: public LLLinkedIter +{ + typedef LLLinkedIter 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 LLTreeDownIter: public LLBaseIter, NODE> +{ + typedef LLBaseIter, 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 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(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 +class LLTreeRootIter +{ + enum { use_a_valid_LLTreeIter_RootIter_value = false }; +public: + /// Bogus constructors for default (unrecognized discriminator) case + template + 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 LLTreeRootIter: public LLTreeUpIter +{ + typedef LLTreeUpIter 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 LLTreeRootIter: public LLTreeDownIter +{ + typedef LLTreeDownIter 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. + * + * The end() LLTreeDFSIter must, of course, match the begin() iterator's + * template parameters, but is constructed without runtime parameters. + */ +template +class LLTreeDFSIter: public LLBaseIter, NODE> +{ + typedef LLBaseIter, 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 func_type; +private: + typedef std::vector 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(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. + * + * The end() LLTreeDFSPostIter must, of course, match the begin() iterator's + * template parameters, but is constructed without runtime parameters. + */ +template +class LLTreeDFSPostIter: public LLBaseIter, NODE> +{ + typedef LLBaseIter, 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 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 > 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(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. + * + * The end() LLTreeBFSIter must, of course, match the begin() iterator's + * template parameters, but is constructed without runtime parameters. + */ +template +class LLTreeBFSIter: public LLBaseIter, NODE> +{ + typedef LLBaseIter, 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 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 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(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 +class LLTreeWalkIter +{ + enum { use_a_valid_LLTreeIter_WalkIter_value = false }; +public: + /// Bogus constructors for default (unrecognized discriminator) case + template + 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 LLTreeWalkIter: + public LLTreeDFSIter +{ + typedef LLTreeDFSIter 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 LLTreeWalkIter: + public LLTreeDFSPostIter +{ + typedef LLTreeDFSPostIter 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 LLTreeWalkIter: + public LLTreeBFSIter +{ + typedef LLTreeBFSIter 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) */ diff --git a/indra/llinventory/lleconomy.h b/indra/llinventory/lleconomy.h index 2e2adc4d4..e48008545 100644 --- a/indra/llinventory/lleconomy.h +++ b/indra/llinventory/lleconomy.h @@ -32,7 +32,7 @@ #ifndef LL_LLECONOMY_H #define LL_LLECONOMY_H -#include "llmemory.h" +#include "llsingleton.h" class LLMessageSystem; class LLVector3; diff --git a/indra/llinventory/llinventory.h b/indra/llinventory/llinventory.h index e28c046bf..479c7d397 100644 --- a/indra/llinventory/llinventory.h +++ b/indra/llinventory/llinventory.h @@ -36,10 +36,9 @@ #include "lldarray.h" #include "llfoldertype.h" #include "llinventorytype.h" -#include "llinventorydefines.h" #include "llmemtype.h" #include "llpermissions.h" -#include "llmemory.h" +#include "llrefcount.h" #include "llsaleinfo.h" #include "llsd.h" #include "lluuid.h" @@ -304,84 +303,11 @@ protected: //----------------------------------------------------------------------------- -// 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 -{ - 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); - } -}; - -// These functions convert between structured data and an inventroy -// item, appropriate for serialization. LLSD ll_create_sd_from_inventory_item(LLPointer item); LLPointer ll_create_item_from_sd(const LLSD& sd_item); LLSD ll_create_sd_from_inventory_category(LLPointer cat); diff --git a/indra/llinventory/llinventorytype.cpp b/indra/llinventory/llinventorytype.cpp index 35b5bde05..1dc7a7f2c 100644 --- a/indra/llinventory/llinventorytype.cpp +++ b/indra/llinventory/llinventorytype.cpp @@ -35,6 +35,7 @@ #include "llinventorytype.h" #include "lldictionary.h" #include "llmemory.h" +#include "llsingleton.h" static const std::string empty_string; diff --git a/indra/llinventory/llnotecard.h b/indra/llinventory/llnotecard.h index b903f1fdb..092ab2ce3 100644 --- a/indra/llinventory/llnotecard.h +++ b/indra/llinventory/llnotecard.h @@ -33,7 +33,7 @@ #ifndef LL_NOTECARD_H #define LL_NOTECARD_H -#include "llmemory.h" +#include "llpointer.h" #include "llinventory.h" class LLNotecard diff --git a/indra/llinventory/llparcel.cpp b/indra/llinventory/llparcel.cpp index c167ef194..070437ee4 100644 --- a/indra/llinventory/llparcel.cpp +++ b/indra/llinventory/llparcel.cpp @@ -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; diff --git a/indra/llinventory/llparcel.h b/indra/llinventory/llparcel.h index 7423229f7..67dda0c37 100644 --- a/indra/llinventory/llparcel.h +++ b/indra/llinventory/llparcel.h @@ -432,13 +432,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; } @@ -473,7 +470,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; } @@ -619,8 +618,6 @@ protected: LLTimer mMediaResetTimer; S32 mGraceExtension; - BOOL mRecordTransaction; - // This value is non-zero if there is an auction associated with // the parcel. diff --git a/indra/llinventory/llparcelflags.h b/indra/llinventory/llparcelflags.h index a1bd85f50..122468e91 100644 --- a/indra/llinventory/llparcelflags.h +++ b/indra/llinventory/llparcelflags.h @@ -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 diff --git a/indra/llinventory/llsaleinfo.cpp b/indra/llinventory/llsaleinfo.cpp index e51e35e6e..b7afb28ad 100644 --- a/indra/llinventory/llsaleinfo.cpp +++ b/indra/llinventory/llsaleinfo.cpp @@ -30,8 +30,8 @@ * $/LicenseInfo$ */ -#include "linden_common.h" #include +#include "linden_common.h" #include "llsaleinfo.h" diff --git a/indra/newview/llassetuploadresponders.cpp b/indra/newview/llassetuploadresponders.cpp index 435f67ebf..a3f100a84 100644 --- a/indra/newview/llassetuploadresponders.cpp +++ b/indra/newview/llassetuploadresponders.cpp @@ -39,6 +39,7 @@ #include "llcompilequeue.h" #include "llfloaterbuycurrency.h" #include "llnotify.h" +#include "llinventorydefines.h" #include "llinventorymodel.h" #include "llinventoryview.h" #include "llpermissionsflags.h" diff --git a/indra/newview/llfloaterbulkpermission.cpp b/indra/newview/llfloaterbulkpermission.cpp index 3216a8de0..1dc8a30d3 100644 --- a/indra/newview/llfloaterbulkpermission.cpp +++ b/indra/newview/llfloaterbulkpermission.cpp @@ -35,6 +35,7 @@ #include "llviewerprecompiledheaders.h" #include "llfloaterbulkpermission.h" #include "llfloaterperms.h" // for utilities +#include "llinventorydefines.h" #include "llagent.h" #include "llchat.h" #include "llviewerwindow.h" diff --git a/indra/newview/llfloaterbuy.cpp b/indra/newview/llfloaterbuy.cpp index 49199fff2..ade709dac 100644 --- a/indra/newview/llfloaterbuy.cpp +++ b/indra/newview/llfloaterbuy.cpp @@ -43,6 +43,7 @@ #include "llagent.h" // for agent id #include "llalertdialog.h" #include "llinventorymodel.h" // for gInventory +#include "llinventorydefines.h" #include "llinventoryview.h" // for get_item_icon #include "llselectmgr.h" #include "llscrolllistctrl.h" diff --git a/indra/newview/llfloaterbuycontents.cpp b/indra/newview/llfloaterbuycontents.cpp index f78ab995a..5cef261e5 100644 --- a/indra/newview/llfloaterbuycontents.cpp +++ b/indra/newview/llfloaterbuycontents.cpp @@ -46,6 +46,7 @@ #include "llalertdialog.h" #include "llcheckboxctrl.h" #include "llinventorymodel.h" // for gInventory +#include "llinventorydefines.h" #include "llinventoryview.h" // for get_item_icon #include "llselectmgr.h" #include "llscrolllistctrl.h" diff --git a/indra/newview/llfloaterproperties.cpp b/indra/newview/llfloaterproperties.cpp index 62ecd8faf..c9c8e0482 100644 --- a/indra/newview/llfloaterproperties.cpp +++ b/indra/newview/llfloaterproperties.cpp @@ -38,6 +38,7 @@ #include "llcachename.h" #include "lldbstrings.h" #include "llinventory.h" +#include "llinventorydefines.h" #include "llagent.h" #include "llbutton.h" diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index a7788044d..840f4070b 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -36,6 +36,7 @@ #include "llinventoryview.h" #include "llinventorybridge.h" +#include "llinventorydefines.h" #include "message.h" diff --git a/indra/newview/llinventoryview.cpp b/indra/newview/llinventoryview.cpp index 69fbc19cd..6b50d56ed 100644 --- a/indra/newview/llinventoryview.cpp +++ b/indra/newview/llinventoryview.cpp @@ -36,6 +36,7 @@ #include "llinventoryview.h" #include "llinventorybridge.h" +#include "llinventorydefines.h" #include "message.h" diff --git a/indra/newview/llpanelcontents.cpp b/indra/newview/llpanelcontents.cpp index 5ab510eed..b35b91b6c 100644 --- a/indra/newview/llpanelcontents.cpp +++ b/indra/newview/llpanelcontents.cpp @@ -45,6 +45,7 @@ #include "llpermissionsflags.h" #include "lleconomy.h" #include "material_codes.h" +#include "llinventorydefines.h" // project includes #include "llui.h" diff --git a/indra/newview/llpanelgroupnotices.cpp b/indra/newview/llpanelgroupnotices.cpp index 950f08699..25a21a7fd 100644 --- a/indra/newview/llpanelgroupnotices.cpp +++ b/indra/newview/llpanelgroupnotices.cpp @@ -39,6 +39,7 @@ #include "llinventory.h" #include "llviewerinventory.h" #include "llinventorymodel.h" +#include "llinventorydefines.h" #include "llinventoryview.h" #include "llagent.h" #include "lltooldraganddrop.h" diff --git a/indra/newview/llpanelinventory.cpp b/indra/newview/llpanelinventory.cpp index 8a1e7c112..5e090f009 100644 --- a/indra/newview/llpanelinventory.cpp +++ b/indra/newview/llpanelinventory.cpp @@ -50,6 +50,7 @@ #include "llfontgl.h" #include "llassetstorage.h" #include "llinventory.h" +#include "llinventorydefines.h" #include "llagent.h" #include "llcallbacklist.h" diff --git a/indra/newview/llpreview.cpp b/indra/newview/llpreview.cpp index ba1508f62..63742e917 100644 --- a/indra/newview/llpreview.cpp +++ b/indra/newview/llpreview.cpp @@ -36,6 +36,7 @@ #include "llpreview.h" #include "lllineeditor.h" #include "llinventory.h" +#include "llinventorydefines.h" #include "llinventorymodel.h" #include "llresmgr.h" #include "lltextbox.h" diff --git a/indra/newview/llpreviewgesture.cpp b/indra/newview/llpreviewgesture.cpp index 9dba4df0b..fdbd2ab22 100644 --- a/indra/newview/llpreviewgesture.cpp +++ b/indra/newview/llpreviewgesture.cpp @@ -39,6 +39,7 @@ // libraries #include "lldatapacker.h" #include "lldarray.h" +#include "llinventorydefines.h" #include "llstring.h" #include "lldir.h" #include "llmultigesture.h" diff --git a/indra/newview/llpreviewnotecard.cpp b/indra/newview/llpreviewnotecard.cpp index 642a75a91..df35fa406 100644 --- a/indra/newview/llpreviewnotecard.cpp +++ b/indra/newview/llpreviewnotecard.cpp @@ -35,6 +35,7 @@ #include "llpreviewnotecard.h" #include "llinventory.h" +#include "llinventorydefines.h" #include "llagent.h" #include "llagentcamera.h" diff --git a/indra/newview/llpreviewscript.cpp b/indra/newview/llpreviewscript.cpp index e4abac51d..ac9d720c5 100644 --- a/indra/newview/llpreviewscript.cpp +++ b/indra/newview/llpreviewscript.cpp @@ -40,6 +40,7 @@ #include "llcheckboxctrl.h" #include "llcombobox.h" #include "lldir.h" +#include "llinventorydefines.h" #include "llinventorymodel.h" #include "llkeyboard.h" #include "lllineeditor.h" diff --git a/indra/newview/lltooldraganddrop.cpp b/indra/newview/lltooldraganddrop.cpp index 5da60b8b1..424184983 100644 --- a/indra/newview/lltooldraganddrop.cpp +++ b/indra/newview/lltooldraganddrop.cpp @@ -49,6 +49,7 @@ #include "llhudeffecttrail.h" #include "llhudmanager.h" #include "llinventorybridge.h" +#include "llinventorydefines.h" #include "llinventorymodel.h" #include "llinventoryview.h" #include "llmutelist.h" diff --git a/indra/newview/lltracker.cpp b/indra/newview/lltracker.cpp index 299db5c1a..d5b66e61b 100644 --- a/indra/newview/lltracker.cpp +++ b/indra/newview/lltracker.cpp @@ -56,6 +56,7 @@ #include "llfloaterworldmap.h" #include "llhudtext.h" #include "llhudview.h" +#include "llinventorydefines.h" #include "llinventorymodel.h" #include "lllandmarklist.h" #include "llsky.h" diff --git a/indra/newview/llviewerinventory.cpp b/indra/newview/llviewerinventory.cpp index a1d157b7f..9fc0c8f9c 100644 --- a/indra/newview/llviewerinventory.cpp +++ b/indra/newview/llviewerinventory.cpp @@ -46,6 +46,7 @@ #include "llgesturemgr.h" #include "llinventorybridge.h" +#include "llinventorydefines.h" #include "llinventoryview.h" #include "llviewerregion.h" diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp index b03001dd4..49bc8d04a 100644 --- a/indra/newview/llviewermenu.cpp +++ b/indra/newview/llviewermenu.cpp @@ -167,6 +167,7 @@ #include "llimagebmp.h" #include "llimagej2c.h" #include "llimagetga.h" +#include "llinventorydefines.h" #include "llinventorymodel.h" #include "llinventoryview.h" #include "llkeyboard.h" diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index b01a9f51d..6b8ed1a4d 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -95,6 +95,7 @@ #include "llhudeffecttrail.h" #include "llhudmanager.h" #include "llimpanel.h" +#include "llinventorydefines.h" #include "llinventorymodel.h" #include "llinventoryview.h" #include "llmenugl.h" diff --git a/indra/newview/llviewerobject.cpp b/indra/newview/llviewerobject.cpp index 9b29944ff..311168c0e 100644 --- a/indra/newview/llviewerobject.cpp +++ b/indra/newview/llviewerobject.cpp @@ -45,6 +45,7 @@ #include "llfontgl.h" #include "llframetimer.h" #include "llinventory.h" +#include "llinventorydefines.h" #include "llmaterialtable.h" #include "llmutelist.h" #include "llnamevalue.h" diff --git a/indra/newview/llviewerobjectbackup.cpp b/indra/newview/llviewerobjectbackup.cpp index d3e41550b..35fa42c74 100644 --- a/indra/newview/llviewerobjectbackup.cpp +++ b/indra/newview/llviewerobjectbackup.cpp @@ -49,6 +49,7 @@ #include "llsdutil.h" #include "llsdutil_math.h" #include "lltransactiontypes.h" +#include "llinventorydefines.h" // newview includes #include "llagent.h" diff --git a/indra/newview/llviewertexteditor.cpp b/indra/newview/llviewertexteditor.cpp index a4590160e..2ec7cf396 100644 --- a/indra/newview/llviewertexteditor.cpp +++ b/indra/newview/llviewertexteditor.cpp @@ -36,6 +36,7 @@ #include "llaudioengine.h" #include "llagent.h" #include "llinventory.h" +#include "llinventorydefines.h" #include "llinventorymodel.h" #include "llinventoryview.h" #include "llinventorybridge.h" // for landmark prefix string