diff options
Diffstat (limited to 'indra/llcommon')
-rw-r--r-- | indra/llcommon/CMakeLists.txt | 2 | ||||
-rw-r--r-- | indra/llcommon/linden_common.h | 3 | ||||
-rw-r--r-- | indra/llcommon/llassettype.cpp | 27 | ||||
-rw-r--r-- | indra/llcommon/llassettype.h | 1 | ||||
-rw-r--r-- | indra/llcommon/llchat.h | 10 | ||||
-rw-r--r-- | indra/llcommon/lldate.cpp | 68 | ||||
-rw-r--r-- | indra/llcommon/lldate.h | 2 | ||||
-rw-r--r-- | indra/llcommon/llkeythrottle.h | 57 | ||||
-rw-r--r-- | indra/llcommon/llstat.cpp | 51 | ||||
-rw-r--r-- | indra/llcommon/llstat.h | 21 | ||||
-rw-r--r-- | indra/llcommon/llstring.cpp | 324 | ||||
-rw-r--r-- | indra/llcommon/llstring.h | 303 | ||||
-rw-r--r-- | indra/llcommon/llversionserver.h | 4 | ||||
-rw-r--r-- | indra/llcommon/llversionviewer.h | 2 | ||||
-rw-r--r-- | indra/llcommon/metapropertyt.h | 13 |
15 files changed, 532 insertions, 356 deletions
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index baf374ee38..1c84c9e21e 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -295,7 +295,7 @@ SET(llcommon_TEST_SOURCE_FILES LL_ADD_PROJECT_UNIT_TESTS(llcommon "${llcommon_TEST_SOURCE_FILES}") #set(TEST_DEBUG on) -set(test_libs llcommon ${LLCOMMON_LIBRARIES} ${WINDOWS_LIBRARIES}) +set(test_libs llcommon ${LLCOMMON_LIBRARIES} ${WINDOWS_LIBRARIES} ${GOOGLEMOCK_LIBRARIES}) # Have to treat lllazy test as an integration test until this issue is resolved: # https://jira.lindenlab.com/jira/browse/DEV-29456 LL_ADD_INTEGRATION_TEST(lllazy lllazy.cpp "${test_libs}") diff --git a/indra/llcommon/linden_common.h b/indra/llcommon/linden_common.h index d0ab5e969f..c2eb867795 100644 --- a/indra/llcommon/linden_common.h +++ b/indra/llcommon/linden_common.h @@ -81,7 +81,8 @@ #include "lldefs.h" #include "llerror.h" #include "llextendedstatus.h" -#include "llfasttimer.h" +// Don't do this, adds 15K lines of header code to every library file. +//#include "llfasttimer.h" #include "llfile.h" #include "llformat.h" diff --git a/indra/llcommon/llassettype.cpp b/indra/llcommon/llassettype.cpp index e595cc1f8b..78aa6f4f37 100644 --- a/indra/llcommon/llassettype.cpp +++ b/indra/llcommon/llassettype.cpp @@ -80,27 +80,27 @@ LLAssetDictionary::LLAssetDictionary() { // DESCRIPTION TYPE NAME HUMAN NAME CATEGORY NAME DRAG&DROP CAN LINK? PROTECTED? // |--------------------|-----------|-------------------|-------------------|---------------|-----------|-----------| - addEntry(LLAssetType::AT_TEXTURE, new AssetEntry("TEXTURE", "texture", "texture", "Textures", DAD_TEXTURE, FALSE, TRUE)); - addEntry(LLAssetType::AT_SOUND, new AssetEntry("SOUND", "sound", "sound", "Sounds", DAD_SOUND, FALSE, TRUE)); - addEntry(LLAssetType::AT_CALLINGCARD, new AssetEntry("CALLINGCARD", "callcard", "calling card", "Calling Cards", DAD_CALLINGCARD, FALSE, TRUE)); - addEntry(LLAssetType::AT_LANDMARK, new AssetEntry("LANDMARK", "landmark", "landmark", "Landmarks", DAD_LANDMARK, FALSE, TRUE)); - addEntry(LLAssetType::AT_SCRIPT, new AssetEntry("SCRIPT", "script", "legacy script", "Scripts", DAD_NONE, FALSE, TRUE)); + addEntry(LLAssetType::AT_TEXTURE, new AssetEntry("TEXTURE", "texture", "texture", "Textures", DAD_TEXTURE, TRUE, TRUE)); + addEntry(LLAssetType::AT_SOUND, new AssetEntry("SOUND", "sound", "sound", "Sounds", DAD_SOUND, TRUE, TRUE)); + addEntry(LLAssetType::AT_CALLINGCARD, new AssetEntry("CALLINGCARD", "callcard", "calling card", "Calling Cards", DAD_CALLINGCARD, TRUE, TRUE)); + addEntry(LLAssetType::AT_LANDMARK, new AssetEntry("LANDMARK", "landmark", "landmark", "Landmarks", DAD_LANDMARK, TRUE, TRUE)); + addEntry(LLAssetType::AT_SCRIPT, new AssetEntry("SCRIPT", "script", "legacy script", "Scripts", DAD_NONE, TRUE, TRUE)); addEntry(LLAssetType::AT_CLOTHING, new AssetEntry("CLOTHING", "clothing", "clothing", "Clothing", DAD_CLOTHING, TRUE, TRUE)); addEntry(LLAssetType::AT_OBJECT, new AssetEntry("OBJECT", "object", "object", "Objects", DAD_OBJECT, TRUE, TRUE)); - addEntry(LLAssetType::AT_NOTECARD, new AssetEntry("NOTECARD", "notecard", "note card", "Notecards", DAD_NOTECARD, FALSE, TRUE)); + addEntry(LLAssetType::AT_NOTECARD, new AssetEntry("NOTECARD", "notecard", "note card", "Notecards", DAD_NOTECARD, TRUE, TRUE)); addEntry(LLAssetType::AT_CATEGORY, new AssetEntry("CATEGORY", "category", "folder", "New Folder", DAD_CATEGORY, TRUE, TRUE)); addEntry(LLAssetType::AT_ROOT_CATEGORY, new AssetEntry("ROOT_CATEGORY", "root", "root", "Inventory", DAD_ROOT_CATEGORY, TRUE, TRUE)); - addEntry(LLAssetType::AT_LSL_TEXT, new AssetEntry("LSL_TEXT", "lsltext", "lsl2 script", "Scripts", DAD_SCRIPT, FALSE, TRUE)); - addEntry(LLAssetType::AT_LSL_BYTECODE, new AssetEntry("LSL_BYTECODE", "lslbyte", "lsl bytecode", "Scripts", DAD_NONE, FALSE, TRUE)); - addEntry(LLAssetType::AT_TEXTURE_TGA, new AssetEntry("TEXTURE_TGA", "txtr_tga", "tga texture", "Uncompressed Images", DAD_NONE, FALSE, TRUE)); + addEntry(LLAssetType::AT_LSL_TEXT, new AssetEntry("LSL_TEXT", "lsltext", "lsl2 script", "Scripts", DAD_SCRIPT, TRUE, TRUE)); + addEntry(LLAssetType::AT_LSL_BYTECODE, new AssetEntry("LSL_BYTECODE", "lslbyte", "lsl bytecode", "Scripts", DAD_NONE, TRUE, TRUE)); + addEntry(LLAssetType::AT_TEXTURE_TGA, new AssetEntry("TEXTURE_TGA", "txtr_tga", "tga texture", "Uncompressed Images", DAD_NONE, TRUE, TRUE)); addEntry(LLAssetType::AT_BODYPART, new AssetEntry("BODYPART", "bodypart", "body part", "Body Parts", DAD_BODYPART, TRUE, TRUE)); addEntry(LLAssetType::AT_TRASH, new AssetEntry("TRASH", "trash", "trash", "Trash", DAD_NONE, FALSE, TRUE)); addEntry(LLAssetType::AT_SNAPSHOT_CATEGORY, new AssetEntry("SNAPSHOT_CATEGORY", "snapshot", "snapshot", "Photo Album", DAD_NONE, FALSE, TRUE)); addEntry(LLAssetType::AT_LOST_AND_FOUND, new AssetEntry("LOST_AND_FOUND", "lstndfnd", "lost and found", "Lost And Found", DAD_NONE, FALSE, TRUE)); - addEntry(LLAssetType::AT_SOUND_WAV, new AssetEntry("SOUND_WAV", "snd_wav", "sound", "Uncompressed SoundS", DAD_NONE, FALSE, TRUE)); - addEntry(LLAssetType::AT_IMAGE_TGA, new AssetEntry("IMAGE_TGA", "img_tga", "targa image", "Uncompressed Images", DAD_NONE, FALSE, TRUE)); - addEntry(LLAssetType::AT_IMAGE_JPEG, new AssetEntry("IMAGE_JPEG", "jpeg", "jpeg image", "Uncompressed Images", DAD_NONE, FALSE, TRUE)); - addEntry(LLAssetType::AT_ANIMATION, new AssetEntry("ANIMATION", "animatn", "animation", "Animations", DAD_ANIMATION, FALSE, TRUE)); + addEntry(LLAssetType::AT_SOUND_WAV, new AssetEntry("SOUND_WAV", "snd_wav", "sound", "Uncompressed SoundS", DAD_NONE, TRUE, TRUE)); + addEntry(LLAssetType::AT_IMAGE_TGA, new AssetEntry("IMAGE_TGA", "img_tga", "targa image", "Uncompressed Images", DAD_NONE, TRUE, TRUE)); + addEntry(LLAssetType::AT_IMAGE_JPEG, new AssetEntry("IMAGE_JPEG", "jpeg", "jpeg image", "Uncompressed Images", DAD_NONE, TRUE, TRUE)); + addEntry(LLAssetType::AT_ANIMATION, new AssetEntry("ANIMATION", "animatn", "animation", "Animations", DAD_ANIMATION, TRUE, TRUE)); addEntry(LLAssetType::AT_GESTURE, new AssetEntry("GESTURE", "gesture", "gesture", "Gestures", DAD_GESTURE, TRUE, TRUE)); addEntry(LLAssetType::AT_SIMSTATE, new AssetEntry("SIMSTATE", "simstate", "simstate", "New Folder", DAD_NONE, FALSE, TRUE)); addEntry(LLAssetType::AT_FAVORITE, new AssetEntry("FAVORITE", "favorite", "favorite", "favorite", DAD_NONE, FALSE, TRUE)); @@ -289,6 +289,7 @@ bool LLAssetType::lookupIsEnsembleCategoryType(EType asset_type) asset_type <= AT_FOLDER_ENSEMBLE_END); } + // static. Generate a good default description void LLAssetType::generateDescriptionFor(LLAssetType::EType asset_type, std::string& description) diff --git a/indra/llcommon/llassettype.h b/indra/llcommon/llassettype.h index 8b29c8defa..33705cd2b1 100644 --- a/indra/llcommon/llassettype.h +++ b/indra/llcommon/llassettype.h @@ -150,6 +150,7 @@ public: AT_COUNT = 49,
+
// +*********************************************************+
// | TO ADD AN ELEMENT TO THIS ENUM: |
// +*********************************************************+
diff --git a/indra/llcommon/llchat.h b/indra/llcommon/llchat.h index 7b010d6739..acd0da61a4 100644 --- a/indra/llcommon/llchat.h +++ b/indra/llcommon/llchat.h @@ -65,6 +65,12 @@ typedef enum e_chat_audible_level CHAT_AUDIBLE_FULLY = 1 } EChatAudible; +typedef enum e_chat_style +{ + CHAT_STYLE_NORMAL, + CHAT_STYLE_IRC +}EChatStyle; + // A piece of chat class LLChat { @@ -79,7 +85,8 @@ public: mMuted(FALSE), mTime(0.0), mPosAgent(), - mURL() + mURL(), + mChatStyle(CHAT_STYLE_NORMAL) { } std::string mText; // UTF-8 line of text @@ -92,6 +99,7 @@ public: F64 mTime; // viewer only, seconds from viewer start LLVector3 mPosAgent; std::string mURL; + EChatStyle mChatStyle; }; #endif diff --git a/indra/llcommon/lldate.cpp b/indra/llcommon/lldate.cpp index 7bc9e16bc9..7c0ac6c554 100644 --- a/indra/llcommon/lldate.cpp +++ b/indra/llcommon/lldate.cpp @@ -38,7 +38,7 @@ #include "apr_time.h" #include <time.h> -#include <locale> +#include <locale.h> #include <string> #include <iomanip> #include <sstream> @@ -94,33 +94,34 @@ std::string LLDate::asRFC1123() const return toHTTPDateString (std::string ("%A, %d %b %Y %H:%M:%S GMT")); } +LLFastTimer::DeclareTimer FT_DATE_FORMAT("Date Format"); + std::string LLDate::toHTTPDateString (std::string fmt) const { - std::ostringstream stream; + LLFastTimer ft1(FT_DATE_FORMAT); + time_t locSeconds = (time_t) mSecondsSinceEpoch; struct tm * gmt = gmtime (&locSeconds); - - stream.imbue (std::locale(LLStringUtil::getLocale().c_str())); - toHTTPDateStream (stream, gmt, fmt); - return stream.str(); + return toHTTPDateString(gmt, fmt); } std::string LLDate::toHTTPDateString (tm * gmt, std::string fmt) { - std::ostringstream stream; - stream.imbue (std::locale(LLStringUtil::getLocale().c_str())); - toHTTPDateStream (stream, gmt, fmt); - return stream.str(); -} + LLFastTimer ft1(FT_DATE_FORMAT); -void LLDate::toHTTPDateStream(std::ostream& s, tm * gmt, std::string fmt) -{ - using namespace std; + // avoid calling setlocale() unnecessarily - it's expensive. + static std::string prev_locale = ""; + std::string this_locale = LLStringUtil::getLocale(); + if (this_locale != prev_locale) + { + setlocale(LC_TIME, this_locale.c_str()); + prev_locale = this_locale; + } - const char * pBeg = fmt.c_str(); - const char * pEnd = pBeg + fmt.length(); - const time_put<char>& tp = use_facet<time_put<char> >(s.getloc()); - tp.put (s, s, s.fill(), gmt, pBeg, pEnd); + // use strftime() as it appears to be faster than std::time_put + char buffer[128]; + strftime(buffer, 128, fmt.c_str(), gmt); + return std::string(buffer); } void LLDate::toStream(std::ostream& s) const @@ -154,6 +155,37 @@ void LLDate::toStream(std::ostream& s) const s << 'Z'; } +bool LLDate::split(S32 *year, S32 *month, S32 *day, S32 *hour, S32 *min, S32 *sec) const +{ + apr_time_t time = (apr_time_t)(mSecondsSinceEpoch * LL_APR_USEC_PER_SEC); + + apr_time_exp_t exp_time; + if (apr_time_exp_gmt(&exp_time, time) != APR_SUCCESS) + { + return false; + } + + if (year) + *year = exp_time.tm_year + 1900; + + if (month) + *month = exp_time.tm_mon + 1; + + if (day) + *day = exp_time.tm_mday; + + if (hour) + *hour = exp_time.tm_hour; + + if (min) + *min = exp_time.tm_min; + + if (sec) + *sec = exp_time.tm_sec; + + return true; +} + bool LLDate::fromString(const std::string& iso8601_date) { std::istringstream stream(iso8601_date); diff --git a/indra/llcommon/lldate.h b/indra/llcommon/lldate.h index 4dffaafc7d..1f14093390 100644 --- a/indra/llcommon/lldate.h +++ b/indra/llcommon/lldate.h @@ -84,9 +84,9 @@ public: std::string asString() const; std::string asRFC1123() const; void toStream(std::ostream&) const; + bool split(S32 *year, S32 *month = NULL, S32 *day = NULL, S32 *hour = NULL, S32 *min = NULL, S32 *sec = NULL) const; std::string toHTTPDateString (std::string fmt) const; static std::string toHTTPDateString (tm * gmt, std::string fmt); - static void toHTTPDateStream(std::ostream&, tm *, std::string); /** * @brief Set the date from an ISO-8601 string. * diff --git a/indra/llcommon/llkeythrottle.h b/indra/llcommon/llkeythrottle.h index 873f50a65e..7544ab1d11 100644 --- a/indra/llcommon/llkeythrottle.h +++ b/indra/llcommon/llkeythrottle.h @@ -118,6 +118,63 @@ public: THROTTLE_BLOCKED, // rate exceed, block key }; + F64 getActionCount(const T& id) + { + U64 now = 0; + if ( mIsRealtime ) + { + now = LLKeyThrottleImpl<T>::getTime(); + } + else + { + now = LLKeyThrottleImpl<T>::getFrame(); + } + + if (now >= (m.startTime + m.intervalLength)) + { + if (now < (m.startTime + 2 * m.intervalLength)) + { + // prune old data + delete m.prevMap; + m.prevMap = m.currMap; + m.currMap = new typename LLKeyThrottleImpl<T>::EntryMap; + + m.startTime += m.intervalLength; + } + else + { + // lots of time has passed, all data is stale + delete m.prevMap; + delete m.currMap; + m.prevMap = new typename LLKeyThrottleImpl<T>::EntryMap; + m.currMap = new typename LLKeyThrottleImpl<T>::EntryMap; + + m.startTime = now; + } + } + + U32 prevCount = 0; + + typename LLKeyThrottleImpl<T>::EntryMap::const_iterator prev = m.prevMap->find(id); + if (prev != m.prevMap->end()) + { + prevCount = prev->second.count; + } + + typename LLKeyThrottleImpl<T>::Entry& curr = (*m.currMap)[id]; + + // curr.count is the number of keys in + // this current 'time slice' from the beginning of it until now + // prevCount is the number of keys in the previous + // time slice scaled to be one full time slice back from the current + // (now) time. + + // compute current, windowed rate + F64 timeInCurrent = ((F64)(now - m.startTime) / m.intervalLength); + F64 averageCount = curr.count + prevCount * (1.0 - timeInCurrent); + return averageCount; + } + // call each time the key wants use State noteAction(const T& id, S32 weight = 1) { diff --git a/indra/llcommon/llstat.cpp b/indra/llcommon/llstat.cpp index 90dae11793..0bd2609f4a 100644 --- a/indra/llcommon/llstat.cpp +++ b/indra/llcommon/llstat.cpp @@ -43,7 +43,7 @@ // 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; @@ -130,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)) @@ -141,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 ) @@ -254,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(); } @@ -269,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); } } @@ -612,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) { @@ -630,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 diff --git a/indra/llcommon/llstat.h b/indra/llcommon/llstat.h index 64ea8e5b40..bd73c9a6bb 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; } diff --git a/indra/llcommon/llstring.cpp b/indra/llcommon/llstring.cpp index d7da40d645..8052da2450 100644 --- a/indra/llcommon/llstring.cpp +++ b/indra/llcommon/llstring.cpp @@ -42,7 +42,7 @@ #include <winnls.h> // for WideCharToMultiByte #endif -LLFastTimer::DeclareTimer STRING_LOCALIZATION("String Localization"); +LLFastTimer::DeclareTimer FT_STRING_FORMAT("String Format"); std::string ll_safe_string(const char* in) @@ -776,12 +776,12 @@ namespace LLStringFn // https://wiki.lindenlab.com/wiki/Unicode_Guidelines has details on // allowable code points for XML. Specifically, they are: // 0x09, 0x0a, 0x0d, and 0x20 on up. JC - std::string strip_invalid_xml(const std::string& input) + std::string strip_invalid_xml(const std::string& instr) { std::string output; - output.reserve( input.size() ); - std::string::const_iterator it = input.begin(); - while (it != input.end()) + output.reserve( instr.size() ); + std::string::const_iterator it = instr.begin(); + while (it != instr.end()) { // Must compare as unsigned for >= // Test most likely match first @@ -817,6 +817,320 @@ namespace LLStringFn } } +//////////////////////////////////////////////////////////// + +//static +template<> +void LLStringUtil::getTokens(const std::string& instr, std::vector<std::string >& tokens, const std::string& delims) +{ + std::string currToken; + std::string::size_type begIdx, endIdx; + + begIdx = instr.find_first_not_of (delims); + while (begIdx != std::string::npos) + { + endIdx = instr.find_first_of (delims, begIdx); + if (endIdx == std::string::npos) + { + endIdx = instr.length(); + } + + currToken = instr.substr(begIdx, endIdx - begIdx); + LLStringUtil::trim (currToken); + tokens.push_back(currToken); + begIdx = instr.find_first_not_of (delims, endIdx); + } +} + +template<> +LLStringUtil::size_type LLStringUtil::getSubstitution(const std::string& instr, size_type& start, std::vector<std::string>& tokens) +{ + const std::string delims (","); + + // Find the first ] + size_type pos2 = instr.find(']', start); + if (pos2 == std::string::npos) + return std::string::npos; + + // Find the last [ before ] + size_type pos1 = instr.find_last_of('[', pos2-1); + if (pos1 == std::string::npos || pos1 < start) + return std::string::npos; + + getTokens(std::string(instr,pos1+1,pos2-pos1-1), tokens, delims); + start = pos2+1; + + return pos1; +} + +// static +template<> +bool LLStringUtil::simpleReplacement(std::string &replacement, std::string token, const format_map_t& substitutions) +{ + // see if we have a replacement for the bracketed string (without the brackets) + // test first using has() because if we just look up with operator[] we get back an + // empty string even if the value is missing. We want to distinguish between + // missing replacements and deliberately empty replacement strings. + format_map_t::const_iterator iter = substitutions.find(token); + if (iter != substitutions.end()) + { + replacement = iter->second; + return true; + } + // if not, see if there's one WITH brackets + iter = substitutions.find(std::string("[" + token + "]")); + if (iter != substitutions.end()) + { + replacement = iter->second; + return true; + } + + return false; +} + +// static +template<> +bool LLStringUtil::simpleReplacement(std::string &replacement, std::string token, const LLSD& substitutions) +{ + // see if we have a replacement for the bracketed string (without the brackets) + // test first using has() because if we just look up with operator[] we get back an + // empty string even if the value is missing. We want to distinguish between + // missing replacements and deliberately empty replacement strings. + if (substitutions.has(token)) + { + replacement = substitutions[token].asString(); + return true; + } + // if not, see if there's one WITH brackets + else if (substitutions.has(std::string("[" + token + "]"))) + { + replacement = substitutions[std::string("[" + token + "]")].asString(); + return true; + } + + return false; +} + +// static +template<> +void LLStringUtil::formatNumber(std::string& numStr, std::string decimals) +{ + std::stringstream strStream; + S32 intDecimals = 0; + + convertToS32 (decimals, intDecimals); + if (!sLocale.empty()) + { + strStream.imbue (std::locale(sLocale.c_str())); + } + + if (!intDecimals) + { + S32 intStr; + + if (convertToS32(numStr, intStr)) + { + strStream << intStr; + numStr = strStream.str(); + } + } + else + { + F32 floatStr; + + if (convertToF32(numStr, floatStr)) + { + strStream << std::fixed << std::showpoint << std::setprecision(intDecimals) << floatStr; + numStr = strStream.str(); + } + } +} + +// static +template<> +bool LLStringUtil::formatDatetime(std::string& replacement, std::string token, + std::string param, S32 secFromEpoch) +{ + if (param == "local") // local + { + secFromEpoch -= LLStringOps::getLocalTimeOffset(); + } + else if (param != "utc") // slt + { + secFromEpoch -= LLStringOps::getSltOffset(); + } + + // if never fell into those two ifs above, param must be utc + if (secFromEpoch < 0) secFromEpoch = 0; + + LLDate * datetime = new LLDate((F64)secFromEpoch); + std::string code = LLStringOps::getDatetimeCode (token); + + // special case to handle timezone + if (code == "%Z") { + if (param == "utc") + replacement = "GMT"; + else if (param == "slt") + replacement = "SLT"; + else if (param != "local") // *TODO Vadim: not local? then what? + replacement = LLStringOps::getDaylightSavings() ? "PDT" : "PST"; + + return true; + } + replacement = datetime->toHTTPDateString(code); + + if (code.empty()) + { + return false; + } + else + { + return true; + } +} + +// LLStringUtil::format recogizes the following patterns. +// All substitutions *must* be encased in []'s in the input string. +// The []'s are optional in the substitution map. +// [FOO_123] +// [FOO,number,precision] +// [FOO,datetime,format] + + +// static +template<> +S32 LLStringUtil::format(std::string& s, const format_map_t& substitutions) +{ + LLFastTimer ft(FT_STRING_FORMAT); + S32 res = 0; + + std::string output; + std::vector<std::string> tokens; + + std::string::size_type start = 0; + std::string::size_type prev_start = 0; + std::string::size_type key_start = 0; + while ((key_start = getSubstitution(s, start, tokens)) != std::string::npos) + { + output += std::string(s, prev_start, key_start-prev_start); + prev_start = start; + + bool found_replacement = false; + std::string replacement; + + if (tokens.size() == 1) + { + found_replacement = simpleReplacement (replacement, tokens[0], substitutions); + } + else if (tokens[1] == "number") + { + std::string param = "0"; + + if (tokens.size() > 2) param = tokens[2]; + found_replacement = simpleReplacement (replacement, tokens[0], substitutions); + if (found_replacement) formatNumber (replacement, param); + } + else if (tokens[1] == "datetime") + { + std::string param; + if (tokens.size() > 2) param = tokens[2]; + + format_map_t::const_iterator iter = substitutions.find("datetime"); + if (iter != substitutions.end()) + { + S32 secFromEpoch = 0; + BOOL r = LLStringUtil::convertToS32(iter->second, secFromEpoch); + if (r) + { + found_replacement = formatDatetime(replacement, tokens[0], param, secFromEpoch); + } + } + } + + if (found_replacement) + { + output += replacement; + res++; + } + else + { + // we had no replacement, so leave the string we searched for so that it gets noticed by QA + // "hello [NAME_NOT_FOUND]" is output + output += std::string("[") + tokens[0] + std::string("]"); + } + tokens.clear(); + } + // send the remainder of the string (with no further matches for bracketed names) + output += std::string(s, start); + s = output; + return res; +} + +//static +template<> +S32 LLStringUtil::format(std::string& s, const LLSD& substitutions) +{ + LLFastTimer ft(FT_STRING_FORMAT); + S32 res = 0; + + if (!substitutions.isMap()) + { + return res; + } + + std::string output; + std::vector<std::string> tokens; + + std::string::size_type start = 0; + std::string::size_type prev_start = 0; + std::string::size_type key_start = 0; + while ((key_start = getSubstitution(s, start, tokens)) != std::string::npos) + { + output += std::string(s, prev_start, key_start-prev_start); + prev_start = start; + + bool found_replacement = false; + std::string replacement; + + if (tokens.size() == 1) + { + found_replacement = simpleReplacement (replacement, tokens[0], substitutions); + } + else if (tokens[1] == "number") + { + std::string param = "0"; + + if (tokens.size() > 2) param = tokens[2]; + found_replacement = simpleReplacement (replacement, tokens[0], substitutions); + if (found_replacement) formatNumber (replacement, param); + } + else if (tokens[1] == "datetime") + { + std::string param; + if (tokens.size() > 2) param = tokens[2]; + + S32 secFromEpoch = (S32) substitutions["datetime"].asInteger(); + found_replacement = formatDatetime (replacement, tokens[0], param, secFromEpoch); + } + + if (found_replacement) + { + output += replacement; + res++; + } + else + { + // we had no replacement, so leave the string we searched for so that it gets noticed by QA + // "hello [NAME_NOT_FOUND]" is output + output += std::string("[") + tokens[0] + std::string("]"); + } + tokens.clear(); + } + // send the remainder of the string (with no further matches for bracketed names) + output += std::string(s, start); + s = output; + return res; +} //////////////////////////////////////////////////////////// // Testing diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h index d2de499996..181d6fd33f 100644 --- a/indra/llcommon/llstring.h +++ b/indra/llcommon/llstring.h @@ -36,7 +36,6 @@ #include <string>
#include <locale>
#include <iomanip>
-#include <boost/regex.hpp>
#include "llsd.h"
#include "llfasttimer.h"
@@ -231,7 +230,7 @@ public: static std::basic_string<T> null;
typedef std::map<LLFormatMapString, LLFormatMapString> format_map_t;
- static void getTokens (std::basic_string<T> input, std::vector<std::basic_string<T> >& tokens);
+ static void getTokens(const std::basic_string<T>& instr, std::vector<std::basic_string<T> >& tokens, const std::basic_string<T>& delims);
static void formatNumber(std::basic_string<T>& numStr, std::basic_string<T> decimals);
static bool formatDatetime(std::basic_string<T>& replacement, std::basic_string<T> token, std::basic_string<T> param, S32 secFromEpoch);
static S32 format(std::basic_string<T>& s, const format_map_t& substitutions);
@@ -346,6 +345,8 @@ public: static void testHarness();
#endif
+private:
+ static size_type getSubstitution(const std::basic_string<T>& instr, size_type& start, std::vector<std::basic_string<T> >& tokens);
};
template<class T> std::basic_string<T> LLStringUtilBase<T>::null;
@@ -604,302 +605,12 @@ namespace LLStringFn }
////////////////////////////////////////////////////////////
+// NOTE: LLStringUtil::format, getTokens, and support functions moved to llstring.cpp.
+// There is no LLWStringUtil::format implementation currently.
+// Calling thse for anything other than LLStringUtil will produce link errors.
-//static
-template<class T>
-void LLStringUtilBase<T>::getTokens (std::basic_string<T> input, std::vector<std::basic_string<T> >& tokens)
-{
- const std::basic_string<T> delims (",");
- std::basic_string<T> currToken;
- size_type begIdx, endIdx;
-
- begIdx = input.find_first_not_of (delims);
- while (begIdx != std::basic_string<T>::npos)
- {
- endIdx = input.find_first_of (delims, begIdx);
- if (endIdx == std::basic_string<T>::npos)
- {
- endIdx = input.length();
- }
-
- currToken = input.substr(begIdx, endIdx - begIdx);
- trim (currToken);
- tokens.push_back(currToken);
- begIdx = input.find_first_not_of (delims, endIdx);
- }
-}
-
-extern LL_COMMON_API LLFastTimer::DeclareTimer STRING_LOCALIZATION;
-
-// static
-template<class T>
-S32 LLStringUtilBase<T>::format(std::basic_string<T>& s, const format_map_t& substitutions)
-{
- LLFastTimer ft(STRING_LOCALIZATION);
- S32 res = 0;
-
- std::basic_ostringstream<T> output;
- // match strings like [NAME,number,3]
- const boost::regex key("\\[((\\s)*([0-9_A-Za-z]+)((\\s)*,(\\s)*[0-9_A-Za-z\\s]*){0,2}(\\s)*)]");
-
-
- typename std::basic_string<T>::const_iterator start = s.begin();
- typename std::basic_string<T>::const_iterator end = s.end();
- boost::smatch match;
-
-
- while (boost::regex_search(start, end, match, key, boost::match_default))
- {
- bool found_replacement = false;
- std::vector<std::basic_string<T> > tokens;
- std::basic_string<T> replacement;
-
- getTokens (std::basic_string<T>(match[1].first, match[1].second), tokens);
-
- if (tokens.size() == 1)
- {
- found_replacement = simpleReplacement (replacement, tokens[0], substitutions);
- }
- else if (tokens[1] == "number")
- {
- std::basic_string<T> param = "0";
-
- if (tokens.size() > 2) param = tokens[2];
- found_replacement = simpleReplacement (replacement, tokens[0], substitutions);
- if (found_replacement) formatNumber (replacement, param);
- }
- else if (tokens[1] == "datetime")
- {
- std::basic_string<T> param;
- if (tokens.size() > 2) param = tokens[2];
-
- format_map_t::const_iterator iter = substitutions.find("datetime");
- if (iter != substitutions.end())
- {
- S32 secFromEpoch = 0;
- BOOL r = LLStringUtil::convertToS32(iter->second, secFromEpoch);
- if (r)
- {
- found_replacement = formatDatetime(replacement, tokens[0], param, secFromEpoch);
- }
- }
- }
-
- if (found_replacement)
- {
- output << std::basic_string<T>(start, match[0].first) << replacement;
- res++;
- }
- else
- {
- // we had no replacement, so leave the string we searched for so that it gets noticed by QA
- // "hello [NAME_NOT_FOUND]" is output
- output << std::basic_string<T>(start, match[0].second);
- }
-
- // update search position
- start = match[0].second;
- }
- // send the remainder of the string (with no further matches for bracketed names)
- output << std::basic_string<T>(start, end);
- s = output.str();
- return res;
-}
-
-//static
-template<class T>
-S32 LLStringUtilBase<T>::format(std::basic_string<T>& s, const LLSD& substitutions)
-{
- LLFastTimer ft(STRING_LOCALIZATION);
-
- S32 res = 0;
-
- if (!substitutions.isMap())
- {
- return res;
- }
-
- std::basic_ostringstream<T> output;
- // match strings like [NAME,number,3]
- const boost::regex key("\\[((\\s)*([0-9_A-Za-z]+)((\\s)*,(\\s)*[0-9_A-Za-z\\s]*){0,2}(\\s)*)]");
-
-
- typename std::basic_string<T>::const_iterator start = s.begin();
- typename std::basic_string<T>::const_iterator end = s.end();
- boost::smatch match;
-
-
- while (boost::regex_search(start, end, match, key, boost::match_default))
- {
- bool found_replacement = false;
- std::vector<std::basic_string<T> > tokens;
- std::basic_string<T> replacement;
-
- getTokens (std::basic_string<T>(match[1].first, match[1].second), tokens);
-
- if (tokens.size() == 1)
- {
- found_replacement = simpleReplacement (replacement, tokens[0], substitutions);
- }
- else if (tokens[1] == "number")
- {
- std::basic_string<T> param = "0";
-
- if (tokens.size() > 2) param = tokens[2];
- found_replacement = simpleReplacement (replacement, tokens[0], substitutions);
- if (found_replacement) formatNumber (replacement, param);
- }
- else if (tokens[1] == "datetime")
- {
- std::basic_string<T> param;
- if (tokens.size() > 2) param = tokens[2];
-
- S32 secFromEpoch = (S32) substitutions["datetime"].asInteger();
- found_replacement = formatDatetime (replacement, tokens[0], param, secFromEpoch);
- }
-
- if (found_replacement)
- {
- output << std::basic_string<T>(start, match[0].first) << replacement;
- res++;
- }
- else
- {
- // we had no replacement, so leave the string we searched for so that it gets noticed by QA
- // "hello [NAME_NOT_FOUND]" is output
- output << std::basic_string<T>(start, match[0].second);
- }
-
- // update search position
- start = match[0].second;
- }
- // send the remainder of the string (with no further matches for bracketed names)
- output << std::basic_string<T>(start, end);
- s = output.str();
- return res;
-}
-
-// static
-template<class T>
-bool LLStringUtilBase<T>::simpleReplacement(std::basic_string<T> &replacement, std::basic_string<T> token, const format_map_t& substitutions)
-{
- // see if we have a replacement for the bracketed string (without the brackets)
- // test first using has() because if we just look up with operator[] we get back an
- // empty string even if the value is missing. We want to distinguish between
- // missing replacements and deliberately empty replacement strings.
- format_map_t::const_iterator iter = substitutions.find(token);
- if (iter != substitutions.end())
- {
- replacement = iter->second;
- return true;
- }
- // if not, see if there's one WITH brackets
- iter = substitutions.find(std::basic_string<T>("[" + token + "]"));
- if (iter != substitutions.end())
- {
- replacement = iter->second;
- return true;
- }
-
- return false;
-}
-
-// static
-template<class T>
-bool LLStringUtilBase<T>::simpleReplacement(std::basic_string<T> &replacement, std::basic_string<T> token, const LLSD& substitutions)
-{
- // see if we have a replacement for the bracketed string (without the brackets)
- // test first using has() because if we just look up with operator[] we get back an
- // empty string even if the value is missing. We want to distinguish between
- // missing replacements and deliberately empty replacement strings.
- if (substitutions.has(token))
- {
- replacement = substitutions[token].asString();
- return true;
- }
- // if not, see if there's one WITH brackets
- else if (substitutions.has(std::basic_string<T>("[" + token + "]")))
- {
- replacement = substitutions[std::basic_string<T>("[" + token + "]")].asString();
- return true;
- }
-
- return false;
-}
-
-// static
-template<class T>
-void LLStringUtilBase<T>::formatNumber(std::basic_string<T>& numStr, std::basic_string<T> decimals)
-{
- typedef typename std::basic_string<T>::size_type string_size_type_t;
- std::basic_stringstream<T> strStream;
- S32 intDecimals = 0;
-
- convertToS32 (decimals, intDecimals);
- if (!sLocale.empty())
- {
- strStream.imbue (std::locale(sLocale.c_str()));
- }
-
- if (!intDecimals)
- {
- S32 intStr;
-
- if (convertToS32(numStr, intStr))
- {
- strStream << intStr;
- numStr = strStream.str();
- }
- }
- else
- {
- F32 floatStr;
-
- if (convertToF32(numStr, floatStr))
- {
- strStream << std::fixed << std::showpoint << std::setprecision(intDecimals) << floatStr;
- numStr = strStream.str();
- }
- }
-}
-
-// static
-template<class T>
-bool LLStringUtilBase<T>::formatDatetime(std::basic_string<T>& replacement, std::basic_string<T> token,
- std::basic_string<T> param, S32 secFromEpoch)
-{
- if (param == "local") // local
- {
- secFromEpoch -= LLStringOps::getLocalTimeOffset();
- }
- else if (param != "utc") // slt
- {
- secFromEpoch -= LLStringOps::getSltOffset();
- }
-
- // if never fell into those two ifs above, param must be utc
- if (secFromEpoch < 0) secFromEpoch = 0;
-
- LLDate * datetime = new LLDate((F64)secFromEpoch);
- std::string code = LLStringOps::getDatetimeCode (token);
-
- // special case to handle timezone
- if (code == "%Z") {
- if (param == "utc") replacement = "GMT";
- else if (param != "local") replacement = LLStringOps::getDaylightSavings()? "PDT" : "PST";
- return true;
- }
+////////////////////////////////////////////////////////////
- replacement = datetime->toHTTPDateString(code);
- if (code.empty())
- {
- return false;
- }
- else
- {
- return true;
- }
-}
// static
template<class T>
diff --git a/indra/llcommon/llversionserver.h b/indra/llcommon/llversionserver.h index e9e21cffb6..77a03879bf 100644 --- a/indra/llcommon/llversionserver.h +++ b/indra/llcommon/llversionserver.h @@ -34,9 +34,9 @@ #define LL_LLVERSIONSERVER_H const S32 LL_VERSION_MAJOR = 1; -const S32 LL_VERSION_MINOR = 29; +const S32 LL_VERSION_MINOR = 31; const S32 LL_VERSION_PATCH = 0; -const S32 LL_VERSION_BUILD = 2425; +const S32 LL_VERSION_BUILD = 2639; const char * const LL_CHANNEL = "Second Life Server"; diff --git a/indra/llcommon/llversionviewer.h b/indra/llcommon/llversionviewer.h index 04cf98ce19..ccea101cd6 100644 --- a/indra/llcommon/llversionviewer.h +++ b/indra/llcommon/llversionviewer.h @@ -36,7 +36,7 @@ const S32 LL_VERSION_MAJOR = 2; const S32 LL_VERSION_MINOR = 0; const S32 LL_VERSION_PATCH = 0; -const S32 LL_VERSION_BUILD = 2425; +const S32 LL_VERSION_BUILD = 2639; const char * const LL_CHANNEL = "Second Life 2009"; diff --git a/indra/llcommon/metapropertyt.h b/indra/llcommon/metapropertyt.h index 79a536a224..5ad230d1d5 100644 --- a/indra/llcommon/metapropertyt.h +++ b/indra/llcommon/metapropertyt.h @@ -94,6 +94,13 @@ inline const LLReflective* LLMetaPropertyT<LLUUID>::get(const LLReflective* obje } template <> +inline const LLReflective* LLMetaPropertyT<bool>::get(const LLReflective* object) const +{ + checkObjectClass(object); + return NULL; +} + +template <> inline LLSD LLMetaPropertyT<S32>::getLLSD(const LLReflective* object) const { return *(getProperty(object)); @@ -111,6 +118,12 @@ inline LLSD LLMetaPropertyT<LLUUID>::getLLSD(const LLReflective* object) const return *(getProperty(object)); } +template <> +inline LLSD LLMetaPropertyT<bool>::getLLSD(const LLReflective* object) const +{ + return *(getProperty(object)); +} + template<class TObject, class TProperty> class LLMetaPropertyTT : public LLMetaPropertyT<TProperty> { |