From 2c4358de39a402af6dd835b8479673863c4fa2cc Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Wed, 11 Oct 2023 15:08:38 +0200 Subject: SL-20370 Change PDT to SLT on menu bar --- indra/llcommon/llstring.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'indra/llcommon') diff --git a/indra/llcommon/llstring.cpp b/indra/llcommon/llstring.cpp index f6629803ee..f40e7ad45f 100644 --- a/indra/llcommon/llstring.cpp +++ b/indra/llcommon/llstring.cpp @@ -1235,9 +1235,17 @@ bool LLStringUtil::formatDatetime(std::string& replacement, std::string token, } else { +#if 0 + // EXT-1565 : Zai Lynch, James Linden : 15/Oct/09 + // [BSI] Feedback: Viewer clock mentions SLT, but would prefer it to show PST/PDT // "slt" = Second Life Time, which is deprecated. // If not utc or user local time, fallback to Pacific time replacement = LLStringOps::getPacificDaylightTime() ? "PDT" : "PST"; +#else + // SL-20370 : Steeltoe Linden : 29/Sep/23 + // Change "PDT" to "SLT" on menu bar + replacement = "SLT"; +#endif } return true; } -- cgit v1.2.3 From ddb2c93818fe1132116c6efaebc9bd3afd012187 Mon Sep 17 00:00:00 2001 From: Alexander Gavriliuk Date: Wed, 18 Oct 2023 11:02:51 +0200 Subject: SL-20463 Rename outfit dialog box accepts emoji characters --- indra/llcommon/llstring.cpp | 98 +++++++++++++++++++++++++++++++++++++++++++++ indra/llcommon/llstring.h | 7 ++++ 2 files changed, 105 insertions(+) (limited to 'indra/llcommon') diff --git a/indra/llcommon/llstring.cpp b/indra/llcommon/llstring.cpp index f40e7ad45f..9a2251e0a7 100644 --- a/indra/llcommon/llstring.cpp +++ b/indra/llcommon/llstring.cpp @@ -600,6 +600,7 @@ std::string mbcsstring_makeASCII(const std::string& wstr) } return out_str; } + std::string utf8str_removeCRLF(const std::string& utf8str) { if (0 == utf8str.length()) @@ -621,6 +622,43 @@ std::string utf8str_removeCRLF(const std::string& utf8str) return out; } +// Search for any emoji symbol, return true if found +bool wstring_has_emoji(const LLWString& wstr) +{ + for (const llwchar& wch : wstr) + { + if (LLStringOps::isEmoji(wch)) + return true; + } + + return false; +} + +// Cut emoji symbols if exist +bool wstring_remove_emojis(LLWString& wstr) +{ + bool found = false; + for (size_t i = 0; i < wstr.size(); ++i) + { + if (LLStringOps::isEmoji(wstr[i])) + { + wstr.erase(i--, 1); + found = true; + } + } + return found; +} + +// Cut emoji symbols if exist +bool utf8str_remove_emojis(std::string& utf8str) +{ + LLWString wstr = utf8str_to_wstring(utf8str); + if (!wstring_remove_emojis(wstr)) + return false; + utf8str = wstring_to_utf8str(wstr); + return true; +} + #if LL_WINDOWS unsigned int ll_wstring_default_code_page() { @@ -833,6 +871,66 @@ std::string LLStringOps::sDayFormat; std::string LLStringOps::sAM; std::string LLStringOps::sPM; +// static +bool LLStringOps::isEmoji(llwchar wch) +{ + // Most of the following symbols are not actually emoticons, but rather small pictures + + // 0x1F000 .. 0x1F02F - mahjong tiles + // https://symbl.cc/en/unicode/table/#mahjong-tiles + + // 0x1F030 .. 0x1F09F - domino tiles + // https://symbl.cc/en/unicode/table/#domino-tiles + + // 0x1F0A0 .. 0x1F0FF - playing cards + // https://symbl.cc/en/unicode/table/#playing-cards + + // 0x1F100 .. 0x1F1FF - enclosed alphanumeric supplement + // https://symbl.cc/en/unicode/table/#enclosed-alphanumeric-supplement + + // 0x1F200 .. 0x1F2FF - enclosed ideographic supplement + // https://symbl.cc/en/unicode/table/#enclosed-ideographic-supplement + + // 0x1F300 .. 0x1F5FF - miscellaneous symbols and pictographs + // https://symbl.cc/en/unicode/table/#miscellaneous-symbols-and-pictographs + + // 0x1F600 .. 0x1F64F - emoticons + // https://symbl.cc/en/unicode/table/#emoticons + + // 0x1F650 .. 0x1F67F - ornamental dingbats + // https://symbl.cc/en/unicode/table/#ornamental-dingbats + + // 0x1F680 .. 0x1F6FF - transport and map symbols + // https://symbl.cc/en/unicode/table/#transport-and-map-symbols + + // 0x1F700 .. 0x1F77F - alchemical symbols + // https://symbl.cc/en/unicode/table/#alchemical-symbols + + // 0x1F780 .. 0x1F7FF - geometric shapes extended + // https://symbl.cc/en/unicode/table/#geometric-shapes-extended + + // 0x1F800 .. 0x1F8FF - supplemental arrows c + // https://symbl.cc/en/unicode/table/#supplemental-arrows-c + + // 0x1F900 .. 0x1F9FF - supplemental symbols and pictographs + // https://symbl.cc/en/unicode/table/#supplemental-symbols-and-pictographs + + // 0x1FA00 .. 0x1FA6F - chess symbols + // https://symbl.cc/en/unicode/table/#chess-symbols + + // 0x1FA70 .. 0x1FAFF - symbols and pictographs extended a + // https://symbl.cc/en/unicode/table/#symbols-and-pictographs-extended-a + + // 0x1FB00 .. 0x1FBFF - symbols for legacy computing + // https://symbl.cc/en/unicode/table/#symbols-for-legacy-computing + + // 0x1FC00 .. 0x1FFFF - undefined block 44 + // These symbols aren't defined yet + // https://symbl.cc/en/unicode/table/#undefined-block-44 + + return wch >= 0x1F000 && wch < 0x1FC00; +} + S32 LLStringOps::collate(const llwchar* a, const llwchar* b) { diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h index 1fd6cac14a..6e70a6fa5c 100644 --- a/indra/llcommon/llstring.h +++ b/indra/llcommon/llstring.h @@ -189,6 +189,8 @@ public: static bool isAlnum(char a) { return isalnum((unsigned char)a) != 0; } static bool isAlnum(llwchar a) { return iswalnum(a) != 0; } + static bool isEmoji(llwchar wch); + static S32 collate(const char* a, const char* b) { return strcoll(a, b); } static S32 collate(const llwchar* a, const llwchar* b); @@ -737,6 +739,11 @@ LL_COMMON_API std::string mbcsstring_makeASCII(const std::string& str); LL_COMMON_API std::string utf8str_removeCRLF(const std::string& utf8str); +LL_COMMON_API bool wstring_has_emoji(const LLWString& wstr); + +LL_COMMON_API bool wstring_remove_emojis(LLWString& wstr); + +LL_COMMON_API bool utf8str_remove_emojis(std::string& utf8str); #if LL_WINDOWS /* @name Windows string helpers -- cgit v1.2.3 From 9bd1ef1cf82d7fcbbcd8d942cc355d47b1fbe47f Mon Sep 17 00:00:00 2001 From: Miezhiko Date: Tue, 31 Oct 2023 10:58:09 +0400 Subject: llmemory: use getrusage for getCurrentRSS on linux --- indra/llcommon/llmemory.cpp | 30 +++++++----------------------- 1 file changed, 7 insertions(+), 23 deletions(-) (limited to 'indra/llcommon') diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp index d6ae1284d3..aa6519ea44 100644 --- a/indra/llcommon/llmemory.cpp +++ b/indra/llcommon/llmemory.cpp @@ -37,6 +37,7 @@ # include #elif LL_LINUX # include +# include #endif #include "llmemory.h" @@ -228,33 +229,16 @@ U64 LLMemory::getCurrentRSS() U64 LLMemory::getCurrentRSS() { - static const char statPath[] = "/proc/self/stat"; - LLFILE *fp = LLFile::fopen(statPath, "r"); - U64 rss = 0; + struct rusage usage; - if (fp == NULL) - { - LL_WARNS() << "couldn't open " << statPath << LL_ENDL; + if (getrusage(RUSAGE_SELF, &usage) != 0) { + // Error handling code could be here return 0; } - // Eee-yew! See Documentation/filesystems/proc.txt in your - // nearest friendly kernel tree for details. - - { - int ret = fscanf(fp, "%*d (%*[^)]) %*c %*d %*d %*d %*d %*d %*d %*d " - "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %Lu", - &rss); - if (ret != 1) - { - LL_WARNS() << "couldn't parse contents of " << statPath << LL_ENDL; - rss = 0; - } - } - - fclose(fp); - - return rss; + // ru_maxrss (since Linux 2.6.32) + // This is the maximum resident set size used (in kilobytes). + return usage.ru_maxrss * 1024; } #else -- cgit v1.2.3 From a1fed466f0cc0c08d3cdcba88e02230c94e763b0 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 23 Nov 2023 00:57:46 +0200 Subject: SL-17434 Crash clearing LLEventPumps We actively use event pumps's connections in threads, make sure nothing modifies list of connections during reset. And in case this doesn't fix the issue list affected pump before it crashes to have a better idea of what is going on. --- indra/llcommon/llevents.cpp | 20 ++++++++++++++++++-- indra/llcommon/llevents.h | 5 +++-- 2 files changed, 21 insertions(+), 4 deletions(-) (limited to 'indra/llcommon') diff --git a/indra/llcommon/llevents.cpp b/indra/llcommon/llevents.cpp index 0a213bddef..aa9a258723 100644 --- a/indra/llcommon/llevents.cpp +++ b/indra/llcommon/llevents.cpp @@ -152,12 +152,21 @@ void LLEventPumps::clear() } } -void LLEventPumps::reset() +void LLEventPumps::reset(bool log_pumps) { // Reset every known LLEventPump instance. Leave it up to each instance to // decide what to do with the reset() call. + if (log_pumps) + { + LL_INFOS() << "Resetting " << (S32)mPumpMap.size() << " pumps" << LL_ENDL; + } + for (PumpMap::value_type& pair : mPumpMap) { + if (log_pumps) + { + LL_INFOS() << "Resetting pump " << pair.first << LL_ENDL; + } pair.second->reset(); } } @@ -314,9 +323,11 @@ std::string LLEventPump::inventName(const std::string& pfx) void LLEventPump::clear() { + LLMutexLock lock(&mConnectionListMutex); // Destroy the original LLStandardSignal instance, replacing it with a // whole new one. mSignal = std::make_shared(); + mConnections.clear(); } @@ -324,6 +335,7 @@ void LLEventPump::reset() { // Resetting mSignal is supposed to disconnect everything on its own // But due to crash on 'reset' added explicit cleanup to get more data + LLMutexLock lock(&mConnectionListMutex); ConnectionMap::const_iterator iter = mConnections.begin(); ConnectionMap::const_iterator end = mConnections.end(); while (iter!=end) @@ -348,6 +360,8 @@ LLBoundListener LLEventPump::listen_impl(const std::string& name, const LLEventL return LLBoundListener(); } + LLMutexLock lock(&mConnectionListMutex); + float nodePosition = 1.0; // if the supplied name is empty we are not interested in the ordering mechanism @@ -507,8 +521,9 @@ LLBoundListener LLEventPump::listen_impl(const std::string& name, const LLEventL return bound; } -LLBoundListener LLEventPump::getListener(const std::string& name) const +LLBoundListener LLEventPump::getListener(const std::string& name) { + LLMutexLock lock(&mConnectionListMutex); ConnectionMap::const_iterator found = mConnections.find(name); if (found != mConnections.end()) { @@ -520,6 +535,7 @@ LLBoundListener LLEventPump::getListener(const std::string& name) const void LLEventPump::stopListening(const std::string& name) { + LLMutexLock lock(&mConnectionListMutex); ConnectionMap::iterator found = mConnections.find(name); if (found != mConnections.end()) { diff --git a/indra/llcommon/llevents.h b/indra/llcommon/llevents.h index ae6e5aabc9..b5c4e58c9c 100644 --- a/indra/llcommon/llevents.h +++ b/indra/llcommon/llevents.h @@ -293,7 +293,7 @@ public: * Reset all known LLEventPump instances * workaround for DEV-35406 crash on shutdown */ - void reset(); + void reset(bool log_pumps = false); private: friend class LLEventPump; @@ -519,7 +519,7 @@ public: /// Get the LLBoundListener associated with the passed name (dummy /// LLBoundListener if not found) - virtual LLBoundListener getListener(const std::string& name) const; + virtual LLBoundListener getListener(const std::string& name); /** * Instantiate one of these to block an existing connection: * @code @@ -562,6 +562,7 @@ private: LLHandle mRegistry; std::string mName; + LLMutex mConnectionListMutex; protected: virtual LLBoundListener listen_impl(const std::string& name, const LLEventListener&, -- cgit v1.2.3 From 51088cde7f5a0bdaf9249bfdd5d31b9b212403ab Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Wed, 3 Jan 2024 22:57:28 +0200 Subject: SL-17896 Don't crash silently if files are missing or out of memory Under debug LL_ERRS will show a message as well, but release won't show anything and will quit silently so show a notification when applicable. --- indra/llcommon/llcoros.cpp | 1 + indra/llcommon/llerror.cpp | 42 ++++++++++++++++++++++++++++++++++++++++++ indra/llcommon/llerror.h | 23 +++++++++++++++++++++++ indra/llcommon/llexception.cpp | 1 + 4 files changed, 67 insertions(+) (limited to 'indra/llcommon') diff --git a/indra/llcommon/llcoros.cpp b/indra/llcommon/llcoros.cpp index 3ab97b557f..1d383f174d 100644 --- a/indra/llcommon/llcoros.cpp +++ b/indra/llcommon/llcoros.cpp @@ -278,6 +278,7 @@ std::string LLCoros::launch(const std::string& prefix, const callable_t& callabl catch (std::bad_alloc&) { // Out of memory on stack allocation? + LLError::LLUserWarningMsg::showOutOfMemory(); printActiveCoroutines(); LL_ERRS("LLCoros") << "Bad memory allocation in LLCoros::launch(" << prefix << ")!" << LL_ENDL; } diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp index 414515854a..3de641fcba 100644 --- a/indra/llcommon/llerror.cpp +++ b/indra/llcommon/llerror.cpp @@ -1601,6 +1601,48 @@ namespace LLError { return out << boost::stacktrace::stacktrace(); } + + // LLOutOfMemoryWarning + std::string LLUserWarningMsg::sLocalizedOutOfMemoryTitle; + std::string LLUserWarningMsg::sLocalizedOutOfMemoryWarning; + LLUserWarningMsg::Handler LLUserWarningMsg::sHandler; + + void LLUserWarningMsg::show(const std::string& message) + { + if (sHandler) + { + sHandler(std::string(), message); + } + } + + void LLUserWarningMsg::showOutOfMemory() + { + if (sHandler && !sLocalizedOutOfMemoryTitle.empty()) + { + sHandler(sLocalizedOutOfMemoryTitle, sLocalizedOutOfMemoryWarning); + } + } + + void LLUserWarningMsg::showMissingFiles() + { + // Files Are missing, likely can't localize. + const std::string error_string = + "Second Life viewer couldn't access some of the files it needs and will be closed." + "\n\nPlease reinstall viewer from https://secondlife.com/support/downloads/ and " + "contact https://support.secondlife.com if issue persists after reinstall."; + sHandler("Missing Files", error_string); + } + + void LLUserWarningMsg::setHandler(const LLUserWarningMsg::Handler &handler) + { + sHandler = handler; + } + + void LLUserWarningMsg::setOutOfMemoryStrings(const std::string& title, const std::string& message) + { + sLocalizedOutOfMemoryTitle = title; + sLocalizedOutOfMemoryWarning = message; + } } void crashdriver(void (*callback)(int*)) diff --git a/indra/llcommon/llerror.h b/indra/llcommon/llerror.h index 05dd88ee51..6f6b349cf5 100644 --- a/indra/llcommon/llerror.h +++ b/indra/llcommon/llerror.h @@ -39,6 +39,7 @@ #include "llpreprocessor.h" #include +#include // std::function const int LL_ERR_NOERR = 0; @@ -301,6 +302,28 @@ namespace LLError { friend std::ostream& operator<<(std::ostream& out, const LLStacktrace&); }; + + // Provides access to OS notification popup on error, since + // not everything has access to OS's messages + class LLUserWarningMsg + { + public: + typedef std::function Handler; + static void setHandler(const Handler&); + static void setOutOfMemoryStrings(const std::string& title, const std::string& message); + + // When viewer encounters bad alloc or can't access files try warning user about reasons + static void showOutOfMemory(); + static void showMissingFiles(); + // Genering error + static void show(const std::string&); + + private: + // needs to be preallocated before viewer runs out of memory + static std::string sLocalizedOutOfMemoryTitle; + static std::string sLocalizedOutOfMemoryWarning; + static Handler sHandler; + }; } //this is cheaper than llcallstacks if no need to output other variables to call stacks. diff --git a/indra/llcommon/llexception.cpp b/indra/llcommon/llexception.cpp index 46560b5e4c..0787bde57f 100644 --- a/indra/llcommon/llexception.cpp +++ b/indra/llcommon/llexception.cpp @@ -37,6 +37,7 @@ #include "llerror.h" #include "llerrorcontrol.h" + // used to attach and extract stacktrace information to/from boost::exception, // see https://www.boost.org/doc/libs/release/doc/html/stacktrace/getting_started.html#stacktrace.getting_started.exceptions_with_stacktrace // apparently the struct passed as the first template param needs no definition? -- cgit v1.2.3 From 7c8907522fe6600918dacc15ee138ca72b2cf35e Mon Sep 17 00:00:00 2001 From: AiraYumi Date: Sat, 6 Jan 2024 23:29:06 +0900 Subject: replace boost library to standard --- indra/llcommon/lldoubledispatch.h | 2 +- indra/llcommon/llerror.cpp | 8 +++---- indra/llcommon/llerrorcontrol.h | 2 +- indra/llcommon/llinitparam.h | 2 +- indra/llcommon/llleap.cpp | 4 ++-- indra/llcommon/llprocess.h | 2 +- indra/llcommon/llrun.h | 2 +- indra/llcommon/llstring.h | 2 +- indra/llcommon/tests/llerror_test.cpp | 30 ++++++++++++------------- indra/llcommon/tests/lleventcoro_test.cpp | 8 +++---- indra/llcommon/tests/llinstancetracker_test.cpp | 4 ++-- indra/llcommon/tests/wrapllerrs.h | 4 ++-- 12 files changed, 35 insertions(+), 35 deletions(-) (limited to 'indra/llcommon') diff --git a/indra/llcommon/lldoubledispatch.h b/indra/llcommon/lldoubledispatch.h index 8ed295b6f1..ce6731e864 100644 --- a/indra/llcommon/lldoubledispatch.h +++ b/indra/llcommon/lldoubledispatch.h @@ -255,7 +255,7 @@ private: }; /// shared_ptr manages Entry lifespan for us - typedef boost::shared_ptr EntryPtr; + typedef std::shared_ptr EntryPtr; /// use a @c list to make it easy to insert typedef std::list DispatchTable; DispatchTable mDispatch; diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp index 414515854a..4268f107e9 100644 --- a/indra/llcommon/llerror.cpp +++ b/indra/llcommon/llerror.cpp @@ -1070,7 +1070,7 @@ namespace LLError // // NOTE!!! Requires external mutex lock!!! template - std::pair, Recorders::iterator> + std::pair, Recorders::iterator> findRecorderPos(SettingsConfigPtr &s) { // Since we promise to return an iterator, use a classic iterator @@ -1081,7 +1081,7 @@ namespace LLError // *it is a RecorderPtr, a shared_ptr. Use a // dynamic_pointer_cast to try to downcast to test if it's also a // shared_ptr. - auto ptr = boost::dynamic_pointer_cast(*it); + auto ptr = std::dynamic_pointer_cast(*it); if (ptr) { // found the entry we want @@ -1101,7 +1101,7 @@ namespace LLError // shared_ptr might be empty (operator!() returns true) if there was no // such RECORDER subclass instance in mRecorders. template - boost::shared_ptr findRecorder() + std::shared_ptr findRecorder() { SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); LLMutexLock lock(&s->mRecorderMutex); @@ -1134,7 +1134,7 @@ namespace LLError if (!file_name.empty()) { - boost::shared_ptr recordToFile(new RecordToFile(file_name)); + std::shared_ptr recordToFile(new RecordToFile(file_name)); if (recordToFile->okay()) { addRecorder(recordToFile); diff --git a/indra/llcommon/llerrorcontrol.h b/indra/llcommon/llerrorcontrol.h index 57f10b7895..77b187a80f 100644 --- a/indra/llcommon/llerrorcontrol.h +++ b/indra/llcommon/llerrorcontrol.h @@ -174,7 +174,7 @@ namespace LLError bool mWantsMultiline; }; - typedef boost::shared_ptr RecorderPtr; + typedef std::shared_ptr RecorderPtr; /** * Instantiate GenericRecorder with a callable(level, message) to get diff --git a/indra/llcommon/llinitparam.h b/indra/llcommon/llinitparam.h index 9edc7e40f3..e0d0ab9ac7 100644 --- a/indra/llcommon/llinitparam.h +++ b/indra/llcommon/llinitparam.h @@ -627,7 +627,7 @@ namespace LLInitParam UserData* mUserData; }; - typedef boost::shared_ptr ParamDescriptorPtr; + typedef std::shared_ptr ParamDescriptorPtr; // each derived Block class keeps a static data structure maintaining offsets to various params class LL_COMMON_API BlockDescriptor diff --git a/indra/llcommon/llleap.cpp b/indra/llcommon/llleap.cpp index 8f88e728ce..b2b1162f63 100644 --- a/indra/llcommon/llleap.cpp +++ b/indra/llcommon/llleap.cpp @@ -462,10 +462,10 @@ private: LLProcessPtr mChild; LLTempBoundListener mStdinConnection, mStdoutConnection, mStdoutDataConnection, mStderrConnection; - boost::scoped_ptr mBlocker; + std::unique_ptr mBlocker; LLProcess::ReadPipe::size_type mExpect; LLError::RecorderPtr mRecorder; - boost::scoped_ptr mListener; + std::unique_ptr mListener; }; // These must follow the declaration of LLLeapImpl, so they may as well be last. diff --git a/indra/llcommon/llprocess.h b/indra/llcommon/llprocess.h index 0842f2eb07..c57821bf52 100644 --- a/indra/llcommon/llprocess.h +++ b/indra/llcommon/llprocess.h @@ -51,7 +51,7 @@ class LLEventPump; class LLProcess; /// LLProcess instances are created on the heap by static factory methods and /// managed by ref-counted pointers. -typedef boost::shared_ptr LLProcessPtr; +typedef std::shared_ptr LLProcessPtr; /** * LLProcess handles launching an external process with specified command line diff --git a/indra/llcommon/llrun.h b/indra/llcommon/llrun.h index d610f86234..42e3d9b47a 100644 --- a/indra/llcommon/llrun.h +++ b/indra/llcommon/llrun.h @@ -48,7 +48,7 @@ public: /** * @brief The pointer to a runnable. */ - typedef boost::shared_ptr run_ptr_t; + typedef std::shared_ptr run_ptr_t; /** * @brief The handle for use in the API. diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h index 1fd6cac14a..61fc47e4d0 100644 --- a/indra/llcommon/llstring.h +++ b/indra/llcommon/llstring.h @@ -1199,7 +1199,7 @@ void LLStringUtilBase::getTokens(const string_type& string, std::vector > instrp; + std::unique_ptr< LLStringUtilBaseImpl::InString > instrp; if (escapes.empty()) instrp.reset(new LLStringUtilBaseImpl::InString(string.begin(), string.end())); else diff --git a/indra/llcommon/tests/llerror_test.cpp b/indra/llcommon/tests/llerror_test.cpp index 148c18aabe..b4cdbdc6bf 100644 --- a/indra/llcommon/tests/llerror_test.cpp +++ b/indra/llcommon/tests/llerror_test.cpp @@ -153,27 +153,27 @@ namespace tut int countMessages() { - return boost::dynamic_pointer_cast(mRecorder)->countMessages(); + return std::dynamic_pointer_cast(mRecorder)->countMessages(); } void clearMessages() { - boost::dynamic_pointer_cast(mRecorder)->clearMessages(); + std::dynamic_pointer_cast(mRecorder)->clearMessages(); } void setWantsTime(bool t) { - boost::dynamic_pointer_cast(mRecorder)->showTime(t); + std::dynamic_pointer_cast(mRecorder)->showTime(t); } void setWantsMultiline(bool t) { - boost::dynamic_pointer_cast(mRecorder)->showMultiline(t); + std::dynamic_pointer_cast(mRecorder)->showMultiline(t); } std::string message(int n) { - return boost::dynamic_pointer_cast(mRecorder)->message(n); + return std::dynamic_pointer_cast(mRecorder)->message(n); } void ensure_message_count(int expectedCount) @@ -497,12 +497,12 @@ namespace void testLogName(LLError::RecorderPtr recorder, LogFromFunction f, const std::string& class_name = "") { - boost::dynamic_pointer_cast(recorder)->clearMessages(); + std::dynamic_pointer_cast(recorder)->clearMessages(); std::string name = f(false); f(true); - std::string messageWithoutName = boost::dynamic_pointer_cast(recorder)->message(0); - std::string messageWithName = boost::dynamic_pointer_cast(recorder)->message(1); + std::string messageWithoutName = std::dynamic_pointer_cast(recorder)->message(0); + std::string messageWithName = std::dynamic_pointer_cast(recorder)->message(1); ensure_has(name + " logged without name", messageWithoutName, name); @@ -691,13 +691,13 @@ namespace tut LL_INFOS() << "boo" << LL_ENDL; ensure_message_field_equals(0, MSG_FIELD, "boo"); - ensure_equals("alt recorder count", boost::dynamic_pointer_cast(altRecorder)->countMessages(), 1); - ensure_contains("alt recorder message 0", boost::dynamic_pointer_cast(altRecorder)->message(0), "boo"); + ensure_equals("alt recorder count", std::dynamic_pointer_cast(altRecorder)->countMessages(), 1); + ensure_contains("alt recorder message 0", std::dynamic_pointer_cast(altRecorder)->message(0), "boo"); LLError::setTimeFunction(roswell); LLError::RecorderPtr anotherRecorder(new TestRecorder()); - boost::dynamic_pointer_cast(anotherRecorder)->showTime(true); + std::dynamic_pointer_cast(anotherRecorder)->showTime(true); LLError::addRecorder(anotherRecorder); LL_INFOS() << "baz" << LL_ENDL; @@ -705,10 +705,10 @@ namespace tut std::string when = roswell(); ensure_message_does_not_contain(1, when); - ensure_equals("alt recorder count", boost::dynamic_pointer_cast(altRecorder)->countMessages(), 2); - ensure_does_not_contain("alt recorder message 1", boost::dynamic_pointer_cast(altRecorder)->message(1), when); - ensure_equals("another recorder count", boost::dynamic_pointer_cast(anotherRecorder)->countMessages(), 1); - ensure_contains("another recorder message 0", boost::dynamic_pointer_cast(anotherRecorder)->message(0), when); + ensure_equals("alt recorder count", std::dynamic_pointer_cast(altRecorder)->countMessages(), 2); + ensure_does_not_contain("alt recorder message 1", std::dynamic_pointer_cast(altRecorder)->message(1), when); + ensure_equals("another recorder count", std::dynamic_pointer_cast(anotherRecorder)->countMessages(), 1); + ensure_contains("another recorder message 0", std::dynamic_pointer_cast(anotherRecorder)->message(0), when); LLError::removeRecorder(altRecorder); LLError::removeRecorder(anotherRecorder); diff --git a/indra/llcommon/tests/lleventcoro_test.cpp b/indra/llcommon/tests/lleventcoro_test.cpp index 032923a108..01104545c6 100644 --- a/indra/llcommon/tests/lleventcoro_test.cpp +++ b/indra/llcommon/tests/lleventcoro_test.cpp @@ -101,7 +101,7 @@ namespace tut int which; LLTestApp testApp; - void explicit_wait(boost::shared_ptr>& cbp); + void explicit_wait(std::shared_ptr>& cbp); void waitForEventOn1(); void coroPump(); void postAndWait1(); @@ -111,7 +111,7 @@ namespace tut typedef coroutine_group::object object; coroutine_group coroutinegrp("coroutine"); - void test_data::explicit_wait(boost::shared_ptr>& cbp) + void test_data::explicit_wait(std::shared_ptr>& cbp) { BEGIN { @@ -127,7 +127,7 @@ namespace tut // For test purposes, instead of handing 'callback' (or an // adapter) off to some I/O subsystem, we'll just pass it back to // our caller. - cbp = boost::make_shared>(); + cbp = std::make_shared>(); LLCoros::Future future = LLCoros::getFuture(*cbp); // calling get() on the future causes us to suspend @@ -146,7 +146,7 @@ namespace tut DEBUG; // Construct the coroutine instance that will run explicit_wait. - boost::shared_ptr> respond; + std::shared_ptr> respond; LLCoros::instance().launch("test<1>", [this, &respond](){ explicit_wait(respond); }); mSync.bump(); diff --git a/indra/llcommon/tests/llinstancetracker_test.cpp b/indra/llcommon/tests/llinstancetracker_test.cpp index 5daa29adf4..95af9c2a50 100644 --- a/indra/llcommon/tests/llinstancetracker_test.cpp +++ b/indra/llcommon/tests/llinstancetracker_test.cpp @@ -94,7 +94,7 @@ namespace tut ensure("couldn't find stack Keyed", bool(found)); ensure_equals("found wrong Keyed instance", found.get(), &one); { - boost::scoped_ptr two(new Keyed("two")); + std::unique_ptr two(new Keyed("two")); ensure_equals(Keyed::instanceCount(), 2); auto found = Keyed::getInstance("two"); ensure("couldn't find heap Keyed", bool(found)); @@ -118,7 +118,7 @@ namespace tut std::weak_ptr found = one.getWeak(); ensure(! found.expired()); { - boost::scoped_ptr two(new Unkeyed); + std::unique_ptr two(new Unkeyed); ensure_equals(Unkeyed::instanceCount(), 2); } ensure_equals(Unkeyed::instanceCount(), 1); diff --git a/indra/llcommon/tests/wrapllerrs.h b/indra/llcommon/tests/wrapllerrs.h index d657b329bb..6978c296b3 100644 --- a/indra/llcommon/tests/wrapllerrs.h +++ b/indra/llcommon/tests/wrapllerrs.h @@ -218,12 +218,12 @@ public: /// for the sought string. std::string messageWith(const std::string& search, bool required=true) { - return boost::dynamic_pointer_cast(mRecorder)->messageWith(search, required); + return std::dynamic_pointer_cast(mRecorder)->messageWith(search, required); } std::ostream& streamto(std::ostream& out) const { - return boost::dynamic_pointer_cast(mRecorder)->streamto(out); + return std::dynamic_pointer_cast(mRecorder)->streamto(out); } friend inline std::ostream& operator<<(std::ostream& out, const CaptureLog& self) -- cgit v1.2.3 From ba74152c823563a66729ea0a7fb7cab5bf58980d Mon Sep 17 00:00:00 2001 From: Ansariel Date: Tue, 9 Jan 2024 00:16:52 +0100 Subject: Replace BOOST_FOREACH with standard C++ range-based for-loops --- indra/llcommon/llprocess.cpp | 9 ++++----- indra/llcommon/llsdutil.h | 6 +++--- indra/llcommon/llsingleton.cpp | 3 +-- indra/llcommon/llsys.cpp | 10 ++++------ indra/llcommon/tests/llprocess_test.cpp | 5 ++--- indra/llcommon/tests/llstreamqueue_test.cpp | 9 +++------ indra/llcommon/tests/lltreeiterators_test.cpp | 23 +++++++++++------------ 7 files changed, 28 insertions(+), 37 deletions(-) (limited to 'indra/llcommon') diff --git a/indra/llcommon/llprocess.cpp b/indra/llcommon/llprocess.cpp index 0d65762284..0d6a147da3 100644 --- a/indra/llcommon/llprocess.cpp +++ b/indra/llcommon/llprocess.cpp @@ -36,7 +36,6 @@ #include "llevents.h" #include "llexception.h" -#include #include #include #include @@ -587,7 +586,7 @@ LLProcess::LLProcess(const LLSDOrParams& params): // apr_procattr_child_err_set()), or accepting a filename, opening it and // passing that apr_file_t (simple <, >, 2> redirect emulation). std::vector select; - BOOST_FOREACH(const FileParam& fparam, params.files) + for (const FileParam& fparam : params.files) { // Every iteration, we're going to append an item to 'select'. At the // top of the loop, its size() is, in effect, an index. Use that to @@ -684,7 +683,7 @@ LLProcess::LLProcess(const LLSDOrParams& params): argv.push_back(params.executable().c_str()); // Add arguments. See above remarks about c_str(). - BOOST_FOREACH(const std::string& arg, params.args) + for (const std::string& arg : params.args) { argv.push_back(arg.c_str()); } @@ -961,7 +960,7 @@ void LLProcess::handle_status(int reason, int status) // only be performed if in fact we're going to produce the log message. LL_DEBUGS("LLProcess") << empty; std::string reason_str; - BOOST_FOREACH(const ReasonCode& rcp, reasons) + for (const ReasonCode& rcp : reasons) { if (reason == rcp.code) { @@ -1151,7 +1150,7 @@ std::ostream& operator<<(std::ostream& out, const LLProcess::Params& params) out << "cd " << LLStringUtil::quote(params.cwd) << ": "; } out << LLStringUtil::quote(params.executable); - BOOST_FOREACH(const std::string& arg, params.args) + for (const std::string& arg : params.args) { out << ' ' << LLStringUtil::quote(arg); } diff --git a/indra/llcommon/llsdutil.h b/indra/llcommon/llsdutil.h index ad54d1b0be..fdcc052bd0 100644 --- a/indra/llcommon/llsdutil.h +++ b/indra/llcommon/llsdutil.h @@ -478,9 +478,9 @@ namespace llsd { /***************************************************************************** -* BOOST_FOREACH() helpers for LLSD +* range-based for-loop helpers for LLSD *****************************************************************************/ -/// Usage: BOOST_FOREACH(LLSD item, inArray(someLLSDarray)) { ... } +/// Usage: for (LLSD item : inArray(someLLSDarray)) { ... } class inArray { public: @@ -503,7 +503,7 @@ private: /// 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)) { ... } +/// Usage: for([const] MapEntry& e : inMap(someLLSDmap)) { ... } class inMap { public: diff --git a/indra/llcommon/llsingleton.cpp b/indra/llcommon/llsingleton.cpp index 6b1986d0e9..5f1a89670e 100644 --- a/indra/llcommon/llsingleton.cpp +++ b/indra/llcommon/llsingleton.cpp @@ -32,7 +32,6 @@ #include "lldependencies.h" #include "llexception.h" #include "llcoros.h" -#include #include #include // std::cerr in dire emergency #include @@ -411,7 +410,7 @@ void LLSingletonBase::cleanup_() void LLSingletonBase::deleteAll() { // It's essential to traverse these in dependency order. - BOOST_FOREACH(LLSingletonBase* sp, dep_sort()) + for (LLSingletonBase* sp : dep_sort()) { // Capture the class name first: in case of exception, don't count on // being able to extract it later. diff --git a/indra/llcommon/llsys.cpp b/indra/llcommon/llsys.cpp index 938685bae6..f6b99b7d85 100644 --- a/indra/llcommon/llsys.cpp +++ b/indra/llcommon/llsys.cpp @@ -49,7 +49,6 @@ #include "llsdutil.h" #include #include -#include #include #include #include @@ -905,9 +904,9 @@ void LLMemoryInfo::stream(std::ostream& s) const // Max key length size_t key_width(0); - BOOST_FOREACH(const MapEntry& pair, inMap(mStatsMap)) + for (const auto& [key, value] : inMap(mStatsMap)) { - size_t len(pair.first.length()); + size_t len(key.length()); if (len > key_width) { key_width = len; @@ -915,10 +914,9 @@ void LLMemoryInfo::stream(std::ostream& s) const } // Now stream stats - BOOST_FOREACH(const MapEntry& pair, inMap(mStatsMap)) + for (const auto& [key, value] : inMap(mStatsMap)) { - s << pfx << std::setw(narrow(key_width+1)) << (pair.first + ':') << ' '; - LLSD value(pair.second); + s << pfx << std::setw(narrow(key_width+1)) << (key + ':') << ' '; if (value.isInteger()) s << std::setw(12) << value.asInteger(); else if (value.isReal()) diff --git a/indra/llcommon/tests/llprocess_test.cpp b/indra/llcommon/tests/llprocess_test.cpp index b6b297b8d7..628f046f55 100644 --- a/indra/llcommon/tests/llprocess_test.cpp +++ b/indra/llcommon/tests/llprocess_test.cpp @@ -21,7 +21,6 @@ // external library headers #include "llapr.h" #include "apr_thread_proc.h" -#include #include #include #include @@ -323,7 +322,7 @@ namespace tut { /*==========================================================================*| std::string reason_str; - BOOST_FOREACH(const ReasonCode& rcp, reasons) + for (const ReasonCode& rcp : reasons) { if (reason == rcp.code) { @@ -554,7 +553,7 @@ namespace tut catch (const failure&) { std::cout << "History:\n"; - BOOST_FOREACH(const Item& item, history) + for (const Item& item : history) { std::string what(item.what); if ((! what.empty()) && what[what.length() - 1] == '\n') diff --git a/indra/llcommon/tests/llstreamqueue_test.cpp b/indra/llcommon/tests/llstreamqueue_test.cpp index 050ad5c5bf..8af057328b 100644 --- a/indra/llcommon/tests/llstreamqueue_test.cpp +++ b/indra/llcommon/tests/llstreamqueue_test.cpp @@ -15,9 +15,6 @@ #include "llstreamqueue.h" // STL headers #include -// std headers -// external library headers -#include // other Linden headers #include "../test/lltut.h" #include "stringize.h" @@ -133,7 +130,7 @@ namespace tut std::streamsize leave(5); // len("craft") above std::streamsize skip(total - leave); std::streamsize written(0); - BOOST_FOREACH(const std::string& block, blocks) + for (const std::string& block : blocks) { written += strq.write(&block[0], block.length()); ensure_equals("size() after write()", strq.size(), written); @@ -152,7 +149,7 @@ namespace tut { set_test_name("concatenate blocks"); std::string blocks[] = { "abcd", "efghij", "klmnopqrs" }; - BOOST_FOREACH(const std::string& block, blocks) + for (const std::string& block : blocks) { strq.write(&block[0], block.length()); } @@ -170,7 +167,7 @@ namespace tut { set_test_name("split blocks"); std::string blocks[] = { "abcdefghijklm", "nopqrstuvwxyz" }; - BOOST_FOREACH(const std::string& block, blocks) + for (const std::string& block : blocks) { strq.write(&block[0], block.length()); } diff --git a/indra/llcommon/tests/lltreeiterators_test.cpp b/indra/llcommon/tests/lltreeiterators_test.cpp index 1d619867d4..b9c7a70c07 100644 --- a/indra/llcommon/tests/lltreeiterators_test.cpp +++ b/indra/llcommon/tests/lltreeiterators_test.cpp @@ -38,7 +38,6 @@ // external library headers #include #include -#include // associated header #include "../lltreeiterators.h" @@ -402,7 +401,7 @@ private: * * Example: * @code - * BOOST_FOREACH(TreeNodePtr node, getRootRange(somenode)) + * for (TreeNodePtr node : getRootRange(somenode)) * { * std::cout << node->name() << '\n'; * } @@ -424,7 +423,7 @@ getRootRange(const TreeNodePtr& node) * * Example: * @code - * BOOST_FOREACH(TreeNodePtr node, getWalkRange(root)) + * for (TreeNodePtr node : getWalkRange(root)) * { * std::cout << node->name() << '\n'; * } @@ -520,7 +519,7 @@ public: * * Example usage: * @code - * BOOST_FOREACH(EnhancedTreeNodePtr node, somenode->getRootRange()) + * for (EnhancedTreeNodePtr node : somenode->getRootRange()) * { * std::cout << node->name() << '\n'; * } @@ -564,7 +563,7 @@ public: * * Example usage: * @code - * BOOST_FOREACH(EnhancedTreeNodePtr node, somenode->getWalkRange()) + * for (EnhancedTreeNodePtr node : somenode->getWalkRange()) * { * std::cout << node->name() << '\n'; * } @@ -644,7 +643,7 @@ LLLinkedIter PlainTree_child_end(PlainTree* node) * * Example: * @code - * BOOST_FOREACH(PlainTree* node, getRootRange(somenode)) + * for (PlainTree* node : getRootRange(somenode)) * { * std::cout << node->name() << '\n'; * } @@ -668,7 +667,7 @@ getRootRange(PlainTree* node) * * Example: * @code - * BOOST_FOREACH(PlainTree* node, getWalkRange(root)) + * for (PlainTree* node : getWalkRange(root)) * { * std::cout << node->name() << '\n'; * } @@ -1103,18 +1102,18 @@ namespace tut // This test function illustrates the looping techniques described in the // comments for the getRootRange() free function, the // EnhancedTreeNode::root_range template and the - // EnhancedTreeNode::getRootRange() method. Obviously the BOOST_FOREACH() + // EnhancedTreeNode::getRootRange() method. Obviously the for() // forms are more succinct. TreeNodePtr tnroot(example_tree()); TreeNodePtr tnB2b(get_B2b (tnroot, boost::bind(&TreeNode::child_begin, _1))); - std::string desc1("BOOST_FOREACH(TreeNodePr, getRootRange(tnB2b))"); + std::string desc1("for (TreeNodePr : getRootRange(tnB2b))"); // std::cout << desc1 << "\n"; // Although we've commented out the output statement, ensure that the // loop construct is still valid, as promised by the getRootRange() // documentation. - BOOST_FOREACH(TreeNodePtr node, getRootRange(tnB2b)) + for (TreeNodePtr node : getRootRange(tnB2b)) { // std::cout << node->name() << '\n'; } @@ -1137,9 +1136,9 @@ namespace tut // std::cout << (*ri)->name() << '\n'; } - std::string desc2("BOOST_FOREACH(EnhancedTreeNodePtr node, etnB2b->getRootRange())"); + std::string desc2("for (EnhancedTreeNodePtr node : etnB2b->getRootRange())"); // std::cout << desc2 << '\n'; - BOOST_FOREACH(EnhancedTreeNodePtr node, etnB2b->getRootRange()) + for (EnhancedTreeNodePtr node : etnB2b->getRootRange()) { // std::cout << node->name() << '\n'; } -- cgit v1.2.3 From 382f9f0786b5225ac6d9648241e6c04f4f94f262 Mon Sep 17 00:00:00 2001 From: AiraYumi Date: Sat, 13 Jan 2024 15:36:45 +0900 Subject: replace part of boost::fibers::* to std::* --- indra/llcommon/llcond.h | 1 - indra/llcommon/llcoros.h | 14 +++++--------- indra/llcommon/lleventcoro.cpp | 6 +++--- indra/llcommon/llthreadsafequeue.h | 9 +++------ indra/llcommon/workqueue.cpp | 1 - 5 files changed, 11 insertions(+), 20 deletions(-) (limited to 'indra/llcommon') diff --git a/indra/llcommon/llcond.h b/indra/llcommon/llcond.h index da6e6affe1..a4bec124ca 100644 --- a/indra/llcommon/llcond.h +++ b/indra/llcommon/llcond.h @@ -16,7 +16,6 @@ #include "llunits.h" #include "llcoros.h" -#include LLCOROS_MUTEX_HEADER #include "mutex.h" #include diff --git a/indra/llcommon/llcoros.h b/indra/llcommon/llcoros.h index 966ce03296..8160b87f23 100644 --- a/indra/llcommon/llcoros.h +++ b/indra/llcommon/llcoros.h @@ -41,10 +41,6 @@ #include #include -// e.g. #include LLCOROS_MUTEX_HEADER -#define LLCOROS_MUTEX_HEADER -#define LLCOROS_CONDVAR_HEADER - namespace boost { namespace fibers { class mutex; @@ -289,17 +285,17 @@ public: * proxy, so continue using the aliases. */ template - using Promise = boost::fibers::promise; + using Promise = std::promise; template - using Future = boost::fibers::future; + using Future = std::future; template static Future getFuture(Promise& promise) { return promise.get_future(); } // use mutex, lock, condition_variable suitable for coroutines - using Mutex = boost::fibers::mutex; + using Mutex = std::mutex; using LockType = std::unique_lock; - using cv_status = boost::fibers::cv_status; - using ConditionVariable = boost::fibers::condition_variable; + using cv_status = std::cv_status; + using ConditionVariable = std::condition_variable; /// for data local to each running coroutine template diff --git a/indra/llcommon/lleventcoro.cpp b/indra/llcommon/lleventcoro.cpp index 067b5e6fbc..97a7ad04ad 100644 --- a/indra/llcommon/lleventcoro.cpp +++ b/indra/llcommon/lleventcoro.cpp @@ -285,7 +285,7 @@ LLSD llcoro::postAndSuspendWithTimeout(const LLSD& event, // declare the future LLCoros::Future future = LLCoros::getFuture(promise); // wait for specified timeout - boost::fibers::future_status status; + std::future_status status; { LLCoros::TempStatus st(STRINGIZE("waiting for " << replyPump.getPump().getName() << " for " << timeout << "s")); @@ -296,7 +296,7 @@ LLSD llcoro::postAndSuspendWithTimeout(const LLSD& event, status = future.wait_for(std::chrono::milliseconds(long(timeout * 1000))); } // if the future is NOT yet ready, return timeoutResult instead - if (status == boost::fibers::future_status::timeout) + if (status == std::future_status::timeout) { LL_DEBUGS("lleventcoro") << "postAndSuspendWithTimeout(): coroutine " << listenerName << " timed out after " << timeout << " seconds," @@ -305,7 +305,7 @@ LLSD llcoro::postAndSuspendWithTimeout(const LLSD& event, } else { - llassert_always(status == boost::fibers::future_status::ready); + llassert_always(status == std::future_status::ready); // future is now ready, no more waiting LLSD value(future.get()); diff --git a/indra/llcommon/llthreadsafequeue.h b/indra/llcommon/llthreadsafequeue.h index f396a71e6f..0aa75c9b73 100644 --- a/indra/llcommon/llthreadsafequeue.h +++ b/indra/llcommon/llthreadsafequeue.h @@ -28,9 +28,6 @@ #define LL_LLTHREADSAFEQUEUE_H #include "llcoros.h" -#include LLCOROS_MUTEX_HEADER -#include -#include LLCOROS_CONDVAR_HEADER #include "llexception.h" #include "mutex.h" #include @@ -182,10 +179,10 @@ protected: size_t mCapacity; bool mClosed; - boost::fibers::timed_mutex mLock; + std::timed_mutex mLock; typedef std::unique_lock lock_t; - boost::fibers::condition_variable_any mCapacityCond; - boost::fibers::condition_variable_any mEmptyCond; + std::condition_variable_any mCapacityCond; + std::condition_variable_any mEmptyCond; enum pop_result { EMPTY, DONE, WAITING, POPPED }; // implementation logic, suitable for passing to tryLockUntil() diff --git a/indra/llcommon/workqueue.cpp b/indra/llcommon/workqueue.cpp index cf80ce0656..9c434bf2a9 100644 --- a/indra/llcommon/workqueue.cpp +++ b/indra/llcommon/workqueue.cpp @@ -18,7 +18,6 @@ // external library headers // other Linden headers #include "llcoros.h" -#include LLCOROS_MUTEX_HEADER #include "llerror.h" #include "llexception.h" #include "stringize.h" -- cgit v1.2.3 From 746788e78901835aeb3ba983840092ce97b257da Mon Sep 17 00:00:00 2001 From: Andrey Lihatskiy Date: Tue, 16 Jan 2024 16:46:34 +0200 Subject: Revert "replaces parts of boost to C++ standard." --- indra/llcommon/llcond.h | 1 + indra/llcommon/llcoros.h | 14 +++++++++----- indra/llcommon/lleventcoro.cpp | 6 +++--- indra/llcommon/llthreadsafequeue.h | 9 ++++++--- indra/llcommon/workqueue.cpp | 1 + 5 files changed, 20 insertions(+), 11 deletions(-) (limited to 'indra/llcommon') diff --git a/indra/llcommon/llcond.h b/indra/llcommon/llcond.h index a4bec124ca..da6e6affe1 100644 --- a/indra/llcommon/llcond.h +++ b/indra/llcommon/llcond.h @@ -16,6 +16,7 @@ #include "llunits.h" #include "llcoros.h" +#include LLCOROS_MUTEX_HEADER #include "mutex.h" #include diff --git a/indra/llcommon/llcoros.h b/indra/llcommon/llcoros.h index 8160b87f23..966ce03296 100644 --- a/indra/llcommon/llcoros.h +++ b/indra/llcommon/llcoros.h @@ -41,6 +41,10 @@ #include #include +// e.g. #include LLCOROS_MUTEX_HEADER +#define LLCOROS_MUTEX_HEADER +#define LLCOROS_CONDVAR_HEADER + namespace boost { namespace fibers { class mutex; @@ -285,17 +289,17 @@ public: * proxy, so continue using the aliases. */ template - using Promise = std::promise; + using Promise = boost::fibers::promise; template - using Future = std::future; + using Future = boost::fibers::future; template static Future getFuture(Promise& promise) { return promise.get_future(); } // use mutex, lock, condition_variable suitable for coroutines - using Mutex = std::mutex; + using Mutex = boost::fibers::mutex; using LockType = std::unique_lock; - using cv_status = std::cv_status; - using ConditionVariable = std::condition_variable; + using cv_status = boost::fibers::cv_status; + using ConditionVariable = boost::fibers::condition_variable; /// for data local to each running coroutine template diff --git a/indra/llcommon/lleventcoro.cpp b/indra/llcommon/lleventcoro.cpp index 97a7ad04ad..067b5e6fbc 100644 --- a/indra/llcommon/lleventcoro.cpp +++ b/indra/llcommon/lleventcoro.cpp @@ -285,7 +285,7 @@ LLSD llcoro::postAndSuspendWithTimeout(const LLSD& event, // declare the future LLCoros::Future future = LLCoros::getFuture(promise); // wait for specified timeout - std::future_status status; + boost::fibers::future_status status; { LLCoros::TempStatus st(STRINGIZE("waiting for " << replyPump.getPump().getName() << " for " << timeout << "s")); @@ -296,7 +296,7 @@ LLSD llcoro::postAndSuspendWithTimeout(const LLSD& event, status = future.wait_for(std::chrono::milliseconds(long(timeout * 1000))); } // if the future is NOT yet ready, return timeoutResult instead - if (status == std::future_status::timeout) + if (status == boost::fibers::future_status::timeout) { LL_DEBUGS("lleventcoro") << "postAndSuspendWithTimeout(): coroutine " << listenerName << " timed out after " << timeout << " seconds," @@ -305,7 +305,7 @@ LLSD llcoro::postAndSuspendWithTimeout(const LLSD& event, } else { - llassert_always(status == std::future_status::ready); + llassert_always(status == boost::fibers::future_status::ready); // future is now ready, no more waiting LLSD value(future.get()); diff --git a/indra/llcommon/llthreadsafequeue.h b/indra/llcommon/llthreadsafequeue.h index 0aa75c9b73..f396a71e6f 100644 --- a/indra/llcommon/llthreadsafequeue.h +++ b/indra/llcommon/llthreadsafequeue.h @@ -28,6 +28,9 @@ #define LL_LLTHREADSAFEQUEUE_H #include "llcoros.h" +#include LLCOROS_MUTEX_HEADER +#include +#include LLCOROS_CONDVAR_HEADER #include "llexception.h" #include "mutex.h" #include @@ -179,10 +182,10 @@ protected: size_t mCapacity; bool mClosed; - std::timed_mutex mLock; + boost::fibers::timed_mutex mLock; typedef std::unique_lock lock_t; - std::condition_variable_any mCapacityCond; - std::condition_variable_any mEmptyCond; + boost::fibers::condition_variable_any mCapacityCond; + boost::fibers::condition_variable_any mEmptyCond; enum pop_result { EMPTY, DONE, WAITING, POPPED }; // implementation logic, suitable for passing to tryLockUntil() diff --git a/indra/llcommon/workqueue.cpp b/indra/llcommon/workqueue.cpp index 9c434bf2a9..cf80ce0656 100644 --- a/indra/llcommon/workqueue.cpp +++ b/indra/llcommon/workqueue.cpp @@ -18,6 +18,7 @@ // external library headers // other Linden headers #include "llcoros.h" +#include LLCOROS_MUTEX_HEADER #include "llerror.h" #include "llexception.h" #include "stringize.h" -- cgit v1.2.3 From 2f452d06e6964b0edf26b0b3f6eaa156e3fa2d48 Mon Sep 17 00:00:00 2001 From: Henri Beauchamp Date: Wed, 13 Mar 2024 13:57:39 +0100 Subject: Proposal #2 to restore how UI/dialogs used to render by prioritizing fallback fonts. With the emojis support, a new font was added, which not only provides emojis but also fancy colorful replacements for UTF-8 characters that used to be supported by our fallback (monochrome) fonts: this causes discrepancies and unwanted/undesired changes in scripted objects menus (e.g. an empty circle or square may render as a black, full one, a heart may render red instead of white), not to mention the larger font size used by the emoji characters... This patch restores the aspect of such menus/dialogs/UI elements with UTF-8 characters that *are* supported by the usual fallback fonts (fonts which may also vary from one viewer to another, and from one OS to another), so that everything keeps working/rendering as it always did so far, while not impairing the use of new colorful emojis. This second proposal ensures that: - "genuine" emojis (in the 0x1f000-0x1ffff range), will *always* be rendered using the new emojis font (this solves, for example, the monochrome "yellow faces" issue seen with some characters in my first proposal). - Special UTF-8 characters (in the 0x2000-0x32FF range) which have been used by scripters so far, will render as they used to, using the monochrome fallback fonts (this repairs scripted dialogs menus). - Remaining special characters, that do not have a corresponding glyph in the monochrome font, but do have one in the emojis font, will use the latter font to render. It also got the nice side-effect of removing the dependency on the ICU4C library. Note however that the recent commit: https://github.com/secondlife/viewer/commit/326055ba82c22fedde186c6a56bafd4fe87e613a will need to be reverted to allow this patch to actually fix scripted dialogs. Also, some cleanup might be needed in skins/default/xui/*/emoji_characters.xml to remove from it the special UTF-8 characters that will no longer be rendered with fanciful colors, but instead with the monochrome font glyphs. --- indra/llcommon/CMakeLists.txt | 2 -- indra/llcommon/llstring.cpp | 41 +++++++++-------------------------------- indra/llcommon/llstring.h | 3 ++- 3 files changed, 11 insertions(+), 35 deletions(-) (limited to 'indra/llcommon') diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index c947184dc8..5f4ed2fffa 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -3,7 +3,6 @@ project(llcommon) include(00-Common) -include(ICU4C) include(LLCommon) include(bugsplat) include(Linking) @@ -283,7 +282,6 @@ target_link_libraries( ll::uriparser ll::oslibraries ll::tracy - ll::icu4c ) target_include_directories(llcommon INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/indra/llcommon/llstring.cpp b/indra/llcommon/llstring.cpp index 4aa54bb12d..28c2ec5b39 100644 --- a/indra/llcommon/llstring.cpp +++ b/indra/llcommon/llstring.cpp @@ -30,7 +30,6 @@ #include "llerror.h" #include "llfasttimer.h" #include "llsd.h" -#include #include #if LL_WINDOWS @@ -1008,40 +1007,18 @@ std::string LLStringOps::sAM; std::string LLStringOps::sPM; // static -bool LLStringOps::isEmoji(llwchar wch) -{ - int ublock = ublock_getCode(wch); - switch (ublock) - { - case UBLOCK_GENERAL_PUNCTUATION: - case UBLOCK_LETTERLIKE_SYMBOLS: - case UBLOCK_ARROWS: - case UBLOCK_MISCELLANEOUS_TECHNICAL: - case UBLOCK_ENCLOSED_ALPHANUMERICS: - case UBLOCK_GEOMETRIC_SHAPES: - case UBLOCK_MISCELLANEOUS_SYMBOLS: - case UBLOCK_DINGBATS: - case UBLOCK_CJK_SYMBOLS_AND_PUNCTUATION: - case UBLOCK_ENCLOSED_CJK_LETTERS_AND_MONTHS: - case UBLOCK_MISCELLANEOUS_SYMBOLS_AND_PICTOGRAPHS: - case UBLOCK_EMOTICONS: - case UBLOCK_TRANSPORT_AND_MAP_SYMBOLS: -#if U_ICU_VERSION_MAJOR_NUM > 56 - // Boost uses ICU so we can't update it independently - case UBLOCK_SUPPLEMENTAL_SYMBOLS_AND_PICTOGRAPHS: -#endif // U_ICU_VERSION_MAJOR_NUM > 56 - return true; - default: -#if U_ICU_VERSION_MAJOR_NUM > 56 - return false; +bool LLStringOps::isEmoji(llwchar a) +{ +#if 0 // Do not consider special characters that might have a corresponding + // glyph in the monochorme fallback fonts as a "genuine" emoji. HB + return a == 0xa9 || a == 0xae || (a >= 0x2000 && a < 0x3300) || + (a >= 0x1f000 && a < 0x20000); #else - // See https://en.wikipedia.org/wiki/Supplemental_Symbols_and_Pictographs - return wch >= 0x1F900 && wch <= 0x1F9FF; -#endif // U_ICU_VERSION_MAJOR_NUM > 56 - } + // These are indeed "genuine" emojis, we *do want* rendered as such. HB + return a >= 0x1f000 && a < 0x20000; +#endif } - S32 LLStringOps::collate(const llwchar* a, const llwchar* b) { #if LL_WINDOWS diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h index a40359115e..a8d910298c 100644 --- a/indra/llcommon/llstring.h +++ b/indra/llcommon/llstring.h @@ -189,7 +189,8 @@ public: static bool isAlnum(char a) { return isalnum((unsigned char)a) != 0; } static bool isAlnum(llwchar a) { return iswalnum(a) != 0; } - static bool isEmoji(llwchar wch); + // Returns true when 'a' corresponds to a "genuine" emoji. HB + static bool isEmoji(llwchar a); static S32 collate(const char* a, const char* b) { return strcoll(a, b); } static S32 collate(const llwchar* a, const llwchar* b); -- cgit v1.2.3 From 50a70fe2f831c6d34a6f518ae040e52ac2f9f924 Mon Sep 17 00:00:00 2001 From: Andrey Kleshchev Date: Thu, 28 Mar 2024 00:45:38 +0200 Subject: viewer#1073 crash at loadSkeleton looks like file that was being parced got corrupted 'in progress' --- indra/llcommon/llsys.cpp | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'indra/llcommon') diff --git a/indra/llcommon/llsys.cpp b/indra/llcommon/llsys.cpp index 938685bae6..352628f129 100644 --- a/indra/llcommon/llsys.cpp +++ b/indra/llcommon/llsys.cpp @@ -1352,6 +1352,10 @@ BOOL gunzip_file(const std::string& srcfile, const std::string& dstfile) } while(gzeof(src) == 0); fclose(dst); dst = NULL; +#if LL_WINDOWS + // Rename in windows needs the dstfile to not exist. + LLFile::remove(dstfile, ENOENT); +#endif if (LLFile::rename(tmpfile, dstfile) == -1) goto err; /* Flawfinder: ignore */ retval = TRUE; err: -- cgit v1.2.3 From 1b68f71348ecf3983b76b40d7940da8377f049b7 Mon Sep 17 00:00:00 2001 From: Andrey Lihatskiy Date: Mon, 29 Apr 2024 07:43:28 +0300 Subject: #824 Process source files in bulk: replace tabs with spaces, convert CRLF to LF, and trim trailing whitespaces as needed --- indra/llcommon/StackWalker.cpp | 66 +- indra/llcommon/StackWalker.h | 80 +- indra/llcommon/always_return.h | 2 +- indra/llcommon/apply.cpp | 2 +- indra/llcommon/apply.h | 10 +- indra/llcommon/chrono.h | 2 +- indra/llcommon/classic_callback.cpp | 2 +- indra/llcommon/commoncontrol.cpp | 2 +- indra/llcommon/commoncontrol.h | 2 +- indra/llcommon/ctype_workaround.h | 18 +- indra/llcommon/fix_macros.h | 2 +- indra/llcommon/function_types.h | 2 +- indra/llcommon/hbxxh.cpp | 6 +- indra/llcommon/hbxxh.h | 6 +- indra/llcommon/indra_constants.cpp | 56 +- indra/llcommon/indra_constants.h | 338 +- indra/llcommon/is_approx_equal_fraction.h | 10 +- indra/llcommon/lazyeventapi.cpp | 2 +- indra/llcommon/lazyeventapi.h | 2 +- indra/llcommon/linden_common.h | 10 +- indra/llcommon/llalignedarray.h | 136 +- indra/llcommon/llallocator.cpp | 10 +- indra/llcommon/llallocator.h | 10 +- indra/llcommon/llallocator_heap_profile.cpp | 48 +- indra/llcommon/llallocator_heap_profile.h | 12 +- indra/llcommon/llapp.cpp | 960 ++-- indra/llcommon/llapp.h | 526 +- indra/llcommon/llapr.cpp | 902 ++-- indra/llcommon/llapr.h | 130 +- indra/llcommon/llassettype.cpp | 280 +- indra/llcommon/llassettype.h | 194 +- indra/llcommon/llatomic.cpp | 10 +- indra/llcommon/llatomic.h | 12 +- indra/llcommon/llbase32.cpp | 50 +- indra/llcommon/llbase32.h | 12 +- indra/llcommon/llbase64.cpp | 50 +- indra/llcommon/llbase64.h | 12 +- indra/llcommon/llbitpack.cpp | 10 +- indra/llcommon/llbitpack.h | 342 +- indra/llcommon/llboost.h | 40 +- indra/llcommon/llcallbacklist.cpp | 224 +- indra/llcommon/llcallbacklist.h | 42 +- indra/llcommon/llcallstack.cpp | 28 +- indra/llcommon/llcallstack.h | 10 +- indra/llcommon/llcleanup.cpp | 2 +- indra/llcommon/llcleanup.h | 2 +- indra/llcommon/llclickaction.h | 10 +- indra/llcommon/llcommon.cpp | 56 +- indra/llcommon/llcommon.h | 16 +- indra/llcommon/llcommonutils.cpp | 44 +- indra/llcommon/llcommonutils.h | 38 +- indra/llcommon/llcond.h | 2 +- indra/llcommon/llcoros.cpp | 10 +- indra/llcommon/llcoros.h | 12 +- indra/llcommon/llcrc.cpp | 116 +- indra/llcommon/llcrc.h | 30 +- indra/llcommon/llcriticaldamp.cpp | 100 +- indra/llcommon/llcriticaldamp.h | 60 +- indra/llcommon/lldate.cpp | 394 +- indra/llcommon/lldate.h | 192 +- indra/llcommon/lldeadmantimer.cpp | 226 +- indra/llcommon/lldeadmantimer.h | 258 +- indra/llcommon/lldefs.h | 202 +- indra/llcommon/lldependencies.cpp | 10 +- indra/llcommon/lldependencies.h | 16 +- indra/llcommon/lldepthstack.h | 116 +- indra/llcommon/lldictionary.cpp | 32 +- indra/llcommon/lldictionary.h | 108 +- indra/llcommon/lldoubledispatch.h | 22 +- indra/llcommon/llendianswizzle.h | 112 +- indra/llcommon/llerror.cpp | 1714 +++--- indra/llcommon/llerror.h | 480 +- indra/llcommon/llerrorcontrol.h | 322 +- indra/llcommon/llerrorlegacy.h | 10 +- indra/llcommon/llevent.cpp | 264 +- indra/llcommon/llevent.h | 180 +- indra/llcommon/lleventapi.cpp | 10 +- indra/llcommon/lleventapi.h | 10 +- indra/llcommon/lleventcoro.cpp | 10 +- indra/llcommon/lleventcoro.h | 12 +- indra/llcommon/lleventdispatcher.cpp | 12 +- indra/llcommon/lleventdispatcher.h | 28 +- indra/llcommon/lleventemitter.h | 96 +- indra/llcommon/lleventfilter.cpp | 10 +- indra/llcommon/lleventfilter.h | 22 +- indra/llcommon/llevents.cpp | 26 +- indra/llcommon/llevents.h | 42 +- indra/llcommon/lleventtimer.cpp | 42 +- indra/llcommon/lleventtimer.h | 68 +- indra/llcommon/llexception.cpp | 6 +- indra/llcommon/llexception.h | 2 +- indra/llcommon/llfasttimer.cpp | 506 +- indra/llcommon/llfasttimer.h | 408 +- indra/llcommon/llfile.cpp | 546 +- indra/llcommon/llfile.h | 148 +- indra/llcommon/llfindlocale.cpp | 10 +- indra/llcommon/llfindlocale.h | 10 +- indra/llcommon/llfixedbuffer.cpp | 80 +- indra/llcommon/llfixedbuffer.h | 38 +- indra/llcommon/llformat.cpp | 46 +- indra/llcommon/llformat.h | 10 +- indra/llcommon/llframetimer.cpp | 96 +- indra/llcommon/llframetimer.h | 218 +- indra/llcommon/llhandle.h | 240 +- indra/llcommon/llhash.h | 32 +- indra/llcommon/llheartbeat.cpp | 196 +- indra/llcommon/llheartbeat.h | 56 +- indra/llcommon/llheteromap.cpp | 4 +- indra/llcommon/llheteromap.h | 2 +- indra/llcommon/llindexedvector.h | 112 +- indra/llcommon/llinitdestroyclass.cpp | 12 +- indra/llcommon/llinitdestroyclass.h | 86 +- indra/llcommon/llinitparam.cpp | 870 +-- indra/llcommon/llinitparam.h | 5580 ++++++++++---------- indra/llcommon/llinstancetracker.cpp | 10 +- indra/llcommon/llinstancetracker.h | 28 +- indra/llcommon/llkeybind.cpp | 20 +- indra/llcommon/llkeybind.h | 12 +- indra/llcommon/llkeythrottle.h | 550 +- indra/llcommon/llkeyusetracker.h | 334 +- indra/llcommon/llleap.cpp | 2 +- indra/llcommon/llleap.h | 2 +- indra/llcommon/llleaplistener.cpp | 2 +- indra/llcommon/llleaplistener.h | 2 +- indra/llcommon/llliveappconfig.cpp | 70 +- indra/llcommon/llliveappconfig.h | 42 +- indra/llcommon/lllivefile.cpp | 152 +- indra/llcommon/lllivefile.h | 106 +- indra/llcommon/llmainthreadtask.cpp | 2 +- indra/llcommon/llmainthreadtask.h | 2 +- indra/llcommon/llmake.h | 2 +- indra/llcommon/llmd5.cpp | 150 +- indra/llcommon/llmd5.h | 30 +- indra/llcommon/llmemory.cpp | 304 +- indra/llcommon/llmemory.h | 350 +- indra/llcommon/llmemorystream.cpp | 32 +- indra/llcommon/llmemorystream.h | 32 +- indra/llcommon/llmetricperformancetester.cpp | 426 +- indra/llcommon/llmetricperformancetester.h | 324 +- indra/llcommon/llmetrics.cpp | 170 +- indra/llcommon/llmetrics.h | 34 +- indra/llcommon/llmortician.cpp | 56 +- indra/llcommon/llmortician.h | 36 +- indra/llcommon/llmutex.cpp | 162 +- indra/llcommon/llmutex.h | 102 +- indra/llcommon/llnametable.h | 118 +- indra/llcommon/llpointer.h | 544 +- indra/llcommon/llpredicate.cpp | 26 +- indra/llcommon/llpredicate.h | 346 +- indra/llcommon/llpreprocessor.h | 86 +- indra/llcommon/llpriqueuemap.h | 188 +- indra/llcommon/llprocess.cpp | 2022 +++---- indra/llcommon/llprocess.h | 994 ++-- indra/llcommon/llprocessor.cpp | 1456 ++--- indra/llcommon/llprocessor.h | 30 +- indra/llcommon/llprocinfo.cpp | 64 +- indra/llcommon/llprocinfo.h | 34 +- indra/llcommon/llptrto.cpp | 10 +- indra/llcommon/llptrto.h | 10 +- indra/llcommon/llqueuedthread.cpp | 550 +- indra/llcommon/llqueuedthread.h | 226 +- indra/llcommon/llrand.cpp | 74 +- indra/llcommon/llrand.h | 38 +- indra/llcommon/llrefcount.cpp | 26 +- indra/llcommon/llrefcount.h | 156 +- indra/llcommon/llregex.h | 90 +- indra/llcommon/llregistry.h | 580 +- indra/llcommon/llrun.cpp | 212 +- indra/llcommon/llrun.h | 204 +- indra/llcommon/llsafehandle.h | 270 +- indra/llcommon/llsd.cpp | 1524 +++--- indra/llcommon/llsd.h | 850 +-- indra/llcommon/llsdjson.cpp | 10 +- indra/llcommon/llsdjson.h | 22 +- indra/llcommon/llsdparam.cpp | 366 +- indra/llcommon/llsdparam.h | 180 +- indra/llcommon/llsdserialize.cpp | 3982 +++++++------- indra/llcommon/llsdserialize.h | 1306 ++--- indra/llcommon/llsdserialize_xml.cpp | 1470 +++--- indra/llcommon/llsdserialize_xml.h | 10 +- indra/llcommon/llsdutil.cpp | 736 +-- indra/llcommon/llsdutil.h | 50 +- indra/llcommon/llsimplehash.h | 228 +- indra/llcommon/llsingleton.cpp | 14 +- indra/llcommon/llsingleton.h | 12 +- indra/llcommon/llsmoothstep.h | 22 +- indra/llcommon/llstacktrace.cpp | 194 +- indra/llcommon/llstacktrace.h | 10 +- indra/llcommon/llstatenums.h | 10 +- indra/llcommon/llstaticstringtable.h | 60 +- indra/llcommon/llstl.h | 346 +- indra/llcommon/llstreamqueue.cpp | 2 +- indra/llcommon/llstreamqueue.h | 2 +- indra/llcommon/llstreamtools.cpp | 760 +-- indra/llcommon/llstreamtools.h | 36 +- indra/llcommon/llstrider.h | 60 +- indra/llcommon/llstring.cpp | 2216 ++++---- indra/llcommon/llstring.h | 2452 ++++----- indra/llcommon/llstringtable.cpp | 430 +- indra/llcommon/llstringtable.h | 264 +- indra/llcommon/llsys.cpp | 1706 +++--- indra/llcommon/llsys.h | 134 +- indra/llcommon/lltempredirect.cpp | 2 +- indra/llcommon/lltempredirect.h | 2 +- indra/llcommon/llthread.cpp | 28 +- indra/llcommon/llthread.h | 36 +- indra/llcommon/llthreadlocalstorage.h | 28 +- indra/llcommon/llthreadsafequeue.cpp | 10 +- indra/llcommon/llthreadsafequeue.h | 286 +- indra/llcommon/lltimer.cpp | 524 +- indra/llcommon/lltimer.h | 166 +- indra/llcommon/lltrace.cpp | 70 +- indra/llcommon/lltrace.h | 222 +- indra/llcommon/lltraceaccumulators.cpp | 350 +- indra/llcommon/lltraceaccumulators.h | 1018 ++-- indra/llcommon/lltracerecording.cpp | 1300 ++--- indra/llcommon/lltracerecording.h | 1306 ++--- indra/llcommon/lltracethreadrecorder.cpp | 326 +- indra/llcommon/lltracethreadrecorder.h | 100 +- indra/llcommon/lltreeiterators.h | 74 +- indra/llcommon/llunits.h | 36 +- indra/llcommon/llunittype.h | 1030 ++-- indra/llcommon/lluri.cpp | 1016 ++-- indra/llcommon/lluri.h | 266 +- indra/llcommon/lluriparser.cpp | 234 +- indra/llcommon/lluriparser.h | 78 +- indra/llcommon/lluuid.cpp | 54 +- indra/llcommon/lluuid.h | 218 +- indra/llcommon/llwin32headers.h | 10 +- indra/llcommon/llwin32headerslean.h | 10 +- indra/llcommon/llworkerthread.cpp | 488 +- indra/llcommon/llworkerthread.h | 216 +- indra/llcommon/lockstatic.h | 2 +- indra/llcommon/mutex.h | 2 +- indra/llcommon/stdtypes.h | 96 +- indra/llcommon/string_table.h | 10 +- indra/llcommon/stringize.h | 10 +- indra/llcommon/tests/StringVec.h | 2 +- indra/llcommon/tests/apply_test.cpp | 2 +- indra/llcommon/tests/bitpack_test.cpp | 170 +- indra/llcommon/tests/classic_callback_test.cpp | 2 +- indra/llcommon/tests/commonmisc_test.cpp | 1176 ++--- indra/llcommon/tests/lazyeventapi_test.cpp | 2 +- indra/llcommon/tests/listener.h | 10 +- .../tests/llallocator_heap_profile_test.cpp | 10 +- indra/llcommon/tests/llallocator_test.cpp | 12 +- indra/llcommon/tests/llbase64_test.cpp | 70 +- indra/llcommon/tests/llcond_test.cpp | 4 +- indra/llcommon/tests/lldate_test.cpp | 286 +- indra/llcommon/tests/lldeadmantimer_test.cpp | 1006 ++-- indra/llcommon/tests/lldependencies_test.cpp | 10 +- indra/llcommon/tests/llerror_test.cpp | 1178 ++--- indra/llcommon/tests/lleventcoro_test.cpp | 10 +- indra/llcommon/tests/lleventdispatcher_test.cpp | 4 +- indra/llcommon/tests/lleventfilter_test.cpp | 10 +- indra/llcommon/tests/llframetimer_test.cpp | 168 +- indra/llcommon/tests/llheteromap_test.cpp | 2 +- indra/llcommon/tests/llinstancetracker_test.cpp | 12 +- indra/llcommon/tests/lllazy_test.cpp | 10 +- indra/llcommon/tests/llleap_test.cpp | 2 +- indra/llcommon/tests/llmainthreadtask_test.cpp | 2 +- indra/llcommon/tests/llmemtype_test.cpp | 100 +- indra/llcommon/tests/llpounceable_test.cpp | 2 +- indra/llcommon/tests/llprocess_test.cpp | 4 +- indra/llcommon/tests/llprocessor_test.cpp | 62 +- indra/llcommon/tests/llprocinfo_test.cpp | 60 +- indra/llcommon/tests/llrand_test.cpp | 138 +- indra/llcommon/tests/llsdserialize_test.cpp | 3048 +++++------ indra/llcommon/tests/llsingleton_test.cpp | 2 +- indra/llcommon/tests/llstreamqueue_test.cpp | 2 +- indra/llcommon/tests/llstring_test.cpp | 1668 +++--- indra/llcommon/tests/lltrace_test.cpp | 186 +- indra/llcommon/tests/lltreeiterators_test.cpp | 14 +- indra/llcommon/tests/llunits_test.cpp | 674 +-- indra/llcommon/tests/lluri_test.cpp | 704 +-- indra/llcommon/tests/stringize_test.cpp | 12 +- indra/llcommon/tests/threadsafeschedule_test.cpp | 2 +- indra/llcommon/tests/tuple_test.cpp | 2 +- indra/llcommon/tests/workqueue_test.cpp | 2 +- indra/llcommon/tests/wrapllerrs.h | 16 +- indra/llcommon/threadpool.cpp | 2 +- indra/llcommon/threadpool.h | 2 +- indra/llcommon/threadpool_fwd.h | 2 +- indra/llcommon/threadsafeschedule.h | 4 +- indra/llcommon/timer.h | 10 +- indra/llcommon/tuple.h | 2 +- indra/llcommon/u64.cpp | 118 +- indra/llcommon/u64.h | 10 +- indra/llcommon/workqueue.cpp | 2 +- indra/llcommon/workqueue.h | 2 +- 290 files changed, 35764 insertions(+), 35764 deletions(-) (limited to 'indra/llcommon') diff --git a/indra/llcommon/StackWalker.cpp b/indra/llcommon/StackWalker.cpp index 56defc6465..201eeed56b 100644 --- a/indra/llcommon/StackWalker.cpp +++ b/indra/llcommon/StackWalker.cpp @@ -1,5 +1,5 @@ /********************************************************************** - * + * * StackWalker.cpp * http://stackwalker.codeplex.com/ * @@ -13,14 +13,14 @@ * http://www.codeproject.com/threads/StackWalker.asp * 2005-07-28 v2 - Changed the params of the constructor and ShowCallstack * (to simplify the usage) - * 2005-08-01 v3 - Changed to use 'CONTEXT_FULL' instead of CONTEXT_ALL + * 2005-08-01 v3 - Changed to use 'CONTEXT_FULL' instead of CONTEXT_ALL * (should also be enough) * - Changed to compile correctly with the PSDK of VC7.0 * (GetFileVersionInfoSizeA and GetFileVersionInfoA is wrongly defined: * it uses LPSTR instead of LPCSTR as first paremeter) * - Added declarations to support VC5/6 without using 'dbghelp.h' - * - Added a 'pUserData' member to the ShowCallstack function and the - * PReadProcessMemoryRoutine declaration (to pass some user-defined data, + * - Added a 'pUserData' member to the ShowCallstack function and the + * PReadProcessMemoryRoutine declaration (to pass some user-defined data, * which can be used in the readMemoryFunction-callback) * 2005-08-02 v4 - OnSymInit now also outputs the OS-Version by default * - Added example for doing an exception-callstack-walking in main.cpp @@ -60,26 +60,26 @@ * Copyright (c) 2005-2013, Jochen Kalmbach * All rights reserved. * - * Redistribution and use in source and binary forms, with or without modification, + * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * Neither the name of Jochen Kalmbach nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of Jochen Kalmbach nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * **********************************************************************/ @@ -234,7 +234,7 @@ DWORD64 // Some missing defines (for VC5/6): #ifndef INVALID_FILE_ATTRIBUTES #define INVALID_FILE_ATTRIBUTES ((DWORD)-1) -#endif +#endif // secure-CRT_functions are only available starting with VC8 @@ -396,7 +396,7 @@ public: m_szSymPath = _strdup(szSymPath); if (this->pSI(m_hProcess, m_szSymPath, FALSE) == FALSE) this->m_parent->OnDbgHelpErr("SymInitialize", GetLastError(), 0); - + DWORD symOptions = this->pSGO(); // SymGetOptions symOptions |= SYMOPT_LOAD_LINES; symOptions |= SYMOPT_FAIL_CRITICAL_ERRORS; @@ -512,11 +512,11 @@ struct IMAGEHLP_MODULE64_V2 { tSSO pSSO; // StackWalk64() - typedef BOOL (__stdcall *tSW)( - DWORD MachineType, + typedef BOOL (__stdcall *tSW)( + DWORD MachineType, HANDLE hProcess, - HANDLE hThread, - LPSTACKFRAME64 StackFrame, + HANDLE hThread, + LPSTACKFRAME64 StackFrame, PVOID ContextRecord, PREAD_PROCESS_MEMORY_ROUTINE64 ReadMemoryRoutine, PFUNCTION_TABLE_ACCESS_ROUTINE64 FunctionTableAccessRoutine, @@ -1012,7 +1012,7 @@ BOOL StackWalker::LoadModules() // The following is used to pass the "userData"-Pointer to the user-provided readMemoryFunction // This has to be done due to a problem with the "hProcess"-parameter in x64... -// Because this class is in no case multi-threading-enabled (because of the limitations +// Because this class is in no case multi-threading-enabled (because of the limitations // of dbghelp.dll) it is "safe" to use a static-variable static StackWalker::PReadProcessMemoryRoutine s_readMemoryFunction = NULL; static LPVOID s_readMemoryFunction_UserData = NULL; @@ -1222,7 +1222,7 @@ BOOL StackWalker::ShowCallstack(bool verbose, HANDLE hThread, const CONTEXT *con csEntry.symTypeString = NULL; break; } - + MyStrCpy(csEntry.moduleName, STACKWALK_MAX_NAMELEN, Module.ModuleName); csEntry.baseOfImage = Module.BaseOfImage; MyStrCpy(csEntry.loadedImageName, STACKWALK_MAX_NAMELEN, Module.LoadedImageName); @@ -1243,7 +1243,7 @@ BOOL StackWalker::ShowCallstack(bool verbose, HANDLE hThread, const CONTEXT *con et = firstEntry; bLastEntryCalled = false; this->OnCallstackEntry(et, csEntry); - + if (s.AddrReturn.Offset == 0) { bLastEntryCalled = true; @@ -1358,7 +1358,7 @@ void StackWalker::OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUser ver.dwOSVersionInfoSize = sizeof(ver); if (GetVersionExA(&ver) != FALSE) { - _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "OS-Version: %d.%d.%d (%s)\n", + _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "OS-Version: %d.%d.%d (%s)\n", ver.dwMajorVersion, ver.dwMinorVersion, ver.dwBuildNumber, ver.szCSDVersion); if (m_verbose) @@ -1372,7 +1372,7 @@ void StackWalker::OnSymInit(LPCSTR szSearchPath, DWORD symOptions, LPCSTR szUser ver.dwOSVersionInfoSize = sizeof(ver); if (GetVersionExA( (OSVERSIONINFOA*) &ver) != FALSE) { - _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "OS-Version: %d.%d.%d (%s) 0x%x-0x%x\n", + _snprintf_s(buffer, STACKWALK_MAX_NAMELEN, "OS-Version: %d.%d.%d (%s) 0x%x-0x%x\n", ver.dwMajorVersion, ver.dwMinorVersion, ver.dwBuildNumber, ver.szCSDVersion, ver.wSuiteMask, ver.wProductType); if (m_verbose) diff --git a/indra/llcommon/StackWalker.h b/indra/llcommon/StackWalker.h index 4634765d0b..91cd55bbaf 100644 --- a/indra/llcommon/StackWalker.h +++ b/indra/llcommon/StackWalker.h @@ -1,5 +1,5 @@ /********************************************************************** - * + * * StackWalker.h * * @@ -13,33 +13,33 @@ * Copyright (c) 2005-2009, Jochen Kalmbach * All rights reserved. * - * Redistribution and use in source and binary forms, with or without modification, + * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * - * Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * Neither the name of Jochen Kalmbach nor the names of its contributors may be - * used to endorse or promote products derived from this software without - * specific prior written permission. - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of Jochen Kalmbach nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * **********************************************************************/ #if LL_WINDOWS -// #pragma once is supported starting with _MCS_VER 1000, +// #pragma once is supported starting with _MCS_VER 1000, // so we need not to check the version (because we only support _MSC_VER >= 1100)! #pragma once @@ -61,34 +61,34 @@ class StackWalker public: typedef enum StackWalkOptions { - // No addition info will be retrived + // No addition info will be retrived // (only the address is available) RetrieveNone = 0, - + // Try to get the symbol-name RetrieveSymbol = 1, - + // Try to get the line for this symbol RetrieveLine = 2, - + // Try to retrieve the module-infos RetrieveModuleInfo = 4, - + // Also retrieve the version for the DLL/EXE RetrieveFileVersion = 8, - + // Contains all the abouve RetrieveVerbose = 0xF, - + // Generate a "good" symbol-search-path SymBuildPath = 0x10, - + // Also use the public Microsoft-Symbol-Server SymUseSymSrv = 0x20, - + // Contains all the abouve "Sym"-options SymAll = 0x30, - + // Contains all options (default) OptionsAll = 0x3F } StackWalkOptions; @@ -96,8 +96,8 @@ public: StackWalker( bool verbose = true, int options = OptionsAll, // 'int' is by design, to combine the enum-flags - LPCSTR szSymPath = NULL, - DWORD dwProcessId = GetCurrentProcessId(), + LPCSTR szSymPath = NULL, + DWORD dwProcessId = GetCurrentProcessId(), HANDLE hProcess = GetCurrentProcess() ); StackWalker(DWORD dwProcessId, HANDLE hProcess); @@ -116,18 +116,18 @@ public: BOOL ShowCallstack( bool verbose, - HANDLE hThread = GetCurrentThread(), - const CONTEXT *context = NULL, + HANDLE hThread = GetCurrentThread(), + const CONTEXT *context = NULL, PReadProcessMemoryRoutine readMemoryFunction = NULL, LPVOID pUserData = NULL // optional to identify some data in the 'readMemoryFunction'-callback ); #if _MSC_VER >= 1300 -// due to some reasons, the "STACKWALK_MAX_NAMELEN" must be declared as "public" +// due to some reasons, the "STACKWALK_MAX_NAMELEN" must be declared as "public" // in older compilers in order to use it... starting with VC7 we can declare it as "protected" protected: #endif - enum { STACKWALK_MAX_NAMELEN = 4096 }; // max name length for found symbols + enum { STACKWALK_MAX_NAMELEN = 4096 }; // max name length for found symbols protected: // Entry for each Callstack-Entry @@ -173,10 +173,10 @@ protected: // The "ugly" assembler-implementation is needed for systems before XP -// If you have a new PSDK and you only compile for XP and later, then you can use +// If you have a new PSDK and you only compile for XP and later, then you can use // the "RtlCaptureContext" -// Currently there is no define which determines the PSDK-Version... -// So we just use the compiler-version (and assumes that the PSDK is +// Currently there is no define which determines the PSDK-Version... +// So we just use the compiler-version (and assumes that the PSDK is // the one which was installed by the VS-IDE) // INFO: If you want, you can use the RtlCaptureContext if you only target XP and later... @@ -185,7 +185,7 @@ protected: #if defined(_M_IX86) #ifdef CURRENT_THREAD_VIA_EXCEPTION -// TODO: The following is not a "good" implementation, +// TODO: The following is not a "good" implementation, // because the callstack is only valid in the "__except" block... #define GET_CURRENT_CONTEXT_STACKWALKER_CODEPLEX(c, contextFlags) \ do { \ diff --git a/indra/llcommon/always_return.h b/indra/llcommon/always_return.h index 6b9f1fdeaf..a206471da5 100644 --- a/indra/llcommon/always_return.h +++ b/indra/llcommon/always_return.h @@ -4,7 +4,7 @@ * @date 2023-01-20 * @brief Call specified callable with arbitrary arguments, but always return * specified type. - * + * * $LicenseInfo:firstyear=2023&license=viewerlgpl$ * Copyright (c) 2023, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/apply.cpp b/indra/llcommon/apply.cpp index 417e23d3b4..805b1234ac 100644 --- a/indra/llcommon/apply.cpp +++ b/indra/llcommon/apply.cpp @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2022-12-21 * @brief Implementation for apply. - * + * * $LicenseInfo:firstyear=2022&license=viewerlgpl$ * Copyright (c) 2022, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/apply.h b/indra/llcommon/apply.h index cf6161ed50..ec1a39f7b0 100644 --- a/indra/llcommon/apply.h +++ b/indra/llcommon/apply.h @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2022-06-18 * @brief C++14 version of std::apply() - * + * * $LicenseInfo:firstyear=2022&license=viewerlgpl$ * Copyright (c) 2022, Linden Research, Inc. * $/LicenseInfo$ @@ -69,7 +69,7 @@ using std::invoke; // Use invoke() to handle pointer-to-method: // derived from https://stackoverflow.com/a/38288251 -template::type>::value, int>::type = 0 > auto invoke(Fn&& f, Args&&... args) @@ -77,7 +77,7 @@ auto invoke(Fn&& f, Args&&... args) return std::mem_fn(std::forward(f))(std::forward(args)...); } -template::type>::value, int>::type = 0 > auto invoke(Fn&& f, Args&&... args) @@ -154,7 +154,7 @@ using std::bind_front; #else // no std::bind_front() -template::type>::value, int>::type = 0 > auto bind_front(Fn&& f, Args&&... args) @@ -172,7 +172,7 @@ auto bind_front(Fn&& f, Args&&... args) }; } -template::type>::value, int>::type = 0 > auto bind_front(Fn&& f, Args&&... args) diff --git a/indra/llcommon/chrono.h b/indra/llcommon/chrono.h index 806e871892..d121b9adf6 100644 --- a/indra/llcommon/chrono.h +++ b/indra/llcommon/chrono.h @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2021-10-05 * @brief supplement with utility functions - * + * * $LicenseInfo:firstyear=2021&license=viewerlgpl$ * Copyright (c) 2021, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/classic_callback.cpp b/indra/llcommon/classic_callback.cpp index 5674e0a44d..b2d0e7b303 100644 --- a/indra/llcommon/classic_callback.cpp +++ b/indra/llcommon/classic_callback.cpp @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2021-09-23 * @brief Implementation for classic_callback. - * + * * $LicenseInfo:firstyear=2021&license=viewerlgpl$ * Copyright (c) 2021, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/commoncontrol.cpp b/indra/llcommon/commoncontrol.cpp index 81e66baf8c..d8bdcd5aa5 100644 --- a/indra/llcommon/commoncontrol.cpp +++ b/indra/llcommon/commoncontrol.cpp @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2022-06-08 * @brief Implementation for commoncontrol. - * + * * $LicenseInfo:firstyear=2022&license=viewerlgpl$ * Copyright (c) 2022, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/commoncontrol.h b/indra/llcommon/commoncontrol.h index 07d4a45ac5..13aa983a99 100644 --- a/indra/llcommon/commoncontrol.h +++ b/indra/llcommon/commoncontrol.h @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2022-06-08 * @brief Access LLViewerControl LLEventAPI, if process has one. - * + * * $LicenseInfo:firstyear=2022&license=viewerlgpl$ * Copyright (c) 2022, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/ctype_workaround.h b/indra/llcommon/ctype_workaround.h index 552be9fb90..89a47fe3db 100644 --- a/indra/llcommon/ctype_workaround.h +++ b/indra/llcommon/ctype_workaround.h @@ -1,4 +1,4 @@ -/** +/** * @file ctype_workaround.h * @brief The workaround is to create some legacy symbols that point * to the correct symbols, which avoids link errors. @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -42,12 +42,12 @@ __const unsigned short int *__ctype_b; __const __int32_t *__ctype_tolower; __const __int32_t *__ctype_toupper; -// call this function at the beginning of main() +// call this function at the beginning of main() void ctype_workaround() { - __ctype_b = *(__ctype_b_loc()); - __ctype_toupper = *(__ctype_toupper_loc()); - __ctype_tolower = *(__ctype_tolower_loc()); + __ctype_b = *(__ctype_b_loc()); + __ctype_toupper = *(__ctype_toupper_loc()); + __ctype_tolower = *(__ctype_tolower_loc()); } #endif diff --git a/indra/llcommon/fix_macros.h b/indra/llcommon/fix_macros.h index 43c09c54bc..ed6c26a371 100644 --- a/indra/llcommon/fix_macros.h +++ b/indra/llcommon/fix_macros.h @@ -6,7 +6,7 @@ * generic names, preventing any library from using those names. We've * had to fix these in so many places that it's worth making a header * file to handle it. - * + * * $LicenseInfo:firstyear=2012&license=viewerlgpl$ * Copyright (c) 2012, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/function_types.h b/indra/llcommon/function_types.h index 3f42f6d640..7e15895a7e 100644 --- a/indra/llcommon/function_types.h +++ b/indra/llcommon/function_types.h @@ -4,7 +4,7 @@ * @date 2023-01-20 * @brief Extend boost::function_types to examine boost::function and * std::function - * + * * $LicenseInfo:firstyear=2023&license=viewerlgpl$ * Copyright (c) 2023, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/hbxxh.cpp b/indra/llcommon/hbxxh.cpp index 388269d6c8..41d797a7e3 100644 --- a/indra/llcommon/hbxxh.cpp +++ b/indra/llcommon/hbxxh.cpp @@ -10,16 +10,16 @@ * 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$ */ diff --git a/indra/llcommon/hbxxh.h b/indra/llcommon/hbxxh.h index 9c0e9cf172..142e140cf3 100644 --- a/indra/llcommon/hbxxh.h +++ b/indra/llcommon/hbxxh.h @@ -10,16 +10,16 @@ * 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$ */ diff --git a/indra/llcommon/indra_constants.cpp b/indra/llcommon/indra_constants.cpp index 9a0c565b06..d24a221671 100644 --- a/indra/llcommon/indra_constants.cpp +++ b/indra/llcommon/indra_constants.cpp @@ -1,25 +1,25 @@ -/** +/** * @file indra_constants.cpp * @brief some useful short term constants for Indra * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -38,39 +38,39 @@ const LLUUID GOVERNOR_LINDEN_ID("3d6181b0-6a4b-97ef-18d8-722652995cf1"); // Maintenance's group id. const LLUUID MAINTENANCE_GROUP_ID("dc7b21cd-3c89-fcaa-31c8-25f9ffd224cd"); // Grass Images -const LLUUID IMG_SMOKE ("b4ba225c-373f-446d-9f7e-6cb7b5cf9b3d"); // VIEWER +const LLUUID IMG_SMOKE ("b4ba225c-373f-446d-9f7e-6cb7b5cf9b3d"); // VIEWER -const LLUUID IMG_DEFAULT ("d2114404-dd59-4a4d-8e6c-49359e91bbf0"); // VIEWER +const LLUUID IMG_DEFAULT ("d2114404-dd59-4a4d-8e6c-49359e91bbf0"); // VIEWER -const LLUUID IMG_SUN ("cce0f112-878f-4586-a2e2-a8f104bba271"); // dataserver -const LLUUID IMG_MOON ("d07f6eed-b96a-47cd-b51d-400ad4a1c428"); // dataserver -const LLUUID IMG_SHOT ("35f217a3-f618-49cf-bbca-c86d486551a9"); // dataserver -const LLUUID IMG_SPARK ("d2e75ac1-d0fb-4532-820e-a20034ac814d"); // dataserver -const LLUUID IMG_FIRE ("aca40aa8-44cf-44ca-a0fa-93e1a2986f82"); // dataserver +const LLUUID IMG_SUN ("cce0f112-878f-4586-a2e2-a8f104bba271"); // dataserver +const LLUUID IMG_MOON ("d07f6eed-b96a-47cd-b51d-400ad4a1c428"); // dataserver +const LLUUID IMG_SHOT ("35f217a3-f618-49cf-bbca-c86d486551a9"); // dataserver +const LLUUID IMG_SPARK ("d2e75ac1-d0fb-4532-820e-a20034ac814d"); // dataserver +const LLUUID IMG_FIRE ("aca40aa8-44cf-44ca-a0fa-93e1a2986f82"); // dataserver const LLUUID IMG_FACE_SELECT ("a85ac674-cb75-4af6-9499-df7c5aaf7a28"); // face selector const LLUUID IMG_DEFAULT_AVATAR ("c228d1cf-4b5d-4ba8-84f4-899a0796aa97"); // dataserver -const LLUUID IMG_INVISIBLE ("3a367d1c-bef1-6d43-7595-e88c1e3aadb3"); // dataserver +const LLUUID IMG_INVISIBLE ("3a367d1c-bef1-6d43-7595-e88c1e3aadb3"); // dataserver const LLUUID IMG_WHITE ("5748decc-f629-461c-9a36-a35a221fe21f"); // dataserver -const LLUUID IMG_EXPLOSION ("68edcf47-ccd7-45b8-9f90-1649d7f12806"); // On dataserver -const LLUUID IMG_EXPLOSION_2 ("21ce046c-83fe-430a-b629-c7660ac78d7c"); // On dataserver -const LLUUID IMG_EXPLOSION_3 ("fedea30a-1be8-47a6-bc06-337a04a39c4b"); // On dataserver -const LLUUID IMG_EXPLOSION_4 ("abf0d56b-82e5-47a2-a8ad-74741bb2c29e"); // On dataserver -const LLUUID IMG_SMOKE_POOF ("1e63e323-5fe0-452e-92f8-b98bd0f764e3"); // On dataserver +const LLUUID IMG_EXPLOSION ("68edcf47-ccd7-45b8-9f90-1649d7f12806"); // On dataserver +const LLUUID IMG_EXPLOSION_2 ("21ce046c-83fe-430a-b629-c7660ac78d7c"); // On dataserver +const LLUUID IMG_EXPLOSION_3 ("fedea30a-1be8-47a6-bc06-337a04a39c4b"); // On dataserver +const LLUUID IMG_EXPLOSION_4 ("abf0d56b-82e5-47a2-a8ad-74741bb2c29e"); // On dataserver +const LLUUID IMG_SMOKE_POOF ("1e63e323-5fe0-452e-92f8-b98bd0f764e3"); // On dataserver -const LLUUID IMG_BIG_EXPLOSION_1 ("5e47a0dc-97bf-44e0-8b40-de06718cee9d"); // On dataserver -const LLUUID IMG_BIG_EXPLOSION_2 ("9c8eca51-53d5-42a7-bb58-cef070395db8"); // On dataserver +const LLUUID IMG_BIG_EXPLOSION_1 ("5e47a0dc-97bf-44e0-8b40-de06718cee9d"); // On dataserver +const LLUUID IMG_BIG_EXPLOSION_2 ("9c8eca51-53d5-42a7-bb58-cef070395db8"); // On dataserver -const LLUUID IMG_ALPHA_GRAD ("e97cf410-8e61-7005-ec06-629eba4cd1fb"); // VIEWER -const LLUUID IMG_ALPHA_GRAD_2D ("38b86f85-2575-52a9-a531-23108d8da837"); // VIEWER -const LLUUID IMG_TRANSPARENT ("8dcd4a48-2d37-4909-9f78-f7a9eb4ef903"); // VIEWER +const LLUUID IMG_ALPHA_GRAD ("e97cf410-8e61-7005-ec06-629eba4cd1fb"); // VIEWER +const LLUUID IMG_ALPHA_GRAD_2D ("38b86f85-2575-52a9-a531-23108d8da837"); // VIEWER +const LLUUID IMG_TRANSPARENT ("8dcd4a48-2d37-4909-9f78-f7a9eb4ef903"); // VIEWER -const LLUUID TERRAIN_DIRT_DETAIL ("0bc58228-74a0-7e83-89bc-5c23464bcec5"); // VIEWER -const LLUUID TERRAIN_GRASS_DETAIL ("63338ede-0037-c4fd-855b-015d77112fc8"); // VIEWER -const LLUUID TERRAIN_MOUNTAIN_DETAIL ("303cd381-8560-7579-23f1-f0a880799740"); // VIEWER -const LLUUID TERRAIN_ROCK_DETAIL ("53a2f406-4895-1d13-d541-d2e3b86bc19c"); // VIEWER +const LLUUID TERRAIN_DIRT_DETAIL ("0bc58228-74a0-7e83-89bc-5c23464bcec5"); // VIEWER +const LLUUID TERRAIN_GRASS_DETAIL ("63338ede-0037-c4fd-855b-015d77112fc8"); // VIEWER +const LLUUID TERRAIN_MOUNTAIN_DETAIL ("303cd381-8560-7579-23f1-f0a880799740"); // VIEWER +const LLUUID TERRAIN_ROCK_DETAIL ("53a2f406-4895-1d13-d541-d2e3b86bc19c"); // VIEWER -const LLUUID DEFAULT_WATER_NORMAL ("822ded49-9a6c-f61c-cb89-6df54f42cdf4"); // VIEWER +const LLUUID DEFAULT_WATER_NORMAL ("822ded49-9a6c-f61c-cb89-6df54f42cdf4"); // VIEWER const LLUUID DEFAULT_OBJECT_TEXTURE ("89556747-24cb-43ed-920b-47caed15465f"); // On dataserver const LLUUID DEFAULT_OBJECT_SPECULAR ("87e0e8f7-8729-1ea8-cfc9-8915773009db"); // On dataserver diff --git a/indra/llcommon/indra_constants.h b/indra/llcommon/indra_constants.h index a16cfac2b9..811313e56e 100644 --- a/indra/llcommon/indra_constants.h +++ b/indra/llcommon/indra_constants.h @@ -1,25 +1,25 @@ -/** +/** * @file indra_constants.h * @brief some useful short term constants for Indra * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -37,21 +37,21 @@ static const U32 REGION_WIDTH_U32 = 256; const F32 REGION_HEIGHT_METERS = 4096.f; -const F32 DEFAULT_AGENT_DEPTH = 0.45f; -const F32 DEFAULT_AGENT_WIDTH = 0.60f; -const F32 DEFAULT_AGENT_HEIGHT = 1.9f; +const F32 DEFAULT_AGENT_DEPTH = 0.45f; +const F32 DEFAULT_AGENT_WIDTH = 0.60f; +const F32 DEFAULT_AGENT_HEIGHT = 1.9f; enum ETerrainBrushType { - // the valid brush numbers cannot be reordered, because they - // are used in the binary LSL format as arguments to llModifyLand() - E_LANDBRUSH_LEVEL = 0, - E_LANDBRUSH_RAISE = 1, - E_LANDBRUSH_LOWER = 2, - E_LANDBRUSH_SMOOTH = 3, - E_LANDBRUSH_NOISE = 4, - E_LANDBRUSH_REVERT = 5, - E_LANDBRUSH_INVALID = 6 + // the valid brush numbers cannot be reordered, because they + // are used in the binary LSL format as arguments to llModifyLand() + E_LANDBRUSH_LEVEL = 0, + E_LANDBRUSH_RAISE = 1, + E_LANDBRUSH_LOWER = 2, + E_LANDBRUSH_SMOOTH = 3, + E_LANDBRUSH_NOISE = 4, + E_LANDBRUSH_REVERT = 5, + E_LANDBRUSH_INVALID = 6 }; enum EMouseClickType{ @@ -67,101 +67,101 @@ enum EMouseClickType{ // keys // Bit masks for various keyboard modifier keys. -const MASK MASK_NONE = 0x0000; -const MASK MASK_CONTROL = 0x0001; // Mapped to cmd on Macs -const MASK MASK_ALT = 0x0002; -const MASK MASK_SHIFT = 0x0004; +const MASK MASK_NONE = 0x0000; +const MASK MASK_CONTROL = 0x0001; // Mapped to cmd on Macs +const MASK MASK_ALT = 0x0002; +const MASK MASK_SHIFT = 0x0004; const MASK MASK_NORMALKEYS = 0x0007; // A real mask - only get the bits for normal modifier keys -const MASK MASK_MAC_CONTROL = 0x0008; // Un-mapped Ctrl key on Macs, not used on Windows -const MASK MASK_MODIFIERS = MASK_CONTROL|MASK_ALT|MASK_SHIFT|MASK_MAC_CONTROL; +const MASK MASK_MAC_CONTROL = 0x0008; // Un-mapped Ctrl key on Macs, not used on Windows +const MASK MASK_MODIFIERS = MASK_CONTROL|MASK_ALT|MASK_SHIFT|MASK_MAC_CONTROL; // Special keys go into >128 -const KEY KEY_SPECIAL = 0x80; // special keys start here -const KEY KEY_RETURN = 0x81; -const KEY KEY_LEFT = 0x82; -const KEY KEY_RIGHT = 0x83; -const KEY KEY_UP = 0x84; -const KEY KEY_DOWN = 0x85; -const KEY KEY_ESCAPE = 0x86; +const KEY KEY_SPECIAL = 0x80; // special keys start here +const KEY KEY_RETURN = 0x81; +const KEY KEY_LEFT = 0x82; +const KEY KEY_RIGHT = 0x83; +const KEY KEY_UP = 0x84; +const KEY KEY_DOWN = 0x85; +const KEY KEY_ESCAPE = 0x86; const KEY KEY_BACKSPACE =0x87; -const KEY KEY_DELETE = 0x88; -const KEY KEY_SHIFT = 0x89; -const KEY KEY_CONTROL = 0x8A; -const KEY KEY_ALT = 0x8B; -const KEY KEY_HOME = 0x8C; -const KEY KEY_END = 0x8D; +const KEY KEY_DELETE = 0x88; +const KEY KEY_SHIFT = 0x89; +const KEY KEY_CONTROL = 0x8A; +const KEY KEY_ALT = 0x8B; +const KEY KEY_HOME = 0x8C; +const KEY KEY_END = 0x8D; const KEY KEY_PAGE_UP = 0x8E; const KEY KEY_PAGE_DOWN = 0x8F; const KEY KEY_HYPHEN = 0x90; const KEY KEY_EQUALS = 0x91; const KEY KEY_INSERT = 0x92; const KEY KEY_CAPSLOCK = 0x93; -const KEY KEY_TAB = 0x94; -const KEY KEY_ADD = 0x95; +const KEY KEY_TAB = 0x94; +const KEY KEY_ADD = 0x95; const KEY KEY_SUBTRACT =0x96; const KEY KEY_MULTIPLY =0x97; -const KEY KEY_DIVIDE = 0x98; -const KEY KEY_F1 = 0xA1; -const KEY KEY_F2 = 0xA2; -const KEY KEY_F3 = 0xA3; -const KEY KEY_F4 = 0xA4; -const KEY KEY_F5 = 0xA5; -const KEY KEY_F6 = 0xA6; -const KEY KEY_F7 = 0xA7; -const KEY KEY_F8 = 0xA8; -const KEY KEY_F9 = 0xA9; -const KEY KEY_F10 = 0xAA; -const KEY KEY_F11 = 0xAB; -const KEY KEY_F12 = 0xAC; - -const KEY KEY_PAD_UP = 0xC0; -const KEY KEY_PAD_DOWN = 0xC1; -const KEY KEY_PAD_LEFT = 0xC2; -const KEY KEY_PAD_RIGHT = 0xC3; -const KEY KEY_PAD_HOME = 0xC4; -const KEY KEY_PAD_END = 0xC5; -const KEY KEY_PAD_PGUP = 0xC6; -const KEY KEY_PAD_PGDN = 0xC7; -const KEY KEY_PAD_CENTER = 0xC8; // the 5 in the middle -const KEY KEY_PAD_INS = 0xC9; -const KEY KEY_PAD_DEL = 0xCA; -const KEY KEY_PAD_RETURN = 0xCB; -const KEY KEY_PAD_ADD = 0xCC; // not used -const KEY KEY_PAD_SUBTRACT = 0xCD; // not used +const KEY KEY_DIVIDE = 0x98; +const KEY KEY_F1 = 0xA1; +const KEY KEY_F2 = 0xA2; +const KEY KEY_F3 = 0xA3; +const KEY KEY_F4 = 0xA4; +const KEY KEY_F5 = 0xA5; +const KEY KEY_F6 = 0xA6; +const KEY KEY_F7 = 0xA7; +const KEY KEY_F8 = 0xA8; +const KEY KEY_F9 = 0xA9; +const KEY KEY_F10 = 0xAA; +const KEY KEY_F11 = 0xAB; +const KEY KEY_F12 = 0xAC; + +const KEY KEY_PAD_UP = 0xC0; +const KEY KEY_PAD_DOWN = 0xC1; +const KEY KEY_PAD_LEFT = 0xC2; +const KEY KEY_PAD_RIGHT = 0xC3; +const KEY KEY_PAD_HOME = 0xC4; +const KEY KEY_PAD_END = 0xC5; +const KEY KEY_PAD_PGUP = 0xC6; +const KEY KEY_PAD_PGDN = 0xC7; +const KEY KEY_PAD_CENTER = 0xC8; // the 5 in the middle +const KEY KEY_PAD_INS = 0xC9; +const KEY KEY_PAD_DEL = 0xCA; +const KEY KEY_PAD_RETURN = 0xCB; +const KEY KEY_PAD_ADD = 0xCC; // not used +const KEY KEY_PAD_SUBTRACT = 0xCD; // not used const KEY KEY_PAD_MULTIPLY = 0xCE; // not used -const KEY KEY_PAD_DIVIDE = 0xCF; // not used - -const KEY KEY_BUTTON0 = 0xD0; -const KEY KEY_BUTTON1 = 0xD1; -const KEY KEY_BUTTON2 = 0xD2; -const KEY KEY_BUTTON3 = 0xD3; -const KEY KEY_BUTTON4 = 0xD4; -const KEY KEY_BUTTON5 = 0xD5; -const KEY KEY_BUTTON6 = 0xD6; -const KEY KEY_BUTTON7 = 0xD7; -const KEY KEY_BUTTON8 = 0xD8; -const KEY KEY_BUTTON9 = 0xD9; -const KEY KEY_BUTTON10 = 0xDA; -const KEY KEY_BUTTON11 = 0xDB; -const KEY KEY_BUTTON12 = 0xDC; -const KEY KEY_BUTTON13 = 0xDD; -const KEY KEY_BUTTON14 = 0xDE; -const KEY KEY_BUTTON15 = 0xDF; - -const KEY KEY_NONE = 0xFF; // not sent from keyboard. For internal use only. +const KEY KEY_PAD_DIVIDE = 0xCF; // not used + +const KEY KEY_BUTTON0 = 0xD0; +const KEY KEY_BUTTON1 = 0xD1; +const KEY KEY_BUTTON2 = 0xD2; +const KEY KEY_BUTTON3 = 0xD3; +const KEY KEY_BUTTON4 = 0xD4; +const KEY KEY_BUTTON5 = 0xD5; +const KEY KEY_BUTTON6 = 0xD6; +const KEY KEY_BUTTON7 = 0xD7; +const KEY KEY_BUTTON8 = 0xD8; +const KEY KEY_BUTTON9 = 0xD9; +const KEY KEY_BUTTON10 = 0xDA; +const KEY KEY_BUTTON11 = 0xDB; +const KEY KEY_BUTTON12 = 0xDC; +const KEY KEY_BUTTON13 = 0xDD; +const KEY KEY_BUTTON14 = 0xDE; +const KEY KEY_BUTTON15 = 0xDF; + +const KEY KEY_NONE = 0xFF; // not sent from keyboard. For internal use only. const S32 KEY_COUNT = 256; -const F32 DEFAULT_WATER_HEIGHT = 20.0f; +const F32 DEFAULT_WATER_HEIGHT = 20.0f; // Maturity ratings for simulators -const U8 SIM_ACCESS_MIN = 0; // Treated as 'unknown', usually ends up being SIM_ACCESS_PG -const U8 SIM_ACCESS_PG = 13; -const U8 SIM_ACCESS_MATURE = 21; -const U8 SIM_ACCESS_ADULT = 42; // Seriously Adult Only -const U8 SIM_ACCESS_DOWN = 254; -const U8 SIM_ACCESS_MAX = SIM_ACCESS_ADULT; +const U8 SIM_ACCESS_MIN = 0; // Treated as 'unknown', usually ends up being SIM_ACCESS_PG +const U8 SIM_ACCESS_PG = 13; +const U8 SIM_ACCESS_MATURE = 21; +const U8 SIM_ACCESS_ADULT = 42; // Seriously Adult Only +const U8 SIM_ACCESS_DOWN = 254; +const U8 SIM_ACCESS_MAX = SIM_ACCESS_ADULT; // attachment constants const U8 ATTACHMENT_ADD = 0x80; @@ -258,84 +258,84 @@ const U32 PARCEL_MEDIA_COMMAND_LOOP_SET = 13; const S32 CHAT_CHANNEL_DEBUG = S32_MAX; // agent constants -const U32 CONTROL_AT_POS_INDEX = 0; -const U32 CONTROL_AT_NEG_INDEX = 1; -const U32 CONTROL_LEFT_POS_INDEX = 2; -const U32 CONTROL_LEFT_NEG_INDEX = 3; -const U32 CONTROL_UP_POS_INDEX = 4; -const U32 CONTROL_UP_NEG_INDEX = 5; -const U32 CONTROL_PITCH_POS_INDEX = 6; -const U32 CONTROL_PITCH_NEG_INDEX = 7; -const U32 CONTROL_YAW_POS_INDEX = 8; -const U32 CONTROL_YAW_NEG_INDEX = 9; -const U32 CONTROL_FAST_AT_INDEX = 10; -const U32 CONTROL_FAST_LEFT_INDEX = 11; -const U32 CONTROL_FAST_UP_INDEX = 12; -const U32 CONTROL_FLY_INDEX = 13; -const U32 CONTROL_STOP_INDEX = 14; -const U32 CONTROL_FINISH_ANIM_INDEX = 15; -const U32 CONTROL_STAND_UP_INDEX = 16; -const U32 CONTROL_SIT_ON_GROUND_INDEX = 17; -const U32 CONTROL_MOUSELOOK_INDEX = 18; -const U32 CONTROL_NUDGE_AT_POS_INDEX = 19; -const U32 CONTROL_NUDGE_AT_NEG_INDEX = 20; -const U32 CONTROL_NUDGE_LEFT_POS_INDEX = 21; -const U32 CONTROL_NUDGE_LEFT_NEG_INDEX = 22; -const U32 CONTROL_NUDGE_UP_POS_INDEX = 23; -const U32 CONTROL_NUDGE_UP_NEG_INDEX = 24; -const U32 CONTROL_TURN_LEFT_INDEX = 25; -const U32 CONTROL_TURN_RIGHT_INDEX = 26; -const U32 CONTROL_AWAY_INDEX = 27; -const U32 CONTROL_LBUTTON_DOWN_INDEX = 28; -const U32 CONTROL_LBUTTON_UP_INDEX = 29; -const U32 CONTROL_ML_LBUTTON_DOWN_INDEX = 30; -const U32 CONTROL_ML_LBUTTON_UP_INDEX = 31; -const U32 TOTAL_CONTROLS = 32; - -const U32 AGENT_CONTROL_AT_POS = 0x1 << CONTROL_AT_POS_INDEX; // 0x00000001 -const U32 AGENT_CONTROL_AT_NEG = 0x1 << CONTROL_AT_NEG_INDEX; // 0x00000002 -const U32 AGENT_CONTROL_LEFT_POS = 0x1 << CONTROL_LEFT_POS_INDEX; // 0x00000004 -const U32 AGENT_CONTROL_LEFT_NEG = 0x1 << CONTROL_LEFT_NEG_INDEX; // 0x00000008 -const U32 AGENT_CONTROL_UP_POS = 0x1 << CONTROL_UP_POS_INDEX; // 0x00000010 -const U32 AGENT_CONTROL_UP_NEG = 0x1 << CONTROL_UP_NEG_INDEX; // 0x00000020 -const U32 AGENT_CONTROL_PITCH_POS = 0x1 << CONTROL_PITCH_POS_INDEX; // 0x00000040 -const U32 AGENT_CONTROL_PITCH_NEG = 0x1 << CONTROL_PITCH_NEG_INDEX; // 0x00000080 -const U32 AGENT_CONTROL_YAW_POS = 0x1 << CONTROL_YAW_POS_INDEX; // 0x00000100 -const U32 AGENT_CONTROL_YAW_NEG = 0x1 << CONTROL_YAW_NEG_INDEX; // 0x00000200 - -const U32 AGENT_CONTROL_FAST_AT = 0x1 << CONTROL_FAST_AT_INDEX; // 0x00000400 -const U32 AGENT_CONTROL_FAST_LEFT = 0x1 << CONTROL_FAST_LEFT_INDEX; // 0x00000800 -const U32 AGENT_CONTROL_FAST_UP = 0x1 << CONTROL_FAST_UP_INDEX; // 0x00001000 - -const U32 AGENT_CONTROL_FLY = 0x1 << CONTROL_FLY_INDEX; // 0x00002000 -const U32 AGENT_CONTROL_STOP = 0x1 << CONTROL_STOP_INDEX; // 0x00004000 -const U32 AGENT_CONTROL_FINISH_ANIM = 0x1 << CONTROL_FINISH_ANIM_INDEX; // 0x00008000 -const U32 AGENT_CONTROL_STAND_UP = 0x1 << CONTROL_STAND_UP_INDEX; // 0x00010000 -const U32 AGENT_CONTROL_SIT_ON_GROUND = 0x1 << CONTROL_SIT_ON_GROUND_INDEX; // 0x00020000 -const U32 AGENT_CONTROL_MOUSELOOK = 0x1 << CONTROL_MOUSELOOK_INDEX; // 0x00040000 - -const U32 AGENT_CONTROL_NUDGE_AT_POS = 0x1 << CONTROL_NUDGE_AT_POS_INDEX; // 0x00080000 -const U32 AGENT_CONTROL_NUDGE_AT_NEG = 0x1 << CONTROL_NUDGE_AT_NEG_INDEX; // 0x00100000 -const U32 AGENT_CONTROL_NUDGE_LEFT_POS = 0x1 << CONTROL_NUDGE_LEFT_POS_INDEX; // 0x00200000 -const U32 AGENT_CONTROL_NUDGE_LEFT_NEG = 0x1 << CONTROL_NUDGE_LEFT_NEG_INDEX; // 0x00400000 -const U32 AGENT_CONTROL_NUDGE_UP_POS = 0x1 << CONTROL_NUDGE_UP_POS_INDEX; // 0x00800000 -const U32 AGENT_CONTROL_NUDGE_UP_NEG = 0x1 << CONTROL_NUDGE_UP_NEG_INDEX; // 0x01000000 -const U32 AGENT_CONTROL_TURN_LEFT = 0x1 << CONTROL_TURN_LEFT_INDEX; // 0x02000000 -const U32 AGENT_CONTROL_TURN_RIGHT = 0x1 << CONTROL_TURN_RIGHT_INDEX; // 0x04000000 - -const U32 AGENT_CONTROL_AWAY = 0x1 << CONTROL_AWAY_INDEX; // 0x08000000 - -const U32 AGENT_CONTROL_LBUTTON_DOWN = 0x1 << CONTROL_LBUTTON_DOWN_INDEX; // 0x10000000 -const U32 AGENT_CONTROL_LBUTTON_UP = 0x1 << CONTROL_LBUTTON_UP_INDEX; // 0x20000000 -const U32 AGENT_CONTROL_ML_LBUTTON_DOWN = 0x1 << CONTROL_ML_LBUTTON_DOWN_INDEX; // 0x40000000 -const U32 AGENT_CONTROL_ML_LBUTTON_UP = ((U32)0x1) << CONTROL_ML_LBUTTON_UP_INDEX; // 0x80000000 - -// move these up so that we can hide them in "State" for object updates +const U32 CONTROL_AT_POS_INDEX = 0; +const U32 CONTROL_AT_NEG_INDEX = 1; +const U32 CONTROL_LEFT_POS_INDEX = 2; +const U32 CONTROL_LEFT_NEG_INDEX = 3; +const U32 CONTROL_UP_POS_INDEX = 4; +const U32 CONTROL_UP_NEG_INDEX = 5; +const U32 CONTROL_PITCH_POS_INDEX = 6; +const U32 CONTROL_PITCH_NEG_INDEX = 7; +const U32 CONTROL_YAW_POS_INDEX = 8; +const U32 CONTROL_YAW_NEG_INDEX = 9; +const U32 CONTROL_FAST_AT_INDEX = 10; +const U32 CONTROL_FAST_LEFT_INDEX = 11; +const U32 CONTROL_FAST_UP_INDEX = 12; +const U32 CONTROL_FLY_INDEX = 13; +const U32 CONTROL_STOP_INDEX = 14; +const U32 CONTROL_FINISH_ANIM_INDEX = 15; +const U32 CONTROL_STAND_UP_INDEX = 16; +const U32 CONTROL_SIT_ON_GROUND_INDEX = 17; +const U32 CONTROL_MOUSELOOK_INDEX = 18; +const U32 CONTROL_NUDGE_AT_POS_INDEX = 19; +const U32 CONTROL_NUDGE_AT_NEG_INDEX = 20; +const U32 CONTROL_NUDGE_LEFT_POS_INDEX = 21; +const U32 CONTROL_NUDGE_LEFT_NEG_INDEX = 22; +const U32 CONTROL_NUDGE_UP_POS_INDEX = 23; +const U32 CONTROL_NUDGE_UP_NEG_INDEX = 24; +const U32 CONTROL_TURN_LEFT_INDEX = 25; +const U32 CONTROL_TURN_RIGHT_INDEX = 26; +const U32 CONTROL_AWAY_INDEX = 27; +const U32 CONTROL_LBUTTON_DOWN_INDEX = 28; +const U32 CONTROL_LBUTTON_UP_INDEX = 29; +const U32 CONTROL_ML_LBUTTON_DOWN_INDEX = 30; +const U32 CONTROL_ML_LBUTTON_UP_INDEX = 31; +const U32 TOTAL_CONTROLS = 32; + +const U32 AGENT_CONTROL_AT_POS = 0x1 << CONTROL_AT_POS_INDEX; // 0x00000001 +const U32 AGENT_CONTROL_AT_NEG = 0x1 << CONTROL_AT_NEG_INDEX; // 0x00000002 +const U32 AGENT_CONTROL_LEFT_POS = 0x1 << CONTROL_LEFT_POS_INDEX; // 0x00000004 +const U32 AGENT_CONTROL_LEFT_NEG = 0x1 << CONTROL_LEFT_NEG_INDEX; // 0x00000008 +const U32 AGENT_CONTROL_UP_POS = 0x1 << CONTROL_UP_POS_INDEX; // 0x00000010 +const U32 AGENT_CONTROL_UP_NEG = 0x1 << CONTROL_UP_NEG_INDEX; // 0x00000020 +const U32 AGENT_CONTROL_PITCH_POS = 0x1 << CONTROL_PITCH_POS_INDEX; // 0x00000040 +const U32 AGENT_CONTROL_PITCH_NEG = 0x1 << CONTROL_PITCH_NEG_INDEX; // 0x00000080 +const U32 AGENT_CONTROL_YAW_POS = 0x1 << CONTROL_YAW_POS_INDEX; // 0x00000100 +const U32 AGENT_CONTROL_YAW_NEG = 0x1 << CONTROL_YAW_NEG_INDEX; // 0x00000200 + +const U32 AGENT_CONTROL_FAST_AT = 0x1 << CONTROL_FAST_AT_INDEX; // 0x00000400 +const U32 AGENT_CONTROL_FAST_LEFT = 0x1 << CONTROL_FAST_LEFT_INDEX; // 0x00000800 +const U32 AGENT_CONTROL_FAST_UP = 0x1 << CONTROL_FAST_UP_INDEX; // 0x00001000 + +const U32 AGENT_CONTROL_FLY = 0x1 << CONTROL_FLY_INDEX; // 0x00002000 +const U32 AGENT_CONTROL_STOP = 0x1 << CONTROL_STOP_INDEX; // 0x00004000 +const U32 AGENT_CONTROL_FINISH_ANIM = 0x1 << CONTROL_FINISH_ANIM_INDEX; // 0x00008000 +const U32 AGENT_CONTROL_STAND_UP = 0x1 << CONTROL_STAND_UP_INDEX; // 0x00010000 +const U32 AGENT_CONTROL_SIT_ON_GROUND = 0x1 << CONTROL_SIT_ON_GROUND_INDEX; // 0x00020000 +const U32 AGENT_CONTROL_MOUSELOOK = 0x1 << CONTROL_MOUSELOOK_INDEX; // 0x00040000 + +const U32 AGENT_CONTROL_NUDGE_AT_POS = 0x1 << CONTROL_NUDGE_AT_POS_INDEX; // 0x00080000 +const U32 AGENT_CONTROL_NUDGE_AT_NEG = 0x1 << CONTROL_NUDGE_AT_NEG_INDEX; // 0x00100000 +const U32 AGENT_CONTROL_NUDGE_LEFT_POS = 0x1 << CONTROL_NUDGE_LEFT_POS_INDEX; // 0x00200000 +const U32 AGENT_CONTROL_NUDGE_LEFT_NEG = 0x1 << CONTROL_NUDGE_LEFT_NEG_INDEX; // 0x00400000 +const U32 AGENT_CONTROL_NUDGE_UP_POS = 0x1 << CONTROL_NUDGE_UP_POS_INDEX; // 0x00800000 +const U32 AGENT_CONTROL_NUDGE_UP_NEG = 0x1 << CONTROL_NUDGE_UP_NEG_INDEX; // 0x01000000 +const U32 AGENT_CONTROL_TURN_LEFT = 0x1 << CONTROL_TURN_LEFT_INDEX; // 0x02000000 +const U32 AGENT_CONTROL_TURN_RIGHT = 0x1 << CONTROL_TURN_RIGHT_INDEX; // 0x04000000 + +const U32 AGENT_CONTROL_AWAY = 0x1 << CONTROL_AWAY_INDEX; // 0x08000000 + +const U32 AGENT_CONTROL_LBUTTON_DOWN = 0x1 << CONTROL_LBUTTON_DOWN_INDEX; // 0x10000000 +const U32 AGENT_CONTROL_LBUTTON_UP = 0x1 << CONTROL_LBUTTON_UP_INDEX; // 0x20000000 +const U32 AGENT_CONTROL_ML_LBUTTON_DOWN = 0x1 << CONTROL_ML_LBUTTON_DOWN_INDEX; // 0x40000000 +const U32 AGENT_CONTROL_ML_LBUTTON_UP = ((U32)0x1) << CONTROL_ML_LBUTTON_UP_INDEX; // 0x80000000 + +// move these up so that we can hide them in "State" for object updates // (for now) -const U32 AGENT_ATTACH_OFFSET = 4; -const U32 AGENT_ATTACH_MASK = 0xf << AGENT_ATTACH_OFFSET; +const U32 AGENT_ATTACH_OFFSET = 4; +const U32 AGENT_ATTACH_MASK = 0xf << AGENT_ATTACH_OFFSET; -// RN: this method swaps the upper and lower nibbles to maintain backward +// RN: this method swaps the upper and lower nibbles to maintain backward // compatibility with old objects that only used the upper nibble #define ATTACHMENT_ID_FROM_STATE(state) ((S32)((((U8)state & AGENT_ATTACH_MASK) >> 4) | (((U8)state & ~AGENT_ATTACH_MASK) << 4))) diff --git a/indra/llcommon/is_approx_equal_fraction.h b/indra/llcommon/is_approx_equal_fraction.h index 4a9b2e2725..79f4f5ebbd 100644 --- a/indra/llcommon/is_approx_equal_fraction.h +++ b/indra/llcommon/is_approx_equal_fraction.h @@ -5,25 +5,25 @@ * @brief lltut.h uses is_approx_equal_fraction(). Moved to this header * file in llcommon so we can use lltut.h for llcommon tests without * making llcommon depend on llmath. - * + * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcommon/lazyeventapi.cpp b/indra/llcommon/lazyeventapi.cpp index 028af9f33f..91db0ee4a6 100644 --- a/indra/llcommon/lazyeventapi.cpp +++ b/indra/llcommon/lazyeventapi.cpp @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2022-06-17 * @brief Implementation for lazyeventapi. - * + * * $LicenseInfo:firstyear=2022&license=viewerlgpl$ * Copyright (c) 2022, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/lazyeventapi.h b/indra/llcommon/lazyeventapi.h index e36831270b..0e5df4e6f4 100644 --- a/indra/llcommon/lazyeventapi.h +++ b/indra/llcommon/lazyeventapi.h @@ -4,7 +4,7 @@ * @date 2022-06-16 * @brief Declaring a static module-scope LazyEventAPI registers a specific * LLEventAPI for future on-demand instantiation. - * + * * $LicenseInfo:firstyear=2022&license=viewerlgpl$ * Copyright (c) 2022, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/linden_common.h b/indra/llcommon/linden_common.h index a228fd22be..a918caa2e8 100644 --- a/indra/llcommon/linden_common.h +++ b/indra/llcommon/linden_common.h @@ -1,25 +1,25 @@ -/** +/** * @file linden_common.h * @brief Includes common headers that are always safe to include * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcommon/llalignedarray.h b/indra/llcommon/llalignedarray.h index da9d98c16c..0ba8b34cb6 100644 --- a/indra/llcommon/llalignedarray.h +++ b/indra/llcommon/llalignedarray.h @@ -1,25 +1,25 @@ -/** +/** * @file llalignedarray.h * @brief A static array which obeys alignment restrictions and mimics std::vector accessors. * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -33,94 +33,94 @@ template class LLAlignedArray { public: - T* mArray; - U32 mElementCount; - U32 mCapacity; - - LLAlignedArray(); - ~LLAlignedArray(); - - void push_back(const T& elem); - U32 size() const { return mElementCount; } - void resize(U32 size); - T* append(S32 N); - T& operator[](int idx); - const T& operator[](int idx) const; + T* mArray; + U32 mElementCount; + U32 mCapacity; + + LLAlignedArray(); + ~LLAlignedArray(); + + void push_back(const T& elem); + U32 size() const { return mElementCount; } + void resize(U32 size); + T* append(S32 N); + T& operator[](int idx); + const T& operator[](int idx) const; }; template LLAlignedArray::LLAlignedArray() { - llassert(alignment >= 16); - mArray = NULL; - mElementCount = 0; - mCapacity = 0; + llassert(alignment >= 16); + mArray = NULL; + mElementCount = 0; + mCapacity = 0; } template LLAlignedArray::~LLAlignedArray() { - ll_aligned_free(mArray); - mArray = NULL; - mElementCount = 0; - mCapacity = 0; + ll_aligned_free(mArray); + mArray = NULL; + mElementCount = 0; + mCapacity = 0; } template void LLAlignedArray::push_back(const T& elem) { - T* old_buf = NULL; - if (mCapacity <= mElementCount) - { - mCapacity++; - mCapacity *= 2; - T* new_buf = (T*) ll_aligned_malloc(mCapacity*sizeof(T)); - if (mArray) - { - ll_memcpy_nonaliased_aligned_16((char*)new_buf, (char*)mArray, sizeof(T)*mElementCount); - } - old_buf = mArray; - mArray = new_buf; - } - - mArray[mElementCount++] = elem; - - //delete old array here to prevent error on a.push_back(a[0]) - ll_aligned_free(old_buf); + T* old_buf = NULL; + if (mCapacity <= mElementCount) + { + mCapacity++; + mCapacity *= 2; + T* new_buf = (T*) ll_aligned_malloc(mCapacity*sizeof(T)); + if (mArray) + { + ll_memcpy_nonaliased_aligned_16((char*)new_buf, (char*)mArray, sizeof(T)*mElementCount); + } + old_buf = mArray; + mArray = new_buf; + } + + mArray[mElementCount++] = elem; + + //delete old array here to prevent error on a.push_back(a[0]) + ll_aligned_free(old_buf); } template void LLAlignedArray::resize(U32 size) { - if (mCapacity < size) - { - mCapacity = size+mCapacity*2; - T* new_buf = mCapacity > 0 ? (T*) ll_aligned_malloc(mCapacity*sizeof(T)) : NULL; - if (mArray) - { - ll_memcpy_nonaliased_aligned_16((char*) new_buf, (char*) mArray, sizeof(T)*mElementCount); - ll_aligned_free(mArray); - } - - /*for (U32 i = mElementCount; i < mCapacity; ++i) - { - new(new_buf+i) T(); - }*/ - mArray = new_buf; - } - - mElementCount = size; + if (mCapacity < size) + { + mCapacity = size+mCapacity*2; + T* new_buf = mCapacity > 0 ? (T*) ll_aligned_malloc(mCapacity*sizeof(T)) : NULL; + if (mArray) + { + ll_memcpy_nonaliased_aligned_16((char*) new_buf, (char*) mArray, sizeof(T)*mElementCount); + ll_aligned_free(mArray); + } + + /*for (U32 i = mElementCount; i < mCapacity; ++i) + { + new(new_buf+i) T(); + }*/ + mArray = new_buf; + } + + mElementCount = size; } template T& LLAlignedArray::operator[](int idx) { - if(idx >= mElementCount || idx < 0) + if(idx >= mElementCount || idx < 0) { LL_ERRS() << "Out of bounds LLAlignedArray, requested: " << (S32)idx << " size: " << mElementCount << LL_ENDL; } - return mArray[idx]; + return mArray[idx]; } template @@ -130,15 +130,15 @@ const T& LLAlignedArray::operator[](int idx) const { LL_ERRS() << "Out of bounds LLAlignedArray, requested: " << (S32)idx << " size: " << mElementCount << LL_ENDL; } - return mArray[idx]; + return mArray[idx]; } template T* LLAlignedArray::append(S32 N) { - U32 sz = size(); - resize(sz+N); - return &((*this)[sz]); + U32 sz = size(); + resize(sz+N); + return &((*this)[sz]); } #endif diff --git a/indra/llcommon/llallocator.cpp b/indra/llcommon/llallocator.cpp index ac97fb71dd..abe3779b85 100644 --- a/indra/llcommon/llallocator.cpp +++ b/indra/llcommon/llallocator.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llallocator.cpp * @brief Implementation of the LLAllocator class. * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcommon/llallocator.h b/indra/llcommon/llallocator.h index d26ad73c5b..aa3eead546 100644 --- a/indra/llcommon/llallocator.h +++ b/indra/llcommon/llallocator.h @@ -1,25 +1,25 @@ -/** +/** * @file llallocator.h * @brief Declaration of the LLAllocator class. * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcommon/llallocator_heap_profile.cpp b/indra/llcommon/llallocator_heap_profile.cpp index c6d9542b42..85e56b4db4 100644 --- a/indra/llcommon/llallocator_heap_profile.cpp +++ b/indra/llcommon/llallocator_heap_profile.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llallocator_heap_profile.cpp * @brief Implementation of the parser for tcmalloc heap profile data. * @author Brad Kittenbrink @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -67,7 +67,7 @@ void LLAllocatorHeapProfile::parse(std::string const & prof_text) std::string::const_iterator prof_begin = prof_text.begin() + HEAP_PROFILE_MAGIC_STR.length(); - range_t prof_range(prof_begin, prof_text.end()); + range_t prof_range(prof_begin, prof_text.end()); boost::algorithm::split(prof_lines, prof_range, boost::bind(std::equal_to(), '\n', _1)); @@ -107,34 +107,34 @@ void LLAllocatorHeapProfile::parse(std::string const & prof_text) ++j; while(j != line_elems.end() && j->empty()) { ++j; } // skip any separator tokens - llassert(j != line_elems.end()); + llassert(j != line_elems.end()); if (j != line_elems.end()) - { - ++j; // skip the '@' - - mLines.push_back(line(live_count, live_size, tot_count, tot_size)); - line & current_line = mLines.back(); - - for(; j != line_elems.end(); ++j) - { - if(!j->empty()) - { - U32 marker = boost::lexical_cast(*j); - current_line.mTrace.push_back(marker); - } - } - } + { + ++j; // skip the '@' + + mLines.push_back(line(live_count, live_size, tot_count, tot_size)); + line & current_line = mLines.back(); + + for(; j != line_elems.end(); ++j) + { + if(!j->empty()) + { + U32 marker = boost::lexical_cast(*j); + current_line.mTrace.push_back(marker); + } + } + } } // *TODO - parse MAPPED_LIBRARIES section here if we're ever interested in it } void LLAllocatorHeapProfile::dump(std::ostream & out) const { - for (const LLAllocatorHeapProfile::line& line : mLines) + for (const LLAllocatorHeapProfile::line& line : mLines) { out << line.mLiveCount << ": " << line.mLiveSize << '[' << line.mTotalCount << ": " << line.mTotalSize << "] @"; - for (const stack_marker marker : line.mTrace) + for (const stack_marker marker : line.mTrace) { out << ' ' << marker; } diff --git a/indra/llcommon/llallocator_heap_profile.h b/indra/llcommon/llallocator_heap_profile.h index 69300b829b..22f284b703 100644 --- a/indra/llcommon/llallocator_heap_profile.h +++ b/indra/llcommon/llallocator_heap_profile.h @@ -1,4 +1,4 @@ -/** +/** * @file llallocator_heap_profile.h * @brief Declaration of the parser for tcmalloc heap profile data. * @author Brad Kittenbrink @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -59,7 +59,7 @@ public: { } - void parse(std::string const & prof_text); + void parse(std::string const & prof_text); void dump(std::ostream & out) const; diff --git a/indra/llcommon/llapp.cpp b/indra/llcommon/llapp.cpp index 90d0c28eb1..9729f68d23 100644 --- a/indra/llcommon/llapp.cpp +++ b/indra/llcommon/llapp.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llapp.cpp * @brief Implementation of the LLApp class. * * $LicenseInfo:firstyear=2003&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -70,8 +70,8 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *); #else // Called by breakpad exception handler after the minidump has been generated. bool unix_post_minidump_callback(const char *dump_dir, - const char *minidump_id, - void *context, bool succeeded); + const char *minidump_id, + void *context, bool succeeded); #endif # if LL_DARWIN @@ -94,7 +94,7 @@ LLApp* LLApp::sApplication = NULL; // Allows the generation of core files for post mortem under gdb // and disables crashlogger -BOOL LLApp::sDisableCrashlogger = FALSE; +BOOL LLApp::sDisableCrashlogger = FALSE; // Local flag for whether or not to do logging in signal handlers. //static @@ -108,222 +108,222 @@ LLAppErrorHandler LLApp::sErrorHandler = NULL; LLApp::LLApp() { - // Set our status to running - setStatus(APP_STATUS_RUNNING); + // Set our status to running + setStatus(APP_STATUS_RUNNING); + + LLCommon::initClass(); - LLCommon::initClass(); + // initialize the options structure. We need to make this an array + // because the structured data will not auto-allocate if we + // reference an invalid location with the [] operator. + mOptions = LLSD::emptyArray(); + LLSD sd; + for(int i = 0; i < PRIORITY_COUNT; ++i) + { + mOptions.append(sd); + } - // initialize the options structure. We need to make this an array - // because the structured data will not auto-allocate if we - // reference an invalid location with the [] operator. - mOptions = LLSD::emptyArray(); - LLSD sd; - for(int i = 0; i < PRIORITY_COUNT; ++i) - { - mOptions.append(sd); - } + // Make sure we clean up APR when we exit + // Don't need to do this if we're cleaning up APR in the destructor + //atexit(ll_cleanup_apr); - // Make sure we clean up APR when we exit - // Don't need to do this if we're cleaning up APR in the destructor - //atexit(ll_cleanup_apr); + // Set the application to this instance. + sApplication = this; - // Set the application to this instance. - sApplication = this; - - // initialize the buffer to write the minidump filename to - // (this is used to avoid allocating memory in the crash handler) - memset(mMinidumpPath, 0, MAX_MINDUMP_PATH_LENGTH); - mCrashReportPipeStr = L"\\\\.\\pipe\\LLCrashReporterPipe"; + // initialize the buffer to write the minidump filename to + // (this is used to avoid allocating memory in the crash handler) + memset(mMinidumpPath, 0, MAX_MINDUMP_PATH_LENGTH); + mCrashReportPipeStr = L"\\\\.\\pipe\\LLCrashReporterPipe"; } LLApp::~LLApp() { - // reclaim live file memory - std::for_each(mLiveFiles.begin(), mLiveFiles.end(), DeletePointer()); - mLiveFiles.clear(); + // reclaim live file memory + std::for_each(mLiveFiles.begin(), mLiveFiles.end(), DeletePointer()); + mLiveFiles.clear(); - setStopped(); + setStopped(); - SUBSYSTEM_CLEANUP_DBG(LLCommon); + SUBSYSTEM_CLEANUP_DBG(LLCommon); } // static LLApp* LLApp::instance() { - return sApplication; + return sApplication; } LLSD LLApp::getOption(const std::string& name) const { - LLSD rv; - LLSD::array_const_iterator iter = mOptions.beginArray(); - LLSD::array_const_iterator end = mOptions.endArray(); - for(; iter != end; ++iter) - { - rv = (*iter)[name]; - if(rv.isDefined()) break; - } - return rv; + LLSD rv; + LLSD::array_const_iterator iter = mOptions.beginArray(); + LLSD::array_const_iterator end = mOptions.endArray(); + for(; iter != end; ++iter) + { + rv = (*iter)[name]; + if(rv.isDefined()) break; + } + return rv; } bool LLApp::parseCommandOptions(int argc, char** argv) { - LLSD commands; - std::string name; - std::string value; - for(int ii = 1; ii < argc; ++ii) - { - if(argv[ii][0] != '-') - { - LL_INFOS() << "Did not find option identifier while parsing token: " - << argv[ii] << LL_ENDL; - return false; - } - int offset = 1; - if(argv[ii][1] == '-') ++offset; - name.assign(&argv[ii][offset]); - if(((ii+1) >= argc) || (argv[ii+1][0] == '-')) - { - // we found another option after this one or we have - // reached the end. simply record that this option was - // found and continue. - int flag = name.compare("logfile"); - if (0 == flag) - { - commands[name] = "log"; - } - else - { - commands[name] = true; - } - - continue; - } - ++ii; - value.assign(argv[ii]); + LLSD commands; + std::string name; + std::string value; + for(int ii = 1; ii < argc; ++ii) + { + if(argv[ii][0] != '-') + { + LL_INFOS() << "Did not find option identifier while parsing token: " + << argv[ii] << LL_ENDL; + return false; + } + int offset = 1; + if(argv[ii][1] == '-') ++offset; + name.assign(&argv[ii][offset]); + if(((ii+1) >= argc) || (argv[ii+1][0] == '-')) + { + // we found another option after this one or we have + // reached the end. simply record that this option was + // found and continue. + int flag = name.compare("logfile"); + if (0 == flag) + { + commands[name] = "log"; + } + else + { + commands[name] = true; + } + + continue; + } + ++ii; + value.assign(argv[ii]); #if LL_WINDOWS - //Windows changed command line parsing. Deal with it. - S32 slen = value.length() - 1; - S32 start = 0; - S32 end = slen; - if (argv[ii][start]=='"')start++; - if (argv[ii][end]=='"')end--; - if (start!=0 || end!=slen) - { - value = value.substr (start,end); - } + //Windows changed command line parsing. Deal with it. + S32 slen = value.length() - 1; + S32 start = 0; + S32 end = slen; + if (argv[ii][start]=='"')start++; + if (argv[ii][end]=='"')end--; + if (start!=0 || end!=slen) + { + value = value.substr (start,end); + } #endif - commands[name] = value; - } - setOptionData(PRIORITY_COMMAND_LINE, commands); - return true; + commands[name] = value; + } + setOptionData(PRIORITY_COMMAND_LINE, commands); + return true; } bool LLApp::parseCommandOptions(int argc, wchar_t** wargv) { - LLSD commands; - std::string name; - std::string value; - for(int ii = 1; ii < argc; ++ii) - { - if(wargv[ii][0] != '-') - { - LL_INFOS() << "Did not find option identifier while parsing token: " - << wargv[ii] << LL_ENDL; - return false; - } - int offset = 1; - if(wargv[ii][1] == '-') ++offset; + LLSD commands; + std::string name; + std::string value; + for(int ii = 1; ii < argc; ++ii) + { + if(wargv[ii][0] != '-') + { + LL_INFOS() << "Did not find option identifier while parsing token: " + << wargv[ii] << LL_ENDL; + return false; + } + int offset = 1; + if(wargv[ii][1] == '-') ++offset; #if LL_WINDOWS - name.assign(utf16str_to_utf8str(&wargv[ii][offset])); + name.assign(utf16str_to_utf8str(&wargv[ii][offset])); #else - name.assign(wstring_to_utf8str(&wargv[ii][offset])); + name.assign(wstring_to_utf8str(&wargv[ii][offset])); #endif - if(((ii+1) >= argc) || (wargv[ii+1][0] == '-')) - { - // we found another option after this one or we have - // reached the end. simply record that this option was - // found and continue. - int flag = name.compare("logfile"); - if (0 == flag) - { - commands[name] = "log"; - } - else - { - commands[name] = true; - } - - continue; - } - ++ii; + if(((ii+1) >= argc) || (wargv[ii+1][0] == '-')) + { + // we found another option after this one or we have + // reached the end. simply record that this option was + // found and continue. + int flag = name.compare("logfile"); + if (0 == flag) + { + commands[name] = "log"; + } + else + { + commands[name] = true; + } + + continue; + } + ++ii; #if LL_WINDOWS - value.assign(utf16str_to_utf8str((wargv[ii]))); + value.assign(utf16str_to_utf8str((wargv[ii]))); #else - value.assign(wstring_to_utf8str((wargv[ii]))); + value.assign(wstring_to_utf8str((wargv[ii]))); #endif #if LL_WINDOWS - //Windows changed command line parsing. Deal with it. - S32 slen = value.length() - 1; - S32 start = 0; - S32 end = slen; - if (wargv[ii][start]=='"')start++; - if (wargv[ii][end]=='"')end--; - if (start!=0 || end!=slen) - { - value = value.substr (start,end); - } + //Windows changed command line parsing. Deal with it. + S32 slen = value.length() - 1; + S32 start = 0; + S32 end = slen; + if (wargv[ii][start]=='"')start++; + if (wargv[ii][end]=='"')end--; + if (start!=0 || end!=slen) + { + value = value.substr (start,end); + } #endif - commands[name] = value; - } - setOptionData(PRIORITY_COMMAND_LINE, commands); - return true; + commands[name] = value; + } + setOptionData(PRIORITY_COMMAND_LINE, commands); + return true; } void LLApp::manageLiveFile(LLLiveFile* livefile) { - if(!livefile) return; - livefile->checkAndReload(); - livefile->addToEventTimer(); - mLiveFiles.push_back(livefile); + if(!livefile) return; + livefile->checkAndReload(); + livefile->addToEventTimer(); + mLiveFiles.push_back(livefile); } bool LLApp::setOptionData(OptionPriority level, LLSD data) { - if((level < 0) - || (level >= PRIORITY_COUNT) - || (data.type() != LLSD::TypeMap)) - { - return false; - } - mOptions[level] = data; - return true; + if((level < 0) + || (level >= PRIORITY_COUNT) + || (data.type() != LLSD::TypeMap)) + { + return false; + } + mOptions[level] = data; + return true; } LLSD LLApp::getOptionData(OptionPriority level) { - if((level < 0) || (level >= PRIORITY_COUNT)) - { - return LLSD(); - } - return mOptions[level]; + if((level < 0) || (level >= PRIORITY_COUNT)) + { + return LLSD(); + } + return mOptions[level]; } void LLApp::stepFrame() { - LLFrameTimer::updateFrameTime(); - LLFrameTimer::updateFrameCount(); - LLEventTimer::updateClass(); - mRunner.run(); + LLFrameTimer::updateFrameTime(); + LLFrameTimer::updateFrameCount(); + LLEventTimer::updateClass(); + mRunner.run(); } #if LL_WINDOWS @@ -332,31 +332,31 @@ void LLApp::stepFrame() //in-depth article on the issue may be found here: http://randomascii.wordpress.com/2012/07/05/when-even-crashing-doesn-work/ void EnableCrashingOnCrashes() { - typedef BOOL (WINAPI *tGetPolicy)(LPDWORD lpFlags); - typedef BOOL (WINAPI *tSetPolicy)(DWORD dwFlags); - const DWORD EXCEPTION_SWALLOWING = 0x1; - - HMODULE kernel32 = LoadLibraryA("kernel32.dll"); - tGetPolicy pGetPolicy = (tGetPolicy)GetProcAddress(kernel32, - "GetProcessUserModeExceptionPolicy"); - tSetPolicy pSetPolicy = (tSetPolicy)GetProcAddress(kernel32, - "SetProcessUserModeExceptionPolicy"); - if (pGetPolicy && pSetPolicy) - { - DWORD dwFlags; - if (pGetPolicy(&dwFlags)) - { - // Turn off the filter - pSetPolicy(dwFlags & ~EXCEPTION_SWALLOWING); - } - } + typedef BOOL (WINAPI *tGetPolicy)(LPDWORD lpFlags); + typedef BOOL (WINAPI *tSetPolicy)(DWORD dwFlags); + const DWORD EXCEPTION_SWALLOWING = 0x1; + + HMODULE kernel32 = LoadLibraryA("kernel32.dll"); + tGetPolicy pGetPolicy = (tGetPolicy)GetProcAddress(kernel32, + "GetProcessUserModeExceptionPolicy"); + tSetPolicy pSetPolicy = (tSetPolicy)GetProcAddress(kernel32, + "SetProcessUserModeExceptionPolicy"); + if (pGetPolicy && pSetPolicy) + { + DWORD dwFlags; + if (pGetPolicy(&dwFlags)) + { + // Turn off the filter + pSetPolicy(dwFlags & ~EXCEPTION_SWALLOWING); + } + } } #endif void LLApp::setupErrorHandling(bool second_instance) { - // Error handling is done by starting up an error handling thread, which just sleeps and - // occasionally checks to see if the app is in an error state, and sees if it needs to be run. + // Error handling is done by starting up an error handling thread, which just sleeps and + // occasionally checks to see if the app is in an error state, and sees if it needs to be run. #if LL_WINDOWS @@ -377,19 +377,19 @@ void LLApp::setupErrorHandling(bool second_instance) void LLApp::setErrorHandler(LLAppErrorHandler handler) { - LLApp::sErrorHandler = handler; + LLApp::sErrorHandler = handler; } // static void LLApp::runErrorHandler() { - if (LLApp::sErrorHandler) - { - LLApp::sErrorHandler(); - } + if (LLApp::sErrorHandler) + { + LLApp::sErrorHandler(); + } - //LL_INFOS() << "App status now STOPPED" << LL_ENDL; - LLApp::setStopped(); + //LL_INFOS() << "App status now STOPPED" << LL_ENDL; + LLApp::setStopped(); } namespace @@ -435,14 +435,14 @@ void LLApp::setStatus(EAppStatus status) // static void LLApp::setError() { - // set app status to ERROR - setStatus(APP_STATUS_ERROR); + // set app status to ERROR + setStatus(APP_STATUS_ERROR); } void LLApp::setDebugFileNames(const std::string &path) { - mStaticDebugFileName = path + "static_debug_info.log"; - mDynamicDebugFileName = path + "dynamic_debug_info.log"; + mStaticDebugFileName = path + "static_debug_info.log"; + mDynamicDebugFileName = path + "dynamic_debug_info.log"; } void LLApp::writeMiniDump() @@ -452,64 +452,64 @@ void LLApp::writeMiniDump() // static void LLApp::setQuitting() { - if (!isExiting()) - { - // If we're already exiting, we don't want to reset our state back to quitting. - LL_INFOS() << "Setting app state to QUITTING" << LL_ENDL; - setStatus(APP_STATUS_QUITTING); - } + if (!isExiting()) + { + // If we're already exiting, we don't want to reset our state back to quitting. + LL_INFOS() << "Setting app state to QUITTING" << LL_ENDL; + setStatus(APP_STATUS_QUITTING); + } } // static void LLApp::setStopped() { - setStatus(APP_STATUS_STOPPED); + setStatus(APP_STATUS_STOPPED); } // static bool LLApp::isStopped() { - return (APP_STATUS_STOPPED == sStatus.get()); + return (APP_STATUS_STOPPED == sStatus.get()); } // static bool LLApp::isRunning() { - return (APP_STATUS_RUNNING == sStatus.get()); + return (APP_STATUS_RUNNING == sStatus.get()); } // static bool LLApp::isError() { - return (APP_STATUS_ERROR == sStatus.get()); + return (APP_STATUS_ERROR == sStatus.get()); } // static bool LLApp::isQuitting() { - return (APP_STATUS_QUITTING == sStatus.get()); + return (APP_STATUS_QUITTING == sStatus.get()); } // static bool LLApp::isExiting() { - return isQuitting() || isError(); + return isQuitting() || isError(); } void LLApp::disableCrashlogger() { - sDisableCrashlogger = TRUE; + sDisableCrashlogger = TRUE; } // static bool LLApp::isCrashloggerDisabled() { - return (sDisableCrashlogger == TRUE); + return (sDisableCrashlogger == TRUE); } // static @@ -518,336 +518,336 @@ int LLApp::getPid() #if LL_WINDOWS return GetCurrentProcessId(); #else - return getpid(); + return getpid(); #endif } #if LL_WINDOWS LONG WINAPI default_windows_exception_handler(struct _EXCEPTION_POINTERS *exception_infop) { - // Translate the signals/exceptions into cross-platform stuff - // Windows implementation + // Translate the signals/exceptions into cross-platform stuff + // Windows implementation - // Make sure the user sees something to indicate that the app crashed. - LONG retval; + // Make sure the user sees something to indicate that the app crashed. + LONG retval; - if (LLApp::isError()) - { - LL_WARNS() << "Got another fatal signal while in the error handler, die now!" << LL_ENDL; - retval = EXCEPTION_EXECUTE_HANDLER; - return retval; - } + if (LLApp::isError()) + { + LL_WARNS() << "Got another fatal signal while in the error handler, die now!" << LL_ENDL; + retval = EXCEPTION_EXECUTE_HANDLER; + return retval; + } - // Flag status to error, so thread_error starts its work - LLApp::setError(); + // Flag status to error, so thread_error starts its work + LLApp::setError(); - // Block in the exception handler until the app has stopped - // This is pretty sketchy, but appears to work just fine - while (!LLApp::isStopped()) - { - ms_sleep(10); - } + // Block in the exception handler until the app has stopped + // This is pretty sketchy, but appears to work just fine + while (!LLApp::isStopped()) + { + ms_sleep(10); + } - // - // Generate a minidump if we can. - // - // TODO: This needs to be ported over form the viewer-specific - // LLWinDebug class + // + // Generate a minidump if we can. + // + // TODO: This needs to be ported over form the viewer-specific + // LLWinDebug class - // - // At this point, we always want to exit the app. There's no graceful - // recovery for an unhandled exception. - // - // Just kill the process. - retval = EXCEPTION_EXECUTE_HANDLER; - return retval; + // + // At this point, we always want to exit the app. There's no graceful + // recovery for an unhandled exception. + // + // Just kill the process. + retval = EXCEPTION_EXECUTE_HANDLER; + return retval; } // Win32 doesn't support signals. This is used instead. -BOOL ConsoleCtrlHandler(DWORD fdwCtrlType) -{ - switch (fdwCtrlType) - { - case CTRL_BREAK_EVENT: - case CTRL_LOGOFF_EVENT: - case CTRL_SHUTDOWN_EVENT: - case CTRL_CLOSE_EVENT: // From end task or the window close button. - case CTRL_C_EVENT: // from CTRL-C on the keyboard - // Just set our state to quitting, not error - if (LLApp::isQuitting() || LLApp::isError()) - { - // We're already trying to die, just ignore this signal - if (LLApp::sLogInSignal) - { - LL_INFOS() << "Signal handler - Already trying to quit, ignoring signal!" << LL_ENDL; - } - return TRUE; - } - LLApp::setQuitting(); - return TRUE; - - default: - return FALSE; - } -} +BOOL ConsoleCtrlHandler(DWORD fdwCtrlType) +{ + switch (fdwCtrlType) + { + case CTRL_BREAK_EVENT: + case CTRL_LOGOFF_EVENT: + case CTRL_SHUTDOWN_EVENT: + case CTRL_CLOSE_EVENT: // From end task or the window close button. + case CTRL_C_EVENT: // from CTRL-C on the keyboard + // Just set our state to quitting, not error + if (LLApp::isQuitting() || LLApp::isError()) + { + // We're already trying to die, just ignore this signal + if (LLApp::sLogInSignal) + { + LL_INFOS() << "Signal handler - Already trying to quit, ignoring signal!" << LL_ENDL; + } + return TRUE; + } + LLApp::setQuitting(); + return TRUE; + + default: + return FALSE; + } +} #else //!LL_WINDOWS void setup_signals() { - // - // Set up signal handlers that may result in program termination - // - struct sigaction act; - act.sa_sigaction = default_unix_signal_handler; - sigemptyset( &act.sa_mask ); - act.sa_flags = SA_SIGINFO; + // + // Set up signal handlers that may result in program termination + // + struct sigaction act; + act.sa_sigaction = default_unix_signal_handler; + sigemptyset( &act.sa_mask ); + act.sa_flags = SA_SIGINFO; - // Synchronous signals + // Synchronous signals # ifndef LL_BUGSPLAT - sigaction(SIGABRT, &act, NULL); + sigaction(SIGABRT, &act, NULL); # endif - sigaction(SIGALRM, &act, NULL); - sigaction(SIGBUS, &act, NULL); - sigaction(SIGFPE, &act, NULL); - sigaction(SIGHUP, &act, NULL); - sigaction(SIGILL, &act, NULL); - sigaction(SIGPIPE, &act, NULL); - sigaction(SIGSEGV, &act, NULL); - sigaction(SIGSYS, &act, NULL); - - sigaction(LL_HEARTBEAT_SIGNAL, &act, NULL); - sigaction(LL_SMACKDOWN_SIGNAL, &act, NULL); - - // Asynchronous signals that are normally ignored + sigaction(SIGALRM, &act, NULL); + sigaction(SIGBUS, &act, NULL); + sigaction(SIGFPE, &act, NULL); + sigaction(SIGHUP, &act, NULL); + sigaction(SIGILL, &act, NULL); + sigaction(SIGPIPE, &act, NULL); + sigaction(SIGSEGV, &act, NULL); + sigaction(SIGSYS, &act, NULL); + + sigaction(LL_HEARTBEAT_SIGNAL, &act, NULL); + sigaction(LL_SMACKDOWN_SIGNAL, &act, NULL); + + // Asynchronous signals that are normally ignored #ifndef LL_IGNORE_SIGCHLD - sigaction(SIGCHLD, &act, NULL); + sigaction(SIGCHLD, &act, NULL); #endif // LL_IGNORE_SIGCHLD - sigaction(SIGUSR2, &act, NULL); + sigaction(SIGUSR2, &act, NULL); - // Asynchronous signals that result in attempted graceful exit - sigaction(SIGHUP, &act, NULL); - sigaction(SIGTERM, &act, NULL); - sigaction(SIGINT, &act, NULL); + // Asynchronous signals that result in attempted graceful exit + sigaction(SIGHUP, &act, NULL); + sigaction(SIGTERM, &act, NULL); + sigaction(SIGINT, &act, NULL); + + // Asynchronous signals that result in core + sigaction(SIGQUIT, &act, NULL); - // Asynchronous signals that result in core - sigaction(SIGQUIT, &act, NULL); - } void clear_signals() { - struct sigaction act; - act.sa_handler = SIG_DFL; - sigemptyset( &act.sa_mask ); - act.sa_flags = SA_SIGINFO; + struct sigaction act; + act.sa_handler = SIG_DFL; + sigemptyset( &act.sa_mask ); + act.sa_flags = SA_SIGINFO; - // Synchronous signals + // Synchronous signals # ifndef LL_BUGSPLAT - sigaction(SIGABRT, &act, NULL); + sigaction(SIGABRT, &act, NULL); # endif - sigaction(SIGALRM, &act, NULL); - sigaction(SIGBUS, &act, NULL); - sigaction(SIGFPE, &act, NULL); - sigaction(SIGHUP, &act, NULL); - sigaction(SIGILL, &act, NULL); - sigaction(SIGPIPE, &act, NULL); - sigaction(SIGSEGV, &act, NULL); - sigaction(SIGSYS, &act, NULL); - - sigaction(LL_HEARTBEAT_SIGNAL, &act, NULL); - sigaction(LL_SMACKDOWN_SIGNAL, &act, NULL); - - // Asynchronous signals that are normally ignored + sigaction(SIGALRM, &act, NULL); + sigaction(SIGBUS, &act, NULL); + sigaction(SIGFPE, &act, NULL); + sigaction(SIGHUP, &act, NULL); + sigaction(SIGILL, &act, NULL); + sigaction(SIGPIPE, &act, NULL); + sigaction(SIGSEGV, &act, NULL); + sigaction(SIGSYS, &act, NULL); + + sigaction(LL_HEARTBEAT_SIGNAL, &act, NULL); + sigaction(LL_SMACKDOWN_SIGNAL, &act, NULL); + + // Asynchronous signals that are normally ignored #ifndef LL_IGNORE_SIGCHLD - sigaction(SIGCHLD, &act, NULL); + sigaction(SIGCHLD, &act, NULL); #endif // LL_IGNORE_SIGCHLD - // Asynchronous signals that result in attempted graceful exit - sigaction(SIGHUP, &act, NULL); - sigaction(SIGTERM, &act, NULL); - sigaction(SIGINT, &act, NULL); + // Asynchronous signals that result in attempted graceful exit + sigaction(SIGHUP, &act, NULL); + sigaction(SIGTERM, &act, NULL); + sigaction(SIGINT, &act, NULL); - // Asynchronous signals that result in core - sigaction(SIGUSR2, &act, NULL); - sigaction(SIGQUIT, &act, NULL); + // Asynchronous signals that result in core + sigaction(SIGUSR2, &act, NULL); + sigaction(SIGQUIT, &act, NULL); } void default_unix_signal_handler(int signum, siginfo_t *info, void *) { - // Unix implementation of synchronous signal handler - // This runs in the thread that threw the signal. - // We do the somewhat sketchy operation of blocking in here until the error handler - // has gracefully stopped the app. + // Unix implementation of synchronous signal handler + // This runs in the thread that threw the signal. + // We do the somewhat sketchy operation of blocking in here until the error handler + // has gracefully stopped the app. - if (LLApp::sLogInSignal) - { - LL_INFOS() << "Signal handler - Got signal " << signum << " - " << apr_signal_description_get(signum) << LL_ENDL; - } + if (LLApp::sLogInSignal) + { + LL_INFOS() << "Signal handler - Got signal " << signum << " - " << apr_signal_description_get(signum) << LL_ENDL; + } - switch (signum) - { - case SIGCHLD: - if (LLApp::sLogInSignal) - { - LL_INFOS() << "Signal handler - Got SIGCHLD from " << info->si_pid << LL_ENDL; - } + switch (signum) + { + case SIGCHLD: + if (LLApp::sLogInSignal) + { + LL_INFOS() << "Signal handler - Got SIGCHLD from " << info->si_pid << LL_ENDL; + } - return; - case SIGABRT: + return; + case SIGABRT: // Note that this handler is not set for SIGABRT when using Bugsplat - // Abort just results in termination of the app, no funky error handling. - if (LLApp::sLogInSignal) - { - LL_WARNS() << "Signal handler - Got SIGABRT, terminating" << LL_ENDL; - } - clear_signals(); - raise(signum); - return; - case SIGINT: - case SIGHUP: - case SIGTERM: - if (LLApp::sLogInSignal) - { - LL_WARNS() << "Signal handler - Got SIGINT, HUP, or TERM, exiting gracefully" << LL_ENDL; - } - // Graceful exit - // Just set our state to quitting, not error - if (LLApp::isQuitting() || LLApp::isError()) - { - // We're already trying to die, just ignore this signal - if (LLApp::sLogInSignal) - { - LL_INFOS() << "Signal handler - Already trying to quit, ignoring signal!" << LL_ENDL; - } - return; - } - LLApp::setQuitting(); - return; - case SIGALRM: - case SIGPIPE: - case SIGUSR2: - default: - if (signum == LL_SMACKDOWN_SIGNAL || - signum == SIGBUS || - signum == SIGILL || - signum == SIGFPE || - signum == SIGSEGV || - signum == SIGQUIT) - { - if (signum == LL_SMACKDOWN_SIGNAL) - { - // Smackdown treated just like any other app termination, for now - if (LLApp::sLogInSignal) - { - LL_WARNS() << "Signal handler - Handling smackdown signal!" << LL_ENDL; - } - else - { - // Don't log anything, even errors - this is because this signal could happen anywhere. - LLError::setDefaultLevel(LLError::LEVEL_NONE); - } - - // Change the signal that we reraise to SIGABRT, so we generate a core dump. - signum = SIGABRT; - } - - if (LLApp::sLogInSignal) - { - LL_WARNS() << "Signal handler - Handling fatal signal!" << LL_ENDL; - } - if (LLApp::isError()) - { - // Received second fatal signal while handling first, just die right now - // Set the signal handlers back to default before handling the signal - this makes the next signal wipe out the app. - clear_signals(); - - if (LLApp::sLogInSignal) - { - LL_WARNS() << "Signal handler - Got another fatal signal while in the error handler, die now!" << LL_ENDL; - } - raise(signum); - return; - } - - if (LLApp::sLogInSignal) - { - LL_WARNS() << "Signal handler - Flagging error status and waiting for shutdown" << LL_ENDL; - } - - if (LLApp::isCrashloggerDisabled()) // Don't gracefully handle any signal, crash and core for a gdb post mortem - { - clear_signals(); - LL_WARNS() << "Fatal signal received, not handling the crash here, passing back to operating system" << LL_ENDL; - raise(signum); - return; - } - - // Flag status to ERROR - LLApp::setError(); - - if (LLApp::sLogInSignal) - { - LL_WARNS() << "Signal handler - App is stopped, reraising signal" << LL_ENDL; - } - clear_signals(); - raise(signum); - return; - } else { - if (LLApp::sLogInSignal) - { - LL_INFOS() << "Signal handler - Unhandled signal " << signum << ", ignoring!" << LL_ENDL; - } - } - } + // Abort just results in termination of the app, no funky error handling. + if (LLApp::sLogInSignal) + { + LL_WARNS() << "Signal handler - Got SIGABRT, terminating" << LL_ENDL; + } + clear_signals(); + raise(signum); + return; + case SIGINT: + case SIGHUP: + case SIGTERM: + if (LLApp::sLogInSignal) + { + LL_WARNS() << "Signal handler - Got SIGINT, HUP, or TERM, exiting gracefully" << LL_ENDL; + } + // Graceful exit + // Just set our state to quitting, not error + if (LLApp::isQuitting() || LLApp::isError()) + { + // We're already trying to die, just ignore this signal + if (LLApp::sLogInSignal) + { + LL_INFOS() << "Signal handler - Already trying to quit, ignoring signal!" << LL_ENDL; + } + return; + } + LLApp::setQuitting(); + return; + case SIGALRM: + case SIGPIPE: + case SIGUSR2: + default: + if (signum == LL_SMACKDOWN_SIGNAL || + signum == SIGBUS || + signum == SIGILL || + signum == SIGFPE || + signum == SIGSEGV || + signum == SIGQUIT) + { + if (signum == LL_SMACKDOWN_SIGNAL) + { + // Smackdown treated just like any other app termination, for now + if (LLApp::sLogInSignal) + { + LL_WARNS() << "Signal handler - Handling smackdown signal!" << LL_ENDL; + } + else + { + // Don't log anything, even errors - this is because this signal could happen anywhere. + LLError::setDefaultLevel(LLError::LEVEL_NONE); + } + + // Change the signal that we reraise to SIGABRT, so we generate a core dump. + signum = SIGABRT; + } + + if (LLApp::sLogInSignal) + { + LL_WARNS() << "Signal handler - Handling fatal signal!" << LL_ENDL; + } + if (LLApp::isError()) + { + // Received second fatal signal while handling first, just die right now + // Set the signal handlers back to default before handling the signal - this makes the next signal wipe out the app. + clear_signals(); + + if (LLApp::sLogInSignal) + { + LL_WARNS() << "Signal handler - Got another fatal signal while in the error handler, die now!" << LL_ENDL; + } + raise(signum); + return; + } + + if (LLApp::sLogInSignal) + { + LL_WARNS() << "Signal handler - Flagging error status and waiting for shutdown" << LL_ENDL; + } + + if (LLApp::isCrashloggerDisabled()) // Don't gracefully handle any signal, crash and core for a gdb post mortem + { + clear_signals(); + LL_WARNS() << "Fatal signal received, not handling the crash here, passing back to operating system" << LL_ENDL; + raise(signum); + return; + } + + // Flag status to ERROR + LLApp::setError(); + + if (LLApp::sLogInSignal) + { + LL_WARNS() << "Signal handler - App is stopped, reraising signal" << LL_ENDL; + } + clear_signals(); + raise(signum); + return; + } else { + if (LLApp::sLogInSignal) + { + LL_INFOS() << "Signal handler - Unhandled signal " << signum << ", ignoring!" << LL_ENDL; + } + } + } } #if LL_LINUX #endif bool unix_post_minidump_callback(const char *dump_dir, - const char *minidump_id, - void *context, bool succeeded) -{ - // Copy minidump file path into fixed buffer in the app instance to avoid - // heap allocations in a crash handler. - - // path format: /.dmp - auto dirPathLength = strlen(dump_dir); - auto idLength = strlen(minidump_id); - - // The path must not be truncated. - llassert((dirPathLength + idLength + 5) <= LLApp::MAX_MINDUMP_PATH_LENGTH); - - char * path = LLApp::instance()->getMiniDumpFilename(); - auto remaining = LLApp::MAX_MINDUMP_PATH_LENGTH; - strncpy(path, dump_dir, remaining); - remaining -= dirPathLength; - path += dirPathLength; - if (remaining > 0 && dirPathLength > 0 && path[-1] != '/') - { - *path++ = '/'; - --remaining; - } - if (remaining > 0) - { - strncpy(path, minidump_id, remaining); - remaining -= idLength; - path += idLength; - strncpy(path, ".dmp", remaining); - } - - LL_INFOS("CRASHREPORT") << "generated minidump: " << LLApp::instance()->getMiniDumpFilename() << LL_ENDL; - LLApp::runErrorHandler(); - + const char *minidump_id, + void *context, bool succeeded) +{ + // Copy minidump file path into fixed buffer in the app instance to avoid + // heap allocations in a crash handler. + + // path format: /.dmp + auto dirPathLength = strlen(dump_dir); + auto idLength = strlen(minidump_id); + + // The path must not be truncated. + llassert((dirPathLength + idLength + 5) <= LLApp::MAX_MINDUMP_PATH_LENGTH); + + char * path = LLApp::instance()->getMiniDumpFilename(); + auto remaining = LLApp::MAX_MINDUMP_PATH_LENGTH; + strncpy(path, dump_dir, remaining); + remaining -= dirPathLength; + path += dirPathLength; + if (remaining > 0 && dirPathLength > 0 && path[-1] != '/') + { + *path++ = '/'; + --remaining; + } + if (remaining > 0) + { + strncpy(path, minidump_id, remaining); + remaining -= idLength; + path += idLength; + strncpy(path, ".dmp", remaining); + } + + LL_INFOS("CRASHREPORT") << "generated minidump: " << LLApp::instance()->getMiniDumpFilename() << LL_ENDL; + LLApp::runErrorHandler(); + #ifndef LL_RELEASE_FOR_DOWNLOAD - clear_signals(); - return false; + clear_signals(); + return false; #else - return true; + return true; #endif } #endif // !WINDOWS diff --git a/indra/llcommon/llapp.h b/indra/llcommon/llapp.h index a892bfeb1e..93bf4dd929 100644 --- a/indra/llcommon/llapp.h +++ b/indra/llcommon/llapp.h @@ -1,25 +1,25 @@ -/** +/** * @file llapp.h * @brief Declaration of the LLApp class. * * $LicenseInfo:firstyear=2003&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -53,290 +53,290 @@ void clear_signals(); class LL_COMMON_API LLApp { public: - typedef enum e_app_status - { - APP_STATUS_RUNNING, // The application is currently running - the default status - APP_STATUS_QUITTING, // The application is currently quitting - threads should listen for this and clean up - APP_STATUS_STOPPED, // The application is no longer running - tells the error thread it can exit - APP_STATUS_ERROR // The application had a fatal error occur - tells the error thread to run - } EAppStatus; - - - LLApp(); - virtual ~LLApp(); - - /** - * @brief Return the static app instance if one was created. - */ - static LLApp* instance(); - - /** @name Runtime options */ - //@{ - /** - * @brief Enumeration to specify option priorities in highest to - * lowest order. - */ - enum OptionPriority - { - PRIORITY_RUNTIME_OVERRIDE, - PRIORITY_COMMAND_LINE, - PRIORITY_SPECIFIC_CONFIGURATION, - PRIORITY_GENERAL_CONFIGURATION, - PRIORITY_DEFAULT, - PRIORITY_COUNT - }; - - /** - * @brief Get the application option at the highest priority. - * - * If the return value is undefined, the option does not exist. - * @param name The name of the option. - * @return Returns the option data. - */ - LLSD getOption(const std::string& name) const; - - /** - * @brief Parse ASCII command line options and insert them into - * application command line options. - * - * The name inserted into the option will have leading option - * identifiers (a minus or double minus) stripped. All options - * with values will be stored as a string, while all options - * without values will be stored as true. - * @param argc The argc passed into main(). - * @param argv The argv passed into main(). - * @return Returns true if the parse succeeded. - */ - bool parseCommandOptions(int argc, char** argv); - - /** - * @brief Parse Unicode command line options and insert them into - * application command line options. - * - * The name inserted into the option will have leading option - * identifiers (a minus or double minus) stripped. All options - * with values will be stored as a string, while all options - * without values will be stored as true. - * @param argc The argc passed into main(). - * @param wargv The wargv passed into main(). - * @return Returns true if the parse succeeded. - */ - bool parseCommandOptions(int argc, wchar_t** wargv); - - /** - * @brief Keep track of live files automatically. - * - * *TODO: it currently uses the addToEventTimer() API - * instead of the runner. I should probalby use the runner. - * - * *NOTE: DO NOT add the livefile instance to any kind of check loop. - * - * @param livefile A valid instance of an LLLiveFile. This LLApp - * instance will delete the livefile instance. - */ - void manageLiveFile(LLLiveFile* livefile); - - /** - * @brief Set the options at the specified priority. - * - * This function completely replaces the options at the priority - * level with the data specified. This function will make sure - * level and data might be valid before doing the replace. - * @param level The priority level of the data. - * @param data The data to set. - * @return Returns true if the option was set. - */ - bool setOptionData(OptionPriority level, LLSD data); - - /** - * @brief Get the option data at the specified priority. - * - * This method is probably not so useful except when merging - * information. - * @param level The priority level of the data. - * @return Returns The data (if any) at the level priority. - */ - LLSD getOptionData(OptionPriority level); - //@} - - - - // - // Main application logic - // - virtual bool init() = 0; // Override to do application initialization - - // - // cleanup() - // - // It's currently assumed that the cleanup() method will only get - // called from the main thread or the error handling thread, as it will - // likely do thread shutdown, among other things. - // - virtual bool cleanup() = 0; // Override to do application cleanup - - // - // frame() - // - // Pass control to the application for a single frame. Returns 'done' - // flag: if frame() returns false, it expects to be called again. - // - virtual bool frame() = 0; // Override for application body logic - - // - // Crash logging - // - void disableCrashlogger(); // Let the OS handle the crashes - static bool isCrashloggerDisabled(); // Get the here above set value - - // - // Application status - // - static void setQuitting(); // Set status to QUITTING, the app is now shutting down - static void setStopped(); // Set status to STOPPED, the app is done running and should exit - static void setError(); // Set status to ERROR, the error handler should run - static bool isStopped(); - static bool isRunning(); - static bool isQuitting(); - static bool isError(); - static bool isExiting(); // Either quitting or error (app is exiting, cleanly or not) - static int getPid(); - - // - // Sleep for specified time while still running - // - // For use by a coroutine or thread that performs some maintenance on a - // periodic basis. (See also LLEventTimer.) This method supports the - // pattern of an "infinite" loop that sleeps for some time, performs some - // action, then sleeps again. The trouble with literally sleeping a worker - // thread is that it could potentially sleep right through attempted - // application shutdown. This method avoids that by returning false as - // soon as the application status changes away from APP_STATUS_RUNNING - // (isRunning()). - // - // sleep() returns true if it sleeps undisturbed for the entire specified - // duration. The idea is that you can code 'while sleep(duration) ...', - // which will break the loop once shutdown begins. - // - // Since any time-based LLUnit should be implicitly convertible to - // F32Milliseconds, accept that specific type as a proxy. - static bool sleep(F32Milliseconds duration); - // Allow any duration defined in terms of . - // One can imagine a wonderfully general bidirectional conversion system - // between any type derived from LLUnits::LLUnit and - // any std::chrono::duration -- but that doesn't yet exist. - template - bool sleep(const std::chrono::duration& duration) - { - // wait_for_unequal() has the opposite bool return convention - return ! sStatus.wait_for_unequal(duration, APP_STATUS_RUNNING); - } - - /** @name Error handling methods */ - //@{ - /** - * @brief Do our generic platform-specific error-handling setup -- - * signals on unix, structured exceptions on windows. - * - * DO call this method if your app will either spawn children or be - * spawned by a launcher. - * Call just after app object construction. - * (Otherwise your app will crash when getting signals, - * and will not core dump.) - * - * DO NOT call this method if your application has specialized - * error handling code. - */ - void setupErrorHandling(bool mSecondInstance=false); - - void setErrorHandler(LLAppErrorHandler handler); - static void runErrorHandler(); // run shortly after we detect an error - //@} - - // the maximum length of the minidump filename returned by getMiniDumpFilename() - static const U32 MAX_MINDUMP_PATH_LENGTH = 256; - - // change the directory where Breakpad minidump files are written to - void setDebugFileNames(const std::string &path); - - // Return the Google Breakpad minidump filename after a crash. - char *getMiniDumpFilename() { return mMinidumpPath; } - std::string* getStaticDebugFile() { return &mStaticDebugFileName; } - std::string* getDynamicDebugFile() { return &mDynamicDebugFileName; } - - // Write out a Google Breakpad minidump file. - void writeMiniDump(); - - - /** - * @brief Get a reference to the application runner - * - * Please use the runner with caution. Since the Runner usage - * pattern is not yet clear, this method just gives access to it - * to add and remove runnables. - * @return Returns the application runner. Do not save the - * pointer past the caller's stack frame. - */ - LLRunner& getRunner() { return mRunner; } + typedef enum e_app_status + { + APP_STATUS_RUNNING, // The application is currently running - the default status + APP_STATUS_QUITTING, // The application is currently quitting - threads should listen for this and clean up + APP_STATUS_STOPPED, // The application is no longer running - tells the error thread it can exit + APP_STATUS_ERROR // The application had a fatal error occur - tells the error thread to run + } EAppStatus; + + + LLApp(); + virtual ~LLApp(); + + /** + * @brief Return the static app instance if one was created. + */ + static LLApp* instance(); + + /** @name Runtime options */ + //@{ + /** + * @brief Enumeration to specify option priorities in highest to + * lowest order. + */ + enum OptionPriority + { + PRIORITY_RUNTIME_OVERRIDE, + PRIORITY_COMMAND_LINE, + PRIORITY_SPECIFIC_CONFIGURATION, + PRIORITY_GENERAL_CONFIGURATION, + PRIORITY_DEFAULT, + PRIORITY_COUNT + }; + + /** + * @brief Get the application option at the highest priority. + * + * If the return value is undefined, the option does not exist. + * @param name The name of the option. + * @return Returns the option data. + */ + LLSD getOption(const std::string& name) const; + + /** + * @brief Parse ASCII command line options and insert them into + * application command line options. + * + * The name inserted into the option will have leading option + * identifiers (a minus or double minus) stripped. All options + * with values will be stored as a string, while all options + * without values will be stored as true. + * @param argc The argc passed into main(). + * @param argv The argv passed into main(). + * @return Returns true if the parse succeeded. + */ + bool parseCommandOptions(int argc, char** argv); + + /** + * @brief Parse Unicode command line options and insert them into + * application command line options. + * + * The name inserted into the option will have leading option + * identifiers (a minus or double minus) stripped. All options + * with values will be stored as a string, while all options + * without values will be stored as true. + * @param argc The argc passed into main(). + * @param wargv The wargv passed into main(). + * @return Returns true if the parse succeeded. + */ + bool parseCommandOptions(int argc, wchar_t** wargv); + + /** + * @brief Keep track of live files automatically. + * + * *TODO: it currently uses the addToEventTimer() API + * instead of the runner. I should probalby use the runner. + * + * *NOTE: DO NOT add the livefile instance to any kind of check loop. + * + * @param livefile A valid instance of an LLLiveFile. This LLApp + * instance will delete the livefile instance. + */ + void manageLiveFile(LLLiveFile* livefile); + + /** + * @brief Set the options at the specified priority. + * + * This function completely replaces the options at the priority + * level with the data specified. This function will make sure + * level and data might be valid before doing the replace. + * @param level The priority level of the data. + * @param data The data to set. + * @return Returns true if the option was set. + */ + bool setOptionData(OptionPriority level, LLSD data); + + /** + * @brief Get the option data at the specified priority. + * + * This method is probably not so useful except when merging + * information. + * @param level The priority level of the data. + * @return Returns The data (if any) at the level priority. + */ + LLSD getOptionData(OptionPriority level); + //@} + + + + // + // Main application logic + // + virtual bool init() = 0; // Override to do application initialization + + // + // cleanup() + // + // It's currently assumed that the cleanup() method will only get + // called from the main thread or the error handling thread, as it will + // likely do thread shutdown, among other things. + // + virtual bool cleanup() = 0; // Override to do application cleanup + + // + // frame() + // + // Pass control to the application for a single frame. Returns 'done' + // flag: if frame() returns false, it expects to be called again. + // + virtual bool frame() = 0; // Override for application body logic + + // + // Crash logging + // + void disableCrashlogger(); // Let the OS handle the crashes + static bool isCrashloggerDisabled(); // Get the here above set value + + // + // Application status + // + static void setQuitting(); // Set status to QUITTING, the app is now shutting down + static void setStopped(); // Set status to STOPPED, the app is done running and should exit + static void setError(); // Set status to ERROR, the error handler should run + static bool isStopped(); + static bool isRunning(); + static bool isQuitting(); + static bool isError(); + static bool isExiting(); // Either quitting or error (app is exiting, cleanly or not) + static int getPid(); + + // + // Sleep for specified time while still running + // + // For use by a coroutine or thread that performs some maintenance on a + // periodic basis. (See also LLEventTimer.) This method supports the + // pattern of an "infinite" loop that sleeps for some time, performs some + // action, then sleeps again. The trouble with literally sleeping a worker + // thread is that it could potentially sleep right through attempted + // application shutdown. This method avoids that by returning false as + // soon as the application status changes away from APP_STATUS_RUNNING + // (isRunning()). + // + // sleep() returns true if it sleeps undisturbed for the entire specified + // duration. The idea is that you can code 'while sleep(duration) ...', + // which will break the loop once shutdown begins. + // + // Since any time-based LLUnit should be implicitly convertible to + // F32Milliseconds, accept that specific type as a proxy. + static bool sleep(F32Milliseconds duration); + // Allow any duration defined in terms of . + // One can imagine a wonderfully general bidirectional conversion system + // between any type derived from LLUnits::LLUnit and + // any std::chrono::duration -- but that doesn't yet exist. + template + bool sleep(const std::chrono::duration& duration) + { + // wait_for_unequal() has the opposite bool return convention + return ! sStatus.wait_for_unequal(duration, APP_STATUS_RUNNING); + } + + /** @name Error handling methods */ + //@{ + /** + * @brief Do our generic platform-specific error-handling setup -- + * signals on unix, structured exceptions on windows. + * + * DO call this method if your app will either spawn children or be + * spawned by a launcher. + * Call just after app object construction. + * (Otherwise your app will crash when getting signals, + * and will not core dump.) + * + * DO NOT call this method if your application has specialized + * error handling code. + */ + void setupErrorHandling(bool mSecondInstance=false); + + void setErrorHandler(LLAppErrorHandler handler); + static void runErrorHandler(); // run shortly after we detect an error + //@} + + // the maximum length of the minidump filename returned by getMiniDumpFilename() + static const U32 MAX_MINDUMP_PATH_LENGTH = 256; + + // change the directory where Breakpad minidump files are written to + void setDebugFileNames(const std::string &path); + + // Return the Google Breakpad minidump filename after a crash. + char *getMiniDumpFilename() { return mMinidumpPath; } + std::string* getStaticDebugFile() { return &mStaticDebugFileName; } + std::string* getDynamicDebugFile() { return &mDynamicDebugFileName; } + + // Write out a Google Breakpad minidump file. + void writeMiniDump(); + + + /** + * @brief Get a reference to the application runner + * + * Please use the runner with caution. Since the Runner usage + * pattern is not yet clear, this method just gives access to it + * to add and remove runnables. + * @return Returns the application runner. Do not save the + * pointer past the caller's stack frame. + */ + LLRunner& getRunner() { return mRunner; } #ifdef LL_WINDOWS virtual void reportCrashToBugsplat(void* pExcepInfo /*EXCEPTION_POINTERS*/) { } #endif public: - typedef std::map string_map; - string_map mOptionMap; // Contains all command-line options and arguments in a map + typedef std::map string_map; + string_map mOptionMap; // Contains all command-line options and arguments in a map protected: - static void setStatus(EAppStatus status); // Use this to change the application status. - static LLScalarCond sStatus; // Reflects current application status - static BOOL sDisableCrashlogger; // Let the OS handle crashes for us. - std::wstring mCrashReportPipeStr; //Name of pipe to use for crash reporting. + static void setStatus(EAppStatus status); // Use this to change the application status. + static LLScalarCond sStatus; // Reflects current application status + static BOOL sDisableCrashlogger; // Let the OS handle crashes for us. + std::wstring mCrashReportPipeStr; //Name of pipe to use for crash reporting. std::string mDumpPath; //output path for google breakpad. Dependency workaround. - /** - * @brief This method is called once a frame to do once a frame tasks. - */ - void stepFrame(); + /** + * @brief This method is called once a frame to do once a frame tasks. + */ + void stepFrame(); private: - // Contains the filename of the minidump file after a crash. - char mMinidumpPath[MAX_MINDUMP_PATH_LENGTH]; - - std::string mStaticDebugFileName; - std::string mDynamicDebugFileName; + // Contains the filename of the minidump file after a crash. + char mMinidumpPath[MAX_MINDUMP_PATH_LENGTH]; + + std::string mStaticDebugFileName; + std::string mDynamicDebugFileName; - // *NOTE: On Windows, we need a routine to reset the structured - // exception handler when some evil driver has taken it over for - // their own purposes - typedef int(*signal_handler_func)(int signum); - static LLAppErrorHandler sErrorHandler; + // *NOTE: On Windows, we need a routine to reset the structured + // exception handler when some evil driver has taken it over for + // their own purposes + typedef int(*signal_handler_func)(int signum); + static LLAppErrorHandler sErrorHandler; - // This is the application level runnable scheduler. - LLRunner mRunner; + // This is the application level runnable scheduler. + LLRunner mRunner; - /** @name Runtime option implementation */ - //@{ + /** @name Runtime option implementation */ + //@{ - // The application options. - LLSD mOptions; + // The application options. + LLSD mOptions; - // The live files for this application - std::vector mLiveFiles; - //@} + // The live files for this application + std::vector mLiveFiles; + //@} private: - // the static application instance if it was created. - static LLApp* sApplication; + // the static application instance if it was created. + static LLApp* sApplication; #if !LL_WINDOWS - friend void default_unix_signal_handler(int signum, siginfo_t *info, void *); + friend void default_unix_signal_handler(int signum, siginfo_t *info, void *); #endif public: - static BOOL sLogInSignal; + static BOOL sLogInSignal; }; #endif // LL_LLAPP_H diff --git a/indra/llcommon/llapr.cpp b/indra/llcommon/llapr.cpp index 575c524219..c907a8c073 100644 --- a/indra/llcommon/llapr.cpp +++ b/indra/llcommon/llapr.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llapr.cpp * @author Phoenix * @date 2004-11-28 @@ -7,21 +7,21 @@ * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -46,200 +46,200 @@ int abortfunc(int retcode) void ll_init_apr() { - // Initialize APR and create the global pool - apr_initialize(); - - if (!gAPRPoolp) - { - apr_pool_create_ex(&gAPRPoolp, NULL, abortfunc, NULL); - } + // Initialize APR and create the global pool + apr_initialize(); + + if (!gAPRPoolp) + { + apr_pool_create_ex(&gAPRPoolp, NULL, abortfunc, NULL); + } - if(!LLAPRFile::sAPRFilePoolp) - { - LLAPRFile::sAPRFilePoolp = new LLVolatileAPRPool(FALSE) ; - } + if(!LLAPRFile::sAPRFilePoolp) + { + LLAPRFile::sAPRFilePoolp = new LLVolatileAPRPool(FALSE) ; + } - gAPRInitialized = true; + gAPRInitialized = true; } bool ll_apr_is_initialized() { - return gAPRInitialized; + return gAPRInitialized; } void ll_cleanup_apr() { - gAPRInitialized = false; + gAPRInitialized = false; - LL_DEBUGS("APR") << "Cleaning up APR" << LL_ENDL; + LL_DEBUGS("APR") << "Cleaning up APR" << LL_ENDL; - if (gAPRPoolp) - { - apr_pool_destroy(gAPRPoolp); - gAPRPoolp = NULL; - } - if (LLAPRFile::sAPRFilePoolp) - { - delete LLAPRFile::sAPRFilePoolp ; - LLAPRFile::sAPRFilePoolp = NULL ; - } - apr_terminate(); + if (gAPRPoolp) + { + apr_pool_destroy(gAPRPoolp); + gAPRPoolp = NULL; + } + if (LLAPRFile::sAPRFilePoolp) + { + delete LLAPRFile::sAPRFilePoolp ; + LLAPRFile::sAPRFilePoolp = NULL ; + } + apr_terminate(); } // // //LLAPRPool // -LLAPRPool::LLAPRPool(apr_pool_t *parent, apr_size_t size, BOOL releasePoolFlag) - : mParent(parent), - mReleasePoolFlag(releasePoolFlag), - mMaxSize(size), - mPool(NULL) -{ - createAPRPool() ; +LLAPRPool::LLAPRPool(apr_pool_t *parent, apr_size_t size, BOOL releasePoolFlag) + : mParent(parent), + mReleasePoolFlag(releasePoolFlag), + mMaxSize(size), + mPool(NULL) +{ + createAPRPool() ; } -LLAPRPool::~LLAPRPool() +LLAPRPool::~LLAPRPool() { - releaseAPRPool() ; + releaseAPRPool() ; } void LLAPRPool::createAPRPool() { - if(mPool) - { - return ; - } + if(mPool) + { + return ; + } - mStatus = apr_pool_create(&mPool, mParent); - ll_apr_warn_status(mStatus) ; + mStatus = apr_pool_create(&mPool, mParent); + ll_apr_warn_status(mStatus) ; - if(mMaxSize > 0) //size is the number of blocks (which is usually 4K), NOT bytes. - { - apr_allocator_t *allocator = apr_pool_allocator_get(mPool); - if (allocator) - { - apr_allocator_max_free_set(allocator, mMaxSize) ; - } - } + if(mMaxSize > 0) //size is the number of blocks (which is usually 4K), NOT bytes. + { + apr_allocator_t *allocator = apr_pool_allocator_get(mPool); + if (allocator) + { + apr_allocator_max_free_set(allocator, mMaxSize) ; + } + } } void LLAPRPool::releaseAPRPool() { - if(!mPool) - { - return ; - } + if(!mPool) + { + return ; + } - if(!mParent || mReleasePoolFlag) - { - apr_pool_destroy(mPool) ; - mPool = NULL ; - } + if(!mParent || mReleasePoolFlag) + { + apr_pool_destroy(mPool) ; + mPool = NULL ; + } } //virtual -apr_pool_t* LLAPRPool::getAPRPool() -{ - return mPool ; +apr_pool_t* LLAPRPool::getAPRPool() +{ + return mPool ; } -LLVolatileAPRPool::LLVolatileAPRPool(BOOL is_local, apr_pool_t *parent, apr_size_t size, BOOL releasePoolFlag) - : LLAPRPool(parent, size, releasePoolFlag), - mNumActiveRef(0), - mNumTotalRef(0) +LLVolatileAPRPool::LLVolatileAPRPool(BOOL is_local, apr_pool_t *parent, apr_size_t size, BOOL releasePoolFlag) + : LLAPRPool(parent, size, releasePoolFlag), + mNumActiveRef(0), + mNumTotalRef(0) { - //create mutex - if(!is_local) //not a local apr_pool, that is: shared by multiple threads. - { - mMutexp.reset(new std::mutex()); - } + //create mutex + if(!is_local) //not a local apr_pool, that is: shared by multiple threads. + { + mMutexp.reset(new std::mutex()); + } } LLVolatileAPRPool::~LLVolatileAPRPool() { - //delete mutex + //delete mutex mMutexp.reset(); } // //define this virtual function to avoid any mistakenly calling LLAPRPool::getAPRPool(). // -//virtual -apr_pool_t* LLVolatileAPRPool::getAPRPool() +//virtual +apr_pool_t* LLVolatileAPRPool::getAPRPool() { - return LLVolatileAPRPool::getVolatileAPRPool() ; + return LLVolatileAPRPool::getVolatileAPRPool() ; } -apr_pool_t* LLVolatileAPRPool::getVolatileAPRPool() -{ - LLScopedLock lock(mMutexp.get()) ; +apr_pool_t* LLVolatileAPRPool::getVolatileAPRPool() +{ + LLScopedLock lock(mMutexp.get()) ; - mNumTotalRef++ ; - mNumActiveRef++ ; + mNumTotalRef++ ; + mNumActiveRef++ ; - if(!mPool) - { - createAPRPool() ; - } - - return mPool ; + if(!mPool) + { + createAPRPool() ; + } + + return mPool ; } -void LLVolatileAPRPool::clearVolatileAPRPool() +void LLVolatileAPRPool::clearVolatileAPRPool() { LLScopedLock lock(mMutexp.get()); - if(mNumActiveRef > 0) - { - mNumActiveRef--; - if(mNumActiveRef < 1) - { - if(isFull()) - { - mNumTotalRef = 0 ; - - //destroy the apr_pool. - releaseAPRPool() ; - } - else - { - //This does not actually free the memory, - //it just allows the pool to re-use this memory for the next allocation. - apr_pool_clear(mPool) ; - } - } - } - else - { - llassert_always(mNumActiveRef > 0) ; - } - - llassert(mNumTotalRef <= (FULL_VOLATILE_APR_POOL << 2)) ; + if(mNumActiveRef > 0) + { + mNumActiveRef--; + if(mNumActiveRef < 1) + { + if(isFull()) + { + mNumTotalRef = 0 ; + + //destroy the apr_pool. + releaseAPRPool() ; + } + else + { + //This does not actually free the memory, + //it just allows the pool to re-use this memory for the next allocation. + apr_pool_clear(mPool) ; + } + } + } + else + { + llassert_always(mNumActiveRef > 0) ; + } + + llassert(mNumTotalRef <= (FULL_VOLATILE_APR_POOL << 2)) ; } BOOL LLVolatileAPRPool::isFull() { - return mNumTotalRef > FULL_VOLATILE_APR_POOL ; + return mNumTotalRef > FULL_VOLATILE_APR_POOL ; } //--------------------------------------------------------------------- bool _ll_apr_warn_status(apr_status_t status, const char* file, int line) { - if(APR_SUCCESS == status) return false; + if(APR_SUCCESS == status) return false; #if !LL_LINUX - char buf[MAX_STRING]; /* Flawfinder: ignore */ - apr_strerror(status, buf, sizeof(buf)); - LL_WARNS("APR") << "APR: " << file << ":" << line << " " << buf << LL_ENDL; + char buf[MAX_STRING]; /* Flawfinder: ignore */ + apr_strerror(status, buf, sizeof(buf)); + LL_WARNS("APR") << "APR: " << file << ":" << line << " " << buf << LL_ENDL; #endif - return true; + return true; } void _ll_apr_assert_status(apr_status_t status, const char* file, int line) { - llassert(! _ll_apr_warn_status(status, file, line)); + llassert(! _ll_apr_warn_status(status, file, line)); } //--------------------------------------------------------------------- @@ -253,7 +253,7 @@ class LLAPRFilePoolScope public: LLAPRFilePoolScope() : pPool(NULL), mInitialized(false) {} LLAPRFilePoolScope(LLVolatileAPRPool* poolp) : mInitialized(false) - { + { setFilePool(poolp); } ~LLAPRFilePoolScope() @@ -305,154 +305,154 @@ private: // LLAPRFile functions // LLAPRFile::LLAPRFile() - : mFile(NULL), - mCurrentFilePoolp(NULL) + : mFile(NULL), + mCurrentFilePoolp(NULL) { } LLAPRFile::LLAPRFile(const std::string& filename, apr_int32_t flags, LLVolatileAPRPool* pool) - : mFile(NULL), - mCurrentFilePoolp(NULL) + : mFile(NULL), + mCurrentFilePoolp(NULL) { - open(filename, flags, pool); + open(filename, flags, pool); } LLAPRFile::~LLAPRFile() { - close() ; + close() ; } -apr_status_t LLAPRFile::close() +apr_status_t LLAPRFile::close() { - apr_status_t ret = APR_SUCCESS ; - if(mFile) - { - ret = apr_file_close(mFile); - mFile = NULL ; - } + apr_status_t ret = APR_SUCCESS ; + if(mFile) + { + ret = apr_file_close(mFile); + mFile = NULL ; + } - if(mCurrentFilePoolp) - { - mCurrentFilePoolp->clearVolatileAPRPool() ; - mCurrentFilePoolp = NULL ; - } + if(mCurrentFilePoolp) + { + mCurrentFilePoolp->clearVolatileAPRPool() ; + mCurrentFilePoolp = NULL ; + } - return ret ; + return ret ; } apr_status_t LLAPRFile::open(const std::string& filename, apr_int32_t flags, LLVolatileAPRPool* pool, S32* sizep) { - apr_status_t s ; - - //check if already open some file - llassert_always(!mFile) ; - llassert_always(!mCurrentFilePoolp) ; - - mCurrentFilePoolp = pool ? pool : sAPRFilePoolp; - apr_pool_t* apr_pool = mCurrentFilePoolp->getVolatileAPRPool(); //paired with clear in close() - s = apr_file_open(&mFile, filename.c_str(), flags, APR_OS_DEFAULT, apr_pool); - - if (s != APR_SUCCESS || !mFile) - { - mFile = NULL ; - - if (sizep) - { - *sizep = 0; - } - } - else if (sizep) - { - S32 file_size = 0; - apr_off_t offset = 0; - if (apr_file_seek(mFile, APR_END, &offset) == APR_SUCCESS) - { - llassert_always(offset <= 0x7fffffff); - file_size = (S32)offset; - offset = 0; - apr_file_seek(mFile, APR_SET, &offset); - } - *sizep = file_size; - } - - if (!mFile) - { - // It will clean pool - close() ; - } - - return s ; + apr_status_t s ; + + //check if already open some file + llassert_always(!mFile) ; + llassert_always(!mCurrentFilePoolp) ; + + mCurrentFilePoolp = pool ? pool : sAPRFilePoolp; + apr_pool_t* apr_pool = mCurrentFilePoolp->getVolatileAPRPool(); //paired with clear in close() + s = apr_file_open(&mFile, filename.c_str(), flags, APR_OS_DEFAULT, apr_pool); + + if (s != APR_SUCCESS || !mFile) + { + mFile = NULL ; + + if (sizep) + { + *sizep = 0; + } + } + else if (sizep) + { + S32 file_size = 0; + apr_off_t offset = 0; + if (apr_file_seek(mFile, APR_END, &offset) == APR_SUCCESS) + { + llassert_always(offset <= 0x7fffffff); + file_size = (S32)offset; + offset = 0; + apr_file_seek(mFile, APR_SET, &offset); + } + *sizep = file_size; + } + + if (!mFile) + { + // It will clean pool + close() ; + } + + return s ; } //use gAPRPoolp. apr_status_t LLAPRFile::open(const std::string& filename, apr_int32_t flags, BOOL use_global_pool) { - apr_status_t s; + apr_status_t s; - //check if already open some file - llassert_always(!mFile) ; - llassert_always(!mCurrentFilePoolp) ; - llassert_always(use_global_pool) ; //be aware of using gAPRPoolp. - - s = apr_file_open(&mFile, filename.c_str(), flags, APR_OS_DEFAULT, gAPRPoolp); - if (s != APR_SUCCESS || !mFile) - { - mFile = NULL ; - close() ; - return s; - } + //check if already open some file + llassert_always(!mFile) ; + llassert_always(!mCurrentFilePoolp) ; + llassert_always(use_global_pool) ; //be aware of using gAPRPoolp. - return s; + s = apr_file_open(&mFile, filename.c_str(), flags, APR_OS_DEFAULT, gAPRPoolp); + if (s != APR_SUCCESS || !mFile) + { + mFile = NULL ; + close() ; + return s; + } + + return s; } // File I/O S32 LLAPRFile::read(void *buf, S32 nbytes) { - if(!mFile) - { - LL_WARNS() << "apr mFile is removed by somebody else. Can not read." << LL_ENDL ; - return 0; - } - - apr_size_t sz = nbytes; - apr_status_t s = apr_file_read(mFile, buf, &sz); - if (s != APR_SUCCESS) - { - ll_apr_warn_status(s); - return 0; - } - else - { - llassert_always(sz <= 0x7fffffff); - return (S32)sz; - } + if(!mFile) + { + LL_WARNS() << "apr mFile is removed by somebody else. Can not read." << LL_ENDL ; + return 0; + } + + apr_size_t sz = nbytes; + apr_status_t s = apr_file_read(mFile, buf, &sz); + if (s != APR_SUCCESS) + { + ll_apr_warn_status(s); + return 0; + } + else + { + llassert_always(sz <= 0x7fffffff); + return (S32)sz; + } } S32 LLAPRFile::write(const void *buf, S32 nbytes) { - if(!mFile) - { - LL_WARNS() << "apr mFile is removed by somebody else. Can not write." << LL_ENDL ; - return 0; - } - - apr_size_t sz = nbytes; - apr_status_t s = apr_file_write(mFile, buf, &sz); - if (s != APR_SUCCESS) - { - ll_apr_warn_status(s); - return 0; - } - else - { - llassert_always(sz <= 0x7fffffff); - return (S32)sz; - } + if(!mFile) + { + LL_WARNS() << "apr mFile is removed by somebody else. Can not write." << LL_ENDL ; + return 0; + } + + apr_size_t sz = nbytes; + apr_status_t s = apr_file_write(mFile, buf, &sz); + if (s != APR_SUCCESS) + { + ll_apr_warn_status(s); + return 0; + } + else + { + llassert_always(sz <= 0x7fffffff); + return (S32)sz; + } } S32 LLAPRFile::seek(apr_seek_where_t where, S32 offset) { - return LLAPRFile::seek(mFile, where, offset) ; + return LLAPRFile::seek(mFile, where, offset) ; } // @@ -461,285 +461,285 @@ S32 LLAPRFile::seek(apr_seek_where_t where, S32 offset) // //static -apr_status_t LLAPRFile::close(apr_file_t* file_handle) +apr_status_t LLAPRFile::close(apr_file_t* file_handle) { - apr_status_t ret = APR_SUCCESS ; - if(file_handle) - { - ret = apr_file_close(file_handle); - file_handle = NULL ; - } + apr_status_t ret = APR_SUCCESS ; + if(file_handle) + { + ret = apr_file_close(file_handle); + file_handle = NULL ; + } - return ret ; + return ret ; } //static apr_file_t* LLAPRFile::open(const std::string& filename, apr_pool_t* apr_pool, apr_int32_t flags) { - apr_status_t s; - apr_file_t* file_handle ; + apr_status_t s; + apr_file_t* file_handle ; - s = apr_file_open(&file_handle, filename.c_str(), flags, APR_OS_DEFAULT, apr_pool); - if (s != APR_SUCCESS || !file_handle) - { - ll_apr_warn_status(s); - LL_WARNS("APR") << " Attempting to open filename: " << filename << LL_ENDL; - file_handle = NULL ; - close(file_handle) ; - return NULL; - } + s = apr_file_open(&file_handle, filename.c_str(), flags, APR_OS_DEFAULT, apr_pool); + if (s != APR_SUCCESS || !file_handle) + { + ll_apr_warn_status(s); + LL_WARNS("APR") << " Attempting to open filename: " << filename << LL_ENDL; + file_handle = NULL ; + close(file_handle) ; + return NULL; + } - return file_handle ; + return file_handle ; } //static S32 LLAPRFile::seek(apr_file_t* file_handle, apr_seek_where_t where, S32 offset) { - if(!file_handle) - { - return -1 ; - } - - apr_status_t s; - apr_off_t apr_offset; - if (offset >= 0) - { - apr_offset = (apr_off_t)offset; - s = apr_file_seek(file_handle, where, &apr_offset); - } - else - { - apr_offset = 0; - s = apr_file_seek(file_handle, APR_END, &apr_offset); - } - if (s != APR_SUCCESS) - { - ll_apr_warn_status(s); - return -1; - } - else - { - llassert_always(apr_offset <= 0x7fffffff); - return (S32)apr_offset; - } + if(!file_handle) + { + return -1 ; + } + + apr_status_t s; + apr_off_t apr_offset; + if (offset >= 0) + { + apr_offset = (apr_off_t)offset; + s = apr_file_seek(file_handle, where, &apr_offset); + } + else + { + apr_offset = 0; + s = apr_file_seek(file_handle, APR_END, &apr_offset); + } + if (s != APR_SUCCESS) + { + ll_apr_warn_status(s); + return -1; + } + else + { + llassert_always(apr_offset <= 0x7fffffff); + return (S32)apr_offset; + } } //static S32 LLAPRFile::readEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool) { LL_PROFILE_ZONE_SCOPED; - //***************************************** - LLAPRFilePoolScope scope(pool); - apr_file_t* file_handle = open(filename, scope.getVolatileAPRPool(), APR_READ|APR_BINARY); - //***************************************** - if (!file_handle) - { - return 0; - } - - llassert(offset >= 0); - - if (offset > 0) - offset = LLAPRFile::seek(file_handle, APR_SET, offset); - - apr_size_t bytes_read; - if (offset < 0) - { - bytes_read = 0; - } - else - { - bytes_read = nbytes ; - apr_status_t s = apr_file_read(file_handle, buf, &bytes_read); - if (s != APR_SUCCESS) - { - LL_WARNS("APR") << " Attempting to read filename: " << filename << LL_ENDL; - ll_apr_warn_status(s); - bytes_read = 0; - } - else - { - llassert_always(bytes_read <= 0x7fffffff); - } - } - - //***************************************** - close(file_handle) ; - //***************************************** - return (S32)bytes_read; + //***************************************** + LLAPRFilePoolScope scope(pool); + apr_file_t* file_handle = open(filename, scope.getVolatileAPRPool(), APR_READ|APR_BINARY); + //***************************************** + if (!file_handle) + { + return 0; + } + + llassert(offset >= 0); + + if (offset > 0) + offset = LLAPRFile::seek(file_handle, APR_SET, offset); + + apr_size_t bytes_read; + if (offset < 0) + { + bytes_read = 0; + } + else + { + bytes_read = nbytes ; + apr_status_t s = apr_file_read(file_handle, buf, &bytes_read); + if (s != APR_SUCCESS) + { + LL_WARNS("APR") << " Attempting to read filename: " << filename << LL_ENDL; + ll_apr_warn_status(s); + bytes_read = 0; + } + else + { + llassert_always(bytes_read <= 0x7fffffff); + } + } + + //***************************************** + close(file_handle) ; + //***************************************** + return (S32)bytes_read; } //static S32 LLAPRFile::writeEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool) { LL_PROFILE_ZONE_SCOPED; - apr_int32_t flags = APR_CREATE|APR_WRITE|APR_BINARY; - if (offset < 0) - { - flags |= APR_APPEND; - offset = 0; - } - - //***************************************** - LLAPRFilePoolScope scope(pool); - apr_file_t* file_handle = open(filename, scope.getVolatileAPRPool(), flags); - //***************************************** - if (!file_handle) - { - return 0; - } - - if (offset > 0) - { - offset = LLAPRFile::seek(file_handle, APR_SET, offset); - } - - apr_size_t bytes_written; - if (offset < 0) - { - bytes_written = 0; - } - else - { - bytes_written = nbytes ; - apr_status_t s = apr_file_write(file_handle, buf, &bytes_written); - if (s != APR_SUCCESS) - { - LL_WARNS("APR") << " Attempting to write filename: " << filename << LL_ENDL; - ll_apr_warn_status(s); - bytes_written = 0; - } - else - { - llassert_always(bytes_written <= 0x7fffffff); - } - } - - //***************************************** - LLAPRFile::close(file_handle); - //***************************************** - - return (S32)bytes_written; + apr_int32_t flags = APR_CREATE|APR_WRITE|APR_BINARY; + if (offset < 0) + { + flags |= APR_APPEND; + offset = 0; + } + + //***************************************** + LLAPRFilePoolScope scope(pool); + apr_file_t* file_handle = open(filename, scope.getVolatileAPRPool(), flags); + //***************************************** + if (!file_handle) + { + return 0; + } + + if (offset > 0) + { + offset = LLAPRFile::seek(file_handle, APR_SET, offset); + } + + apr_size_t bytes_written; + if (offset < 0) + { + bytes_written = 0; + } + else + { + bytes_written = nbytes ; + apr_status_t s = apr_file_write(file_handle, buf, &bytes_written); + if (s != APR_SUCCESS) + { + LL_WARNS("APR") << " Attempting to write filename: " << filename << LL_ENDL; + ll_apr_warn_status(s); + bytes_written = 0; + } + else + { + llassert_always(bytes_written <= 0x7fffffff); + } + } + + //***************************************** + LLAPRFile::close(file_handle); + //***************************************** + + return (S32)bytes_written; } //static bool LLAPRFile::remove(const std::string& filename, LLVolatileAPRPool* pool) { - apr_status_t s; + apr_status_t s; - LLAPRFilePoolScope scope(pool); - s = apr_file_remove(filename.c_str(), scope.getVolatileAPRPool()); + LLAPRFilePoolScope scope(pool); + s = apr_file_remove(filename.c_str(), scope.getVolatileAPRPool()); - if (s != APR_SUCCESS) - { - ll_apr_warn_status(s); - LL_WARNS("APR") << " Attempting to remove filename: " << filename << LL_ENDL; - return false; - } - return true; + if (s != APR_SUCCESS) + { + ll_apr_warn_status(s); + LL_WARNS("APR") << " Attempting to remove filename: " << filename << LL_ENDL; + return false; + } + return true; } //static bool LLAPRFile::rename(const std::string& filename, const std::string& newname, LLVolatileAPRPool* pool) { - apr_status_t s; + apr_status_t s; + + LLAPRFilePoolScope scope(pool); + s = apr_file_rename(filename.c_str(), newname.c_str(), scope.getVolatileAPRPool()); - LLAPRFilePoolScope scope(pool); - s = apr_file_rename(filename.c_str(), newname.c_str(), scope.getVolatileAPRPool()); - - if (s != APR_SUCCESS) - { - ll_apr_warn_status(s); - LL_WARNS("APR") << " Attempting to rename filename: " << filename << LL_ENDL; - return false; - } - return true; + if (s != APR_SUCCESS) + { + ll_apr_warn_status(s); + LL_WARNS("APR") << " Attempting to rename filename: " << filename << LL_ENDL; + return false; + } + return true; } //static bool LLAPRFile::isExist(const std::string& filename, LLVolatileAPRPool* pool, apr_int32_t flags) { - apr_file_t* apr_file; - apr_status_t s; + apr_file_t* apr_file; + apr_status_t s; - LLAPRFilePoolScope scope(pool); - s = apr_file_open(&apr_file, filename.c_str(), flags, APR_OS_DEFAULT, scope.getVolatileAPRPool()); + LLAPRFilePoolScope scope(pool); + s = apr_file_open(&apr_file, filename.c_str(), flags, APR_OS_DEFAULT, scope.getVolatileAPRPool()); - if (s != APR_SUCCESS || !apr_file) - { - return false; - } - else - { - apr_file_close(apr_file) ; - return true; - } + if (s != APR_SUCCESS || !apr_file) + { + return false; + } + else + { + apr_file_close(apr_file) ; + return true; + } } //static S32 LLAPRFile::size(const std::string& filename, LLVolatileAPRPool* pool) { - apr_file_t* apr_file; - apr_finfo_t info; - apr_status_t s; - - LLAPRFilePoolScope scope(pool); - s = apr_file_open(&apr_file, filename.c_str(), APR_READ, APR_OS_DEFAULT, scope.getVolatileAPRPool()); - - if (s != APR_SUCCESS || !apr_file) - { - return 0; - } - else - { - apr_status_t s = apr_file_info_get(&info, APR_FINFO_SIZE, apr_file); - - apr_file_close(apr_file) ; - - if (s == APR_SUCCESS) - { - return (S32)info.size; - } - else - { - return 0; - } - } + apr_file_t* apr_file; + apr_finfo_t info; + apr_status_t s; + + LLAPRFilePoolScope scope(pool); + s = apr_file_open(&apr_file, filename.c_str(), APR_READ, APR_OS_DEFAULT, scope.getVolatileAPRPool()); + + if (s != APR_SUCCESS || !apr_file) + { + return 0; + } + else + { + apr_status_t s = apr_file_info_get(&info, APR_FINFO_SIZE, apr_file); + + apr_file_close(apr_file) ; + + if (s == APR_SUCCESS) + { + return (S32)info.size; + } + else + { + return 0; + } + } } //static bool LLAPRFile::makeDir(const std::string& dirname, LLVolatileAPRPool* pool) { - apr_status_t s; + apr_status_t s; + + LLAPRFilePoolScope scope(pool); + s = apr_dir_make(dirname.c_str(), APR_FPROT_OS_DEFAULT, scope.getVolatileAPRPool()); - LLAPRFilePoolScope scope(pool); - s = apr_dir_make(dirname.c_str(), APR_FPROT_OS_DEFAULT, scope.getVolatileAPRPool()); - - if (s != APR_SUCCESS) - { - ll_apr_warn_status(s); - LL_WARNS("APR") << " Attempting to make directory: " << dirname << LL_ENDL; - return false; - } - return true; + if (s != APR_SUCCESS) + { + ll_apr_warn_status(s); + LL_WARNS("APR") << " Attempting to make directory: " << dirname << LL_ENDL; + return false; + } + return true; } //static bool LLAPRFile::removeDir(const std::string& dirname, LLVolatileAPRPool* pool) { - apr_status_t s; - - LLAPRFilePoolScope scope(pool); - s = apr_file_remove(dirname.c_str(), scope.getVolatileAPRPool()); - - if (s != APR_SUCCESS) - { - ll_apr_warn_status(s); - LL_WARNS("APR") << " Attempting to remove directory: " << dirname << LL_ENDL; - return false; - } - return true; + apr_status_t s; + + LLAPRFilePoolScope scope(pool); + s = apr_file_remove(dirname.c_str(), scope.getVolatileAPRPool()); + + if (s != APR_SUCCESS) + { + ll_apr_warn_status(s); + LL_WARNS("APR") << " Attempting to remove directory: " << dirname << LL_ENDL; + return false; + } + return true; } // //end of static components of LLAPRFile diff --git a/indra/llcommon/llapr.h b/indra/llcommon/llapr.h index 565d7cfb63..2f88fdcd59 100644 --- a/indra/llcommon/llapr.h +++ b/indra/llcommon/llapr.h @@ -1,4 +1,4 @@ -/** +/** * @file llapr.h * @author Phoenix * @date 2004-11-28 @@ -7,21 +7,21 @@ * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -57,13 +57,13 @@ void LL_COMMON_API _ll_apr_assert_status(apr_status_t status, const char* file, extern "C" LL_COMMON_API apr_pool_t* gAPRPoolp; // Global APR memory pool -/** +/** * @brief initialize the common apr constructs -- apr itself, the * global pool, and a mutex. */ void LL_COMMON_API ll_init_apr(); -/** +/** * @brief Cleanup those common apr constructs. */ void LL_COMMON_API ll_cleanup_apr(); @@ -78,22 +78,22 @@ bool LL_COMMON_API ll_apr_is_initialized(); class LL_COMMON_API LLAPRPool { public: - LLAPRPool(apr_pool_t *parent = NULL, apr_size_t size = 0, BOOL releasePoolFlag = TRUE) ; - virtual ~LLAPRPool() ; + LLAPRPool(apr_pool_t *parent = NULL, apr_size_t size = 0, BOOL releasePoolFlag = TRUE) ; + virtual ~LLAPRPool() ; - virtual apr_pool_t* getAPRPool() ; - apr_status_t getStatus() {return mStatus ; } + virtual apr_pool_t* getAPRPool() ; + apr_status_t getStatus() {return mStatus ; } protected: - void releaseAPRPool() ; - void createAPRPool() ; + void releaseAPRPool() ; + void createAPRPool() ; protected: - apr_pool_t* mPool ; //pointing to an apr_pool - apr_pool_t* mParent ; //parent pool - apr_size_t mMaxSize ; //max size of mPool, mPool should return memory to system if allocated memory beyond this limit. However it seems not to work. - apr_status_t mStatus ; //status when creating the pool - BOOL mReleasePoolFlag ; //if set, mPool is destroyed when LLAPRPool is deleted. default value is true. + apr_pool_t* mPool ; //pointing to an apr_pool + apr_pool_t* mParent ; //parent pool + apr_size_t mMaxSize ; //max size of mPool, mPool should return memory to system if allocated memory beyond this limit. However it seems not to work. + apr_status_t mStatus ; //status when creating the pool + BOOL mReleasePoolFlag ; //if set, mPool is destroyed when LLAPRPool is deleted. default value is true. }; // @@ -104,20 +104,20 @@ protected: class LL_COMMON_API LLVolatileAPRPool : public LLAPRPool { public: - LLVolatileAPRPool(BOOL is_local = TRUE, apr_pool_t *parent = NULL, apr_size_t size = 0, BOOL releasePoolFlag = TRUE); - virtual ~LLVolatileAPRPool(); + LLVolatileAPRPool(BOOL is_local = TRUE, apr_pool_t *parent = NULL, apr_size_t size = 0, BOOL releasePoolFlag = TRUE); + virtual ~LLVolatileAPRPool(); - /*virtual*/ apr_pool_t* getAPRPool() ; //define this virtual function to avoid any mistakenly calling LLAPRPool::getAPRPool(). - apr_pool_t* getVolatileAPRPool() ; - void clearVolatileAPRPool() ; + /*virtual*/ apr_pool_t* getAPRPool() ; //define this virtual function to avoid any mistakenly calling LLAPRPool::getAPRPool(). + apr_pool_t* getVolatileAPRPool() ; + void clearVolatileAPRPool() ; + + BOOL isFull() ; - BOOL isFull() ; - private: - S32 mNumActiveRef ; //number of active pointers pointing to the apr_pool. - S32 mNumTotalRef ; //number of total pointers pointing to the apr_pool since last creating. + S32 mNumActiveRef ; //number of active pointers pointing to the apr_pool. + S32 mNumTotalRef ; //number of total pointers pointing to the apr_pool since last creating. - std::unique_ptr mMutexp; + std::unique_ptr mMutexp; } ; // File IO convenience functions. @@ -137,7 +137,7 @@ private: //which: 1)only keeps one file open; // 2)closes the open file in the destruction function // 3)informs the apr_pool to clean the memory when the file is closed. -//Note: please close an open file at the earliest convenience. +//Note: please close an open file at the earliest convenience. // especially do not put some time-costly operations between open() and close(). // otherwise it might lock the APRFilePool. //there are two different apr_pools the APRFile can use: @@ -147,53 +147,53 @@ private: class LL_COMMON_API LLAPRFile : boost::noncopyable { - // make this non copyable since a copy closes the file + // make this non copyable since a copy closes the file private: - apr_file_t* mFile ; - LLVolatileAPRPool *mCurrentFilePoolp ; //currently in use apr_pool, could be one of them: sAPRFilePoolp, or a temp pool. + apr_file_t* mFile ; + LLVolatileAPRPool *mCurrentFilePoolp ; //currently in use apr_pool, could be one of them: sAPRFilePoolp, or a temp pool. public: - LLAPRFile() ; - LLAPRFile(const std::string& filename, apr_int32_t flags, LLVolatileAPRPool* pool = NULL); - ~LLAPRFile() ; - - apr_status_t open(const std::string& filename, apr_int32_t flags, LLVolatileAPRPool* pool = NULL, S32* sizep = NULL); - apr_status_t open(const std::string& filename, apr_int32_t flags, BOOL use_global_pool); //use gAPRPoolp. - apr_status_t close() ; - - // Returns actual offset, -1 if seek fails - S32 seek(apr_seek_where_t where, S32 offset); - apr_status_t eof() { return apr_file_eof(mFile);} - - // Returns bytes read/written, 0 if read/write fails: - S32 read(void* buf, S32 nbytes); - S32 write(const void* buf, S32 nbytes); - - apr_file_t* getFileHandle() {return mFile;} - + LLAPRFile() ; + LLAPRFile(const std::string& filename, apr_int32_t flags, LLVolatileAPRPool* pool = NULL); + ~LLAPRFile() ; + + apr_status_t open(const std::string& filename, apr_int32_t flags, LLVolatileAPRPool* pool = NULL, S32* sizep = NULL); + apr_status_t open(const std::string& filename, apr_int32_t flags, BOOL use_global_pool); //use gAPRPoolp. + apr_status_t close() ; + + // Returns actual offset, -1 if seek fails + S32 seek(apr_seek_where_t where, S32 offset); + apr_status_t eof() { return apr_file_eof(mFile);} + + // Returns bytes read/written, 0 if read/write fails: + S32 read(void* buf, S32 nbytes); + S32 write(const void* buf, S32 nbytes); + + apr_file_t* getFileHandle() {return mFile;} + // //******************************************************************************************************************************* //static components // public: - static LLVolatileAPRPool *sAPRFilePoolp ; //a global apr_pool for APRFile, which is used only when local pool does not exist. + static LLVolatileAPRPool *sAPRFilePoolp ; //a global apr_pool for APRFile, which is used only when local pool does not exist. private: - static apr_file_t* open(const std::string& filename, apr_pool_t* apr_pool, apr_int32_t flags); - static apr_status_t close(apr_file_t* file) ; - static S32 seek(apr_file_t* file, apr_seek_where_t where, S32 offset); + static apr_file_t* open(const std::string& filename, apr_pool_t* apr_pool, apr_int32_t flags); + static apr_status_t close(apr_file_t* file) ; + static S32 seek(apr_file_t* file, apr_seek_where_t where, S32 offset); public: - // returns false if failure: - static bool remove(const std::string& filename, LLVolatileAPRPool* pool = NULL); - static bool rename(const std::string& filename, const std::string& newname, LLVolatileAPRPool* pool = NULL); - static bool isExist(const std::string& filename, LLVolatileAPRPool* pool = NULL, apr_int32_t flags = APR_READ); - static S32 size(const std::string& filename, LLVolatileAPRPool* pool = NULL); - static bool makeDir(const std::string& dirname, LLVolatileAPRPool* pool = NULL); - static bool removeDir(const std::string& dirname, LLVolatileAPRPool* pool = NULL); - - // Returns bytes read/written, 0 if read/write fails: - static S32 readEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool = NULL); - static S32 writeEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool = NULL); // offset<0 means append + // returns false if failure: + static bool remove(const std::string& filename, LLVolatileAPRPool* pool = NULL); + static bool rename(const std::string& filename, const std::string& newname, LLVolatileAPRPool* pool = NULL); + static bool isExist(const std::string& filename, LLVolatileAPRPool* pool = NULL, apr_int32_t flags = APR_READ); + static S32 size(const std::string& filename, LLVolatileAPRPool* pool = NULL); + static bool makeDir(const std::string& dirname, LLVolatileAPRPool* pool = NULL); + static bool removeDir(const std::string& dirname, LLVolatileAPRPool* pool = NULL); + + // Returns bytes read/written, 0 if read/write fails: + static S32 readEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool = NULL); + static S32 writeEx(const std::string& filename, void *buf, S32 offset, S32 nbytes, LLVolatileAPRPool* pool = NULL); // offset<0 means append //******************************************************************************************************************************* }; diff --git a/indra/llcommon/llassettype.cpp b/indra/llcommon/llassettype.cpp index 6492d888c1..3e46bde954 100644 --- a/indra/llcommon/llassettype.cpp +++ b/indra/llcommon/llassettype.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llassettype.cpp * @brief Implementatino of LLAssetType functionality. * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -36,69 +36,69 @@ ///---------------------------------------------------------------------------- struct AssetEntry : public LLDictionaryEntry { - AssetEntry(const char *desc_name, - const char *type_name, // 8 character limit! - const char *human_name, // for decoding to human readable form; put any and as many printable characters you want in each one - bool can_link, // can you create a link to this type? - bool can_fetch, // can you fetch this asset by ID? - bool can_know) // can you see this asset's ID? - : - LLDictionaryEntry(desc_name), - mTypeName(type_name), - mHumanName(human_name), - mCanLink(can_link), - mCanFetch(can_fetch), - mCanKnow(can_know) - { - llassert(strlen(mTypeName) <= 8); - } - - const char *mTypeName; - const char *mHumanName; - bool mCanLink; - bool mCanFetch; - bool mCanKnow; + AssetEntry(const char *desc_name, + const char *type_name, // 8 character limit! + const char *human_name, // for decoding to human readable form; put any and as many printable characters you want in each one + bool can_link, // can you create a link to this type? + bool can_fetch, // can you fetch this asset by ID? + bool can_know) // can you see this asset's ID? + : + LLDictionaryEntry(desc_name), + mTypeName(type_name), + mHumanName(human_name), + mCanLink(can_link), + mCanFetch(can_fetch), + mCanKnow(can_know) + { + llassert(strlen(mTypeName) <= 8); + } + + const char *mTypeName; + const char *mHumanName; + bool mCanLink; + bool mCanFetch; + bool mCanKnow; }; class LLAssetDictionary : public LLSingleton, - public LLDictionary + public LLDictionary { - LLSINGLETON(LLAssetDictionary); + LLSINGLETON(LLAssetDictionary); }; LLAssetDictionary::LLAssetDictionary() { - // DESCRIPTION TYPE NAME HUMAN NAME CAN LINK? CAN FETCH? CAN KNOW? - // |--------------------|-----------|-------------------|-----------|-----------|---------| - addEntry(LLAssetType::AT_TEXTURE, new AssetEntry("TEXTURE", "texture", "texture", true, false, true)); - addEntry(LLAssetType::AT_SOUND, new AssetEntry("SOUND", "sound", "sound", true, true, true)); - addEntry(LLAssetType::AT_CALLINGCARD, new AssetEntry("CALLINGCARD", "callcard", "calling card", true, false, false)); - addEntry(LLAssetType::AT_LANDMARK, new AssetEntry("LANDMARK", "landmark", "landmark", true, true, true)); - addEntry(LLAssetType::AT_SCRIPT, new AssetEntry("SCRIPT", "script", "legacy script", true, false, false)); - addEntry(LLAssetType::AT_CLOTHING, new AssetEntry("CLOTHING", "clothing", "clothing", true, true, true)); - addEntry(LLAssetType::AT_OBJECT, new AssetEntry("OBJECT", "object", "object", true, false, false)); - addEntry(LLAssetType::AT_NOTECARD, new AssetEntry("NOTECARD", "notecard", "note card", true, false, true)); - addEntry(LLAssetType::AT_CATEGORY, new AssetEntry("CATEGORY", "category", "folder", true, false, false)); - addEntry(LLAssetType::AT_LSL_TEXT, new AssetEntry("LSL_TEXT", "lsltext", "lsl2 script", true, false, false)); - addEntry(LLAssetType::AT_LSL_BYTECODE, new AssetEntry("LSL_BYTECODE", "lslbyte", "lsl bytecode", true, false, false)); - addEntry(LLAssetType::AT_TEXTURE_TGA, new AssetEntry("TEXTURE_TGA", "txtr_tga", "tga texture", true, false, false)); - addEntry(LLAssetType::AT_BODYPART, new AssetEntry("BODYPART", "bodypart", "body part", true, true, true)); - addEntry(LLAssetType::AT_SOUND_WAV, new AssetEntry("SOUND_WAV", "snd_wav", "sound", true, false, false)); - addEntry(LLAssetType::AT_IMAGE_TGA, new AssetEntry("IMAGE_TGA", "img_tga", "targa image", true, false, false)); - addEntry(LLAssetType::AT_IMAGE_JPEG, new AssetEntry("IMAGE_JPEG", "jpeg", "jpeg image", true, false, false)); - addEntry(LLAssetType::AT_ANIMATION, new AssetEntry("ANIMATION", "animatn", "animation", true, true, true)); - addEntry(LLAssetType::AT_GESTURE, new AssetEntry("GESTURE", "gesture", "gesture", true, true, true)); - addEntry(LLAssetType::AT_SIMSTATE, new AssetEntry("SIMSTATE", "simstate", "simstate", false, false, false)); - - addEntry(LLAssetType::AT_LINK, new AssetEntry("LINK", "link", "sym link", false, false, true)); - addEntry(LLAssetType::AT_LINK_FOLDER, new AssetEntry("FOLDER_LINK", "link_f", "sym folder link", false, false, true)); - addEntry(LLAssetType::AT_MESH, new AssetEntry("MESH", "mesh", "mesh", false, false, false)); - addEntry(LLAssetType::AT_WIDGET, new AssetEntry("WIDGET", "widget", "widget", false, false, false)); - addEntry(LLAssetType::AT_PERSON, new AssetEntry("PERSON", "person", "person", false, false, false)); - addEntry(LLAssetType::AT_SETTINGS, new AssetEntry("SETTINGS", "settings", "settings blob", true, true, true)); - addEntry(LLAssetType::AT_MATERIAL, new AssetEntry("MATERIAL", "material", "render material", true, true, true)); - addEntry(LLAssetType::AT_UNKNOWN, new AssetEntry("UNKNOWN", "invalid", NULL, false, false, false)); - addEntry(LLAssetType::AT_NONE, new AssetEntry("NONE", "-1", NULL, FALSE, FALSE, FALSE)); + // DESCRIPTION TYPE NAME HUMAN NAME CAN LINK? CAN FETCH? CAN KNOW? + // |--------------------|-----------|-------------------|-----------|-----------|---------| + addEntry(LLAssetType::AT_TEXTURE, new AssetEntry("TEXTURE", "texture", "texture", true, false, true)); + addEntry(LLAssetType::AT_SOUND, new AssetEntry("SOUND", "sound", "sound", true, true, true)); + addEntry(LLAssetType::AT_CALLINGCARD, new AssetEntry("CALLINGCARD", "callcard", "calling card", true, false, false)); + addEntry(LLAssetType::AT_LANDMARK, new AssetEntry("LANDMARK", "landmark", "landmark", true, true, true)); + addEntry(LLAssetType::AT_SCRIPT, new AssetEntry("SCRIPT", "script", "legacy script", true, false, false)); + addEntry(LLAssetType::AT_CLOTHING, new AssetEntry("CLOTHING", "clothing", "clothing", true, true, true)); + addEntry(LLAssetType::AT_OBJECT, new AssetEntry("OBJECT", "object", "object", true, false, false)); + addEntry(LLAssetType::AT_NOTECARD, new AssetEntry("NOTECARD", "notecard", "note card", true, false, true)); + addEntry(LLAssetType::AT_CATEGORY, new AssetEntry("CATEGORY", "category", "folder", true, false, false)); + addEntry(LLAssetType::AT_LSL_TEXT, new AssetEntry("LSL_TEXT", "lsltext", "lsl2 script", true, false, false)); + addEntry(LLAssetType::AT_LSL_BYTECODE, new AssetEntry("LSL_BYTECODE", "lslbyte", "lsl bytecode", true, false, false)); + addEntry(LLAssetType::AT_TEXTURE_TGA, new AssetEntry("TEXTURE_TGA", "txtr_tga", "tga texture", true, false, false)); + addEntry(LLAssetType::AT_BODYPART, new AssetEntry("BODYPART", "bodypart", "body part", true, true, true)); + addEntry(LLAssetType::AT_SOUND_WAV, new AssetEntry("SOUND_WAV", "snd_wav", "sound", true, false, false)); + addEntry(LLAssetType::AT_IMAGE_TGA, new AssetEntry("IMAGE_TGA", "img_tga", "targa image", true, false, false)); + addEntry(LLAssetType::AT_IMAGE_JPEG, new AssetEntry("IMAGE_JPEG", "jpeg", "jpeg image", true, false, false)); + addEntry(LLAssetType::AT_ANIMATION, new AssetEntry("ANIMATION", "animatn", "animation", true, true, true)); + addEntry(LLAssetType::AT_GESTURE, new AssetEntry("GESTURE", "gesture", "gesture", true, true, true)); + addEntry(LLAssetType::AT_SIMSTATE, new AssetEntry("SIMSTATE", "simstate", "simstate", false, false, false)); + + addEntry(LLAssetType::AT_LINK, new AssetEntry("LINK", "link", "sym link", false, false, true)); + addEntry(LLAssetType::AT_LINK_FOLDER, new AssetEntry("FOLDER_LINK", "link_f", "sym folder link", false, false, true)); + addEntry(LLAssetType::AT_MESH, new AssetEntry("MESH", "mesh", "mesh", false, false, false)); + addEntry(LLAssetType::AT_WIDGET, new AssetEntry("WIDGET", "widget", "widget", false, false, false)); + addEntry(LLAssetType::AT_PERSON, new AssetEntry("PERSON", "person", "person", false, false, false)); + addEntry(LLAssetType::AT_SETTINGS, new AssetEntry("SETTINGS", "settings", "settings blob", true, true, true)); + addEntry(LLAssetType::AT_MATERIAL, new AssetEntry("MATERIAL", "material", "render material", true, true, true)); + addEntry(LLAssetType::AT_UNKNOWN, new AssetEntry("UNKNOWN", "invalid", NULL, false, false, false)); + addEntry(LLAssetType::AT_NONE, new AssetEntry("NONE", "-1", NULL, FALSE, FALSE, FALSE)); }; @@ -107,140 +107,140 @@ const std::string LLAssetType::BADLOOKUP("llassettype_bad_lookup"); // static LLAssetType::EType LLAssetType::getType(const std::string& desc_name) { - std::string s = desc_name; - LLStringUtil::toUpper(s); - return LLAssetDictionary::getInstance()->lookup(s); + std::string s = desc_name; + LLStringUtil::toUpper(s); + return LLAssetDictionary::getInstance()->lookup(s); } // static const std::string &LLAssetType::getDesc(LLAssetType::EType asset_type) { - const AssetEntry *entry = LLAssetDictionary::getInstance()->lookup(asset_type); - if (entry) - { - return entry->mName; - } - else - { - return BADLOOKUP; - } + const AssetEntry *entry = LLAssetDictionary::getInstance()->lookup(asset_type); + if (entry) + { + return entry->mName; + } + else + { + return BADLOOKUP; + } } // static const char *LLAssetType::lookup(LLAssetType::EType asset_type) { - const LLAssetDictionary *dict = LLAssetDictionary::getInstance(); - const AssetEntry *entry = dict->lookup(asset_type); - if (entry) - { - return entry->mTypeName; - } - else - { - return BADLOOKUP.c_str(); - } + const LLAssetDictionary *dict = LLAssetDictionary::getInstance(); + const AssetEntry *entry = dict->lookup(asset_type); + if (entry) + { + return entry->mTypeName; + } + else + { + return BADLOOKUP.c_str(); + } } // static LLAssetType::EType LLAssetType::lookup(const char* name) { - return lookup(ll_safe_string(name)); + return lookup(ll_safe_string(name)); } // static LLAssetType::EType LLAssetType::lookup(const std::string& type_name) { - const LLAssetDictionary *dict = LLAssetDictionary::getInstance(); - for (const LLAssetDictionary::value_type& pair : *dict) - { - const AssetEntry *entry = pair.second; - if (type_name == entry->mTypeName) - { - return pair.first; - } - } - return AT_UNKNOWN; + const LLAssetDictionary *dict = LLAssetDictionary::getInstance(); + for (const LLAssetDictionary::value_type& pair : *dict) + { + const AssetEntry *entry = pair.second; + if (type_name == entry->mTypeName) + { + return pair.first; + } + } + return AT_UNKNOWN; } // static const char *LLAssetType::lookupHumanReadable(LLAssetType::EType asset_type) { - const LLAssetDictionary *dict = LLAssetDictionary::getInstance(); - const AssetEntry *entry = dict->lookup(asset_type); - if (entry) - { - return entry->mHumanName; - } - else - { - return BADLOOKUP.c_str(); - } + const LLAssetDictionary *dict = LLAssetDictionary::getInstance(); + const AssetEntry *entry = dict->lookup(asset_type); + if (entry) + { + return entry->mHumanName; + } + else + { + return BADLOOKUP.c_str(); + } } // static LLAssetType::EType LLAssetType::lookupHumanReadable(const char* name) { - return lookupHumanReadable(ll_safe_string(name)); + return lookupHumanReadable(ll_safe_string(name)); } // static LLAssetType::EType LLAssetType::lookupHumanReadable(const std::string& readable_name) { - const LLAssetDictionary *dict = LLAssetDictionary::getInstance(); - for (const LLAssetDictionary::value_type& pair : *dict) - { - const AssetEntry *entry = pair.second; - if (entry->mHumanName && (readable_name == entry->mHumanName)) - { - return pair.first; - } - } - return AT_NONE; + const LLAssetDictionary *dict = LLAssetDictionary::getInstance(); + for (const LLAssetDictionary::value_type& pair : *dict) + { + const AssetEntry *entry = pair.second; + if (entry->mHumanName && (readable_name == entry->mHumanName)) + { + return pair.first; + } + } + return AT_NONE; } // static bool LLAssetType::lookupCanLink(EType asset_type) { - const LLAssetDictionary *dict = LLAssetDictionary::getInstance(); - const AssetEntry *entry = dict->lookup(asset_type); - if (entry) - { - return entry->mCanLink; - } - return false; + const LLAssetDictionary *dict = LLAssetDictionary::getInstance(); + const AssetEntry *entry = dict->lookup(asset_type); + if (entry) + { + return entry->mCanLink; + } + return false; } // static // Not adding this to dictionary since we probably will only have these two types bool LLAssetType::lookupIsLinkType(EType asset_type) { - if (asset_type == AT_LINK || asset_type == AT_LINK_FOLDER) - { - return true; - } - return false; + if (asset_type == AT_LINK || asset_type == AT_LINK_FOLDER) + { + return true; + } + return false; } // static bool LLAssetType::lookupIsAssetFetchByIDAllowed(EType asset_type) { - const LLAssetDictionary *dict = LLAssetDictionary::getInstance(); - const AssetEntry *entry = dict->lookup(asset_type); - if (entry) - { - return entry->mCanFetch; - } - return false; + const LLAssetDictionary *dict = LLAssetDictionary::getInstance(); + const AssetEntry *entry = dict->lookup(asset_type); + if (entry) + { + return entry->mCanFetch; + } + return false; } // static bool LLAssetType::lookupIsAssetIDKnowable(EType asset_type) { - const LLAssetDictionary *dict = LLAssetDictionary::getInstance(); - const AssetEntry *entry = dict->lookup(asset_type); - if (entry) - { - return entry->mCanKnow; - } - return false; + const LLAssetDictionary *dict = LLAssetDictionary::getInstance(); + const AssetEntry *entry = dict->lookup(asset_type); + if (entry) + { + return entry->mCanKnow; + } + return false; } diff --git a/indra/llcommon/llassettype.h b/indra/llcommon/llassettype.h index e8df8574f7..1989155550 100644 --- a/indra/llcommon/llassettype.h +++ b/indra/llcommon/llassettype.h @@ -1,25 +1,25 @@ -/** +/** * @file llassettype.h * @brief Declaration of LLAssetType. * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -32,89 +32,89 @@ class LL_COMMON_API LLAssetType { public: - enum EType - { - AT_TEXTURE = 0, - // Used for painting the faces of geometry. - // Stored in typical j2c stream format. + enum EType + { + AT_TEXTURE = 0, + // Used for painting the faces of geometry. + // Stored in typical j2c stream format. - AT_SOUND = 1, - // Used to fill the aural spectrum. + AT_SOUND = 1, + // Used to fill the aural spectrum. - AT_CALLINGCARD = 2, - // Links instant message access to the user on the card. - // : E.G. A card for yourself, for linden support, for - // : the guy you were talking to in the coliseum. + AT_CALLINGCARD = 2, + // Links instant message access to the user on the card. + // : E.G. A card for yourself, for linden support, for + // : the guy you were talking to in the coliseum. - AT_LANDMARK = 3, - // Links to places in the world with location and a screen shot or image saved. - // : E.G. Home, linden headquarters, the coliseum, destinations where - // : we want to increase traffic. + AT_LANDMARK = 3, + // Links to places in the world with location and a screen shot or image saved. + // : E.G. Home, linden headquarters, the coliseum, destinations where + // : we want to increase traffic. - AT_SCRIPT = 4, - // Valid scripts that can be attached to an object. - // : E.G. Open a door, jump into the air. + AT_SCRIPT = 4, + // Valid scripts that can be attached to an object. + // : E.G. Open a door, jump into the air. - AT_CLOTHING = 5, - // A collection of textures and parameters that can be worn by an avatar. + AT_CLOTHING = 5, + // A collection of textures and parameters that can be worn by an avatar. - AT_OBJECT = 6, - // Any combination of textures, sounds, and scripts that are - // associated with a fixed piece of geometry. - // : E.G. A hot tub, a house with working door. + AT_OBJECT = 6, + // Any combination of textures, sounds, and scripts that are + // associated with a fixed piece of geometry. + // : E.G. A hot tub, a house with working door. - AT_NOTECARD = 7, - // Just text. + AT_NOTECARD = 7, + // Just text. - AT_CATEGORY = 8, - // Holds a collection of inventory items. - // It's treated as an item in the inventory and therefore needs a type. + AT_CATEGORY = 8, + // Holds a collection of inventory items. + // It's treated as an item in the inventory and therefore needs a type. - AT_LSL_TEXT = 10, - AT_LSL_BYTECODE = 11, - // The LSL is the scripting language. - // We've split it into a text and bytecode representation. - - AT_TEXTURE_TGA = 12, - // Uncompressed TGA texture. + AT_LSL_TEXT = 10, + AT_LSL_BYTECODE = 11, + // The LSL is the scripting language. + // We've split it into a text and bytecode representation. - AT_BODYPART = 13, - // A collection of textures and parameters that can be worn by an avatar. + AT_TEXTURE_TGA = 12, + // Uncompressed TGA texture. - AT_SOUND_WAV = 17, - // Uncompressed sound. + AT_BODYPART = 13, + // A collection of textures and parameters that can be worn by an avatar. - AT_IMAGE_TGA = 18, - // Uncompressed image, non-square. - // Not appropriate for use as a texture. + AT_SOUND_WAV = 17, + // Uncompressed sound. - AT_IMAGE_JPEG = 19, - // Compressed image, non-square. - // Not appropriate for use as a texture. + AT_IMAGE_TGA = 18, + // Uncompressed image, non-square. + // Not appropriate for use as a texture. - AT_ANIMATION = 20, - // Animation. + AT_IMAGE_JPEG = 19, + // Compressed image, non-square. + // Not appropriate for use as a texture. - AT_GESTURE = 21, - // Gesture, sequence of animations, sounds, chat, wait steps. + AT_ANIMATION = 20, + // Animation. - AT_SIMSTATE = 22, - // Simstate file. + AT_GESTURE = 21, + // Gesture, sequence of animations, sounds, chat, wait steps. - AT_LINK = 24, - // Inventory symbolic link + AT_SIMSTATE = 22, + // Simstate file. + + AT_LINK = 24, + // Inventory symbolic link + + AT_LINK_FOLDER = 25, + // Inventory folder link - AT_LINK_FOLDER = 25, - // Inventory folder link - AT_MARKETPLACE_FOLDER = 26, // Marketplace folder. Same as an AT_CATEGORY but different display methods. - - AT_WIDGET = 40, - // UI Widget: this is *not* an inventory asset type, only a viewer side asset (e.g. button, other ui items...) - - AT_PERSON = 45, - // A user uuid which is not an inventory asset type, used in viewer only for adding a person to a chat via drag and drop. + + AT_WIDGET = 40, + // UI Widget: this is *not* an inventory asset type, only a viewer side asset (e.g. button, other ui items...) + + AT_PERSON = 45, + // A user uuid which is not an inventory asset type, used in viewer only for adding a person to a chat via drag and drop. AT_MESH = 49, // Mesh data in our proprietary SLM format @@ -129,45 +129,45 @@ public: AT_SETTINGS = 56, // Collection of settings AT_MATERIAL = 57, // Render Material - AT_COUNT = 58, + AT_COUNT = 58, - // +*********************************************************+ - // | TO ADD AN ELEMENT TO THIS ENUM: | - // +*********************************************************+ - // | 1. INSERT BEFORE AT_COUNT | - // | 2. INCREMENT AT_COUNT BY 1 | - // | 3. ADD TO LLAssetType.cpp | - // | 4. ADD TO LLViewerAssetType.cpp | - // | 5. ADD TO DEFAULT_ASSET_FOR_INV in LLInventoryType.cpp | - // +*********************************************************+ - AT_UNKNOWN = 255, - AT_NONE = -1 - }; + // +*********************************************************+ + // | TO ADD AN ELEMENT TO THIS ENUM: | + // +*********************************************************+ + // | 1. INSERT BEFORE AT_COUNT | + // | 2. INCREMENT AT_COUNT BY 1 | + // | 3. ADD TO LLAssetType.cpp | + // | 4. ADD TO LLViewerAssetType.cpp | + // | 5. ADD TO DEFAULT_ASSET_FOR_INV in LLInventoryType.cpp | + // +*********************************************************+ + AT_UNKNOWN = 255, + AT_NONE = -1 + }; - // machine transation between type and strings - static EType lookup(const char* name); // safe conversion to std::string, *TODO: deprecate - static EType lookup(const std::string& type_name); - static const char* lookup(EType asset_type); + // machine transation between type and strings + static EType lookup(const char* name); // safe conversion to std::string, *TODO: deprecate + static EType lookup(const std::string& type_name); + static const char* lookup(EType asset_type); - // translation from a type to a human readable form. - static EType lookupHumanReadable(const char* desc_name); // safe conversion to std::string, *TODO: deprecate - static EType lookupHumanReadable(const std::string& readable_name); - static const char* lookupHumanReadable(EType asset_type); + // translation from a type to a human readable form. + static EType lookupHumanReadable(const char* desc_name); // safe conversion to std::string, *TODO: deprecate + static EType lookupHumanReadable(const std::string& readable_name); + static const char* lookupHumanReadable(EType asset_type); - static EType getType(const std::string& desc_name); - static const std::string& getDesc(EType asset_type); + static EType getType(const std::string& desc_name); + static const std::string& getDesc(EType asset_type); - static bool lookupCanLink(EType asset_type); - static bool lookupIsLinkType(EType asset_type); + static bool lookupCanLink(EType asset_type); + static bool lookupIsLinkType(EType asset_type); - static bool lookupIsAssetFetchByIDAllowed(EType asset_type); // the asset allows direct download - static bool lookupIsAssetIDKnowable(EType asset_type); // asset data can be known by the viewer + static bool lookupIsAssetFetchByIDAllowed(EType asset_type); // the asset allows direct download + static bool lookupIsAssetIDKnowable(EType asset_type); // asset data can be known by the viewer static const std::string BADLOOKUP; protected: - LLAssetType() {} - ~LLAssetType() {} + LLAssetType() {} + ~LLAssetType() {} }; #endif // LL_LLASSETTYPE_H diff --git a/indra/llcommon/llatomic.cpp b/indra/llcommon/llatomic.cpp index 93aba1f460..d200bb0406 100644 --- a/indra/llcommon/llatomic.cpp +++ b/indra/llcommon/llatomic.cpp @@ -1,24 +1,24 @@ -/** +/** * @file llatomic.cpp * * $LicenseInfo:firstyear=2018&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2018, 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$ */ diff --git a/indra/llcommon/llatomic.h b/indra/llcommon/llatomic.h index 8de773846c..c5304637cc 100644 --- a/indra/llcommon/llatomic.h +++ b/indra/llcommon/llatomic.h @@ -1,25 +1,25 @@ -/** +/** * @file llatomic.h * @brief Base classes for atomic. * * $LicenseInfo:firstyear=2018&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2018, 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$ */ @@ -40,7 +40,7 @@ public: operator const Type() { return mData; } - Type CurrentValue() const { return mData; } + Type CurrentValue() const { return mData; } Type operator =(const Type& x) { mData.store(x); return mData; } void operator -=(Type x) { mData -= x; } diff --git a/indra/llcommon/llbase32.cpp b/indra/llcommon/llbase32.cpp index 349567c90b..979114fe86 100644 --- a/indra/llcommon/llbase32.cpp +++ b/indra/llcommon/llbase32.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llbase32.cpp * @brief base32 encoding that returns a std::string * @author James Cook @@ -10,21 +10,21 @@ * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -118,9 +118,9 @@ base32_encode(char *dst, size_t size, const void *data, size_t len) | 6 | 1 0 7 6 5 | 3-4 | | 7 | 4 3 2 1 0 | 4 | +-------+-----------+--------+ - + */ - + s[0] = (x[0] >> 3); s[1] = ((x[0] & 0x07) << 2) | (x[1] >> 6); s[2] = (x[1] >> 1) & 0x1f; @@ -167,12 +167,12 @@ base32_decode(char *dst, size_t size, const void *data, size_t len) if (0 == base32_map[0]) { for (i = 0; i < LL_ARRAY_SIZE(base32_map); i++) { const char *x; - + x = memchr(base32_alphabet, ascii_toupper(i), sizeof base32_alphabet); base32_map[i] = x ? (x - base32_alphabet) : (unsigned char) -1; } } - + for (i = 0; i < len && max_pad > 0; i++) { unsigned char c; char s[8]; @@ -219,20 +219,20 @@ base32_decode(char *dst, size_t size, const void *data, size_t len) // static std::string LLBase32::encode(const U8* input, size_t input_size) { - std::string output; - if (input) - { - // Each 5 byte chunk of input is represented by an - // 8 byte chunk of output. - size_t input_chunks = (input_size + 4) / 5; - size_t output_size = input_chunks * 8; - - output.resize(output_size); - - size_t encoded = base32_encode(&output[0], output_size, input, input_size); - - LL_INFOS() << "encoded " << encoded << " into buffer of size " - << output_size << LL_ENDL; - } - return output; + std::string output; + if (input) + { + // Each 5 byte chunk of input is represented by an + // 8 byte chunk of output. + size_t input_chunks = (input_size + 4) / 5; + size_t output_size = input_chunks * 8; + + output.resize(output_size); + + size_t encoded = base32_encode(&output[0], output_size, input, input_size); + + LL_INFOS() << "encoded " << encoded << " into buffer of size " + << output_size << LL_ENDL; + } + return output; } diff --git a/indra/llcommon/llbase32.h b/indra/llcommon/llbase32.h index eeb96d789d..8cfbd7ef53 100644 --- a/indra/llcommon/llbase32.h +++ b/indra/llcommon/llbase32.h @@ -1,4 +1,4 @@ -/** +/** * @file llbase32.h * @brief base32 encoding that returns a std::string * @author James Cook @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -31,7 +31,7 @@ class LL_COMMON_API LLBase32 { public: - static std::string encode(const U8* input, size_t input_size); + static std::string encode(const U8* input, size_t input_size); }; #endif diff --git a/indra/llcommon/llbase64.cpp b/indra/llcommon/llbase64.cpp index 433b54f6f8..dbbbec9813 100644 --- a/indra/llcommon/llbase64.cpp +++ b/indra/llcommon/llbase64.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llbase64.cpp * @brief Wrapper for apr base64 encoding that returns a std::string * @author James Cook @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -37,25 +37,25 @@ // static std::string LLBase64::encode(const U8* input, size_t input_size) { - std::string output; - if (input - && input_size > 0) - { - // Yes, it returns int. - int b64_buffer_length = apr_base64_encode_len(narrow(input_size)); - char* b64_buffer = new char[b64_buffer_length]; - - // This is faster than apr_base64_encode() if you know - // you're not on an EBCDIC machine. Also, the output is - // null terminated, even though the documentation doesn't - // specify. See apr_base64.c for details. JC - b64_buffer_length = apr_base64_encode_binary( - b64_buffer, - input, - narrow(input_size)); - output.assign(b64_buffer); - delete[] b64_buffer; - } - return output; + std::string output; + if (input + && input_size > 0) + { + // Yes, it returns int. + int b64_buffer_length = apr_base64_encode_len(narrow(input_size)); + char* b64_buffer = new char[b64_buffer_length]; + + // This is faster than apr_base64_encode() if you know + // you're not on an EBCDIC machine. Also, the output is + // null terminated, even though the documentation doesn't + // specify. See apr_base64.c for details. JC + b64_buffer_length = apr_base64_encode_binary( + b64_buffer, + input, + narrow(input_size)); + output.assign(b64_buffer); + delete[] b64_buffer; + } + return output; } diff --git a/indra/llcommon/llbase64.h b/indra/llcommon/llbase64.h index 16d2c217d0..d4e9d97ea4 100644 --- a/indra/llcommon/llbase64.h +++ b/indra/llcommon/llbase64.h @@ -1,4 +1,4 @@ -/** +/** * @file llbase64.h * @brief Wrapper for apr base64 encoding that returns a std::string * @author James Cook @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -31,7 +31,7 @@ class LL_COMMON_API LLBase64 { public: - static std::string encode(const U8* input, size_t input_size); + static std::string encode(const U8* input, size_t input_size); }; #endif diff --git a/indra/llcommon/llbitpack.cpp b/indra/llcommon/llbitpack.cpp index 622a099945..011b310f40 100644 --- a/indra/llcommon/llbitpack.cpp +++ b/indra/llcommon/llbitpack.cpp @@ -1,25 +1,25 @@ -/** +/** * @file bitpack.cpp * @brief LLBitPack class implementation * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcommon/llbitpack.h b/indra/llcommon/llbitpack.h index f99a354cd4..f7eb57a4f0 100644 --- a/indra/llcommon/llbitpack.h +++ b/indra/llcommon/llbitpack.h @@ -1,25 +1,25 @@ -/** +/** * @file llbitpack.h * @brief Convert data to packed bit stream * * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -35,174 +35,174 @@ const U32 MAX_DATA_BITS = 8; class LLBitPack { public: - LLBitPack(U8 *buffer, U32 max_size) : mBuffer(buffer), mBufferSize(0), mLoad(0), mLoadSize(0), mTotalBits(0), mMaxSize(max_size) - { - } - - ~LLBitPack() - { - } - - void resetBitPacking() - { - mLoad = 0; - mLoadSize = 0; - mTotalBits = 0; - mBufferSize = 0; - } - - U32 bitPack(U8 *total_data, U32 total_dsize) - { - U32 dsize; - U8 data; - - while (total_dsize > 0) - { - if (total_dsize > MAX_DATA_BITS) - { - dsize = MAX_DATA_BITS; - total_dsize -= MAX_DATA_BITS; - } - else - { - dsize = total_dsize; - total_dsize = 0; - } - - data = *total_data++; - - data <<= (MAX_DATA_BITS - dsize); - while (dsize > 0) - { - if (mLoadSize == MAX_DATA_BITS) - { - *(mBuffer + mBufferSize++) = mLoad; - if (mBufferSize > mMaxSize) - { - LL_ERRS() << "mBufferSize exceeding mMaxSize!" << LL_ENDL; - } - mLoadSize = 0; - mLoad = 0x00; - } - mLoad <<= 1; - mLoad |= (data >> (MAX_DATA_BITS - 1)); - data <<= 1; - mLoadSize++; - mTotalBits++; - dsize--; - } - } - return mBufferSize; - } - - U32 bitCopy(U8 *total_data, U32 total_dsize) - { - U32 dsize; - U8 data; - - while (total_dsize > 0) - { - if (total_dsize > MAX_DATA_BITS) - { - dsize = MAX_DATA_BITS; - total_dsize -= MAX_DATA_BITS; - } - else - { - dsize = total_dsize; - total_dsize = 0; - } - - data = *total_data++; - - while (dsize > 0) - { - if (mLoadSize == MAX_DATA_BITS) - { - *(mBuffer + mBufferSize++) = mLoad; - if (mBufferSize > mMaxSize) - { - LL_ERRS() << "mBufferSize exceeding mMaxSize!" << LL_ENDL; - } - mLoadSize = 0; - mLoad = 0x00; - } - mLoad <<= 1; - mLoad |= (data >> (MAX_DATA_BITS - 1)); - data <<= 1; - mLoadSize++; - mTotalBits++; - dsize--; - } - } - return mBufferSize; - } - - U32 bitUnpack(U8 *total_retval, U32 total_dsize) - { - U32 dsize; - U8 *retval; - - while (total_dsize > 0) - { - if (total_dsize > MAX_DATA_BITS) - { - dsize = MAX_DATA_BITS; - total_dsize -= MAX_DATA_BITS; - } - else - { - dsize = total_dsize; - total_dsize = 0; - } - - retval = total_retval++; - *retval = 0x00; - while (dsize > 0) - { - if (mLoadSize == 0) - { + LLBitPack(U8 *buffer, U32 max_size) : mBuffer(buffer), mBufferSize(0), mLoad(0), mLoadSize(0), mTotalBits(0), mMaxSize(max_size) + { + } + + ~LLBitPack() + { + } + + void resetBitPacking() + { + mLoad = 0; + mLoadSize = 0; + mTotalBits = 0; + mBufferSize = 0; + } + + U32 bitPack(U8 *total_data, U32 total_dsize) + { + U32 dsize; + U8 data; + + while (total_dsize > 0) + { + if (total_dsize > MAX_DATA_BITS) + { + dsize = MAX_DATA_BITS; + total_dsize -= MAX_DATA_BITS; + } + else + { + dsize = total_dsize; + total_dsize = 0; + } + + data = *total_data++; + + data <<= (MAX_DATA_BITS - dsize); + while (dsize > 0) + { + if (mLoadSize == MAX_DATA_BITS) + { + *(mBuffer + mBufferSize++) = mLoad; + if (mBufferSize > mMaxSize) + { + LL_ERRS() << "mBufferSize exceeding mMaxSize!" << LL_ENDL; + } + mLoadSize = 0; + mLoad = 0x00; + } + mLoad <<= 1; + mLoad |= (data >> (MAX_DATA_BITS - 1)); + data <<= 1; + mLoadSize++; + mTotalBits++; + dsize--; + } + } + return mBufferSize; + } + + U32 bitCopy(U8 *total_data, U32 total_dsize) + { + U32 dsize; + U8 data; + + while (total_dsize > 0) + { + if (total_dsize > MAX_DATA_BITS) + { + dsize = MAX_DATA_BITS; + total_dsize -= MAX_DATA_BITS; + } + else + { + dsize = total_dsize; + total_dsize = 0; + } + + data = *total_data++; + + while (dsize > 0) + { + if (mLoadSize == MAX_DATA_BITS) + { + *(mBuffer + mBufferSize++) = mLoad; + if (mBufferSize > mMaxSize) + { + LL_ERRS() << "mBufferSize exceeding mMaxSize!" << LL_ENDL; + } + mLoadSize = 0; + mLoad = 0x00; + } + mLoad <<= 1; + mLoad |= (data >> (MAX_DATA_BITS - 1)); + data <<= 1; + mLoadSize++; + mTotalBits++; + dsize--; + } + } + return mBufferSize; + } + + U32 bitUnpack(U8 *total_retval, U32 total_dsize) + { + U32 dsize; + U8 *retval; + + while (total_dsize > 0) + { + if (total_dsize > MAX_DATA_BITS) + { + dsize = MAX_DATA_BITS; + total_dsize -= MAX_DATA_BITS; + } + else + { + dsize = total_dsize; + total_dsize = 0; + } + + retval = total_retval++; + *retval = 0x00; + while (dsize > 0) + { + if (mLoadSize == 0) + { #ifdef _DEBUG - if (mBufferSize > mMaxSize) - { - LL_ERRS() << "mBufferSize exceeding mMaxSize" << LL_ENDL; - LL_ERRS() << mBufferSize << " > " << mMaxSize << LL_ENDL; - } + if (mBufferSize > mMaxSize) + { + LL_ERRS() << "mBufferSize exceeding mMaxSize" << LL_ENDL; + LL_ERRS() << mBufferSize << " > " << mMaxSize << LL_ENDL; + } #endif - mLoad = *(mBuffer + mBufferSize++); - mLoadSize = MAX_DATA_BITS; - } - *retval <<= 1; - *retval |= (mLoad >> (MAX_DATA_BITS - 1)); - mLoadSize--; - mLoad <<= 1; - dsize--; - } - } - return mBufferSize; - } - - U32 flushBitPack() - { - if (mLoadSize) - { - mLoad <<= (MAX_DATA_BITS - mLoadSize); - *(mBuffer + mBufferSize++) = mLoad; - if (mBufferSize > mMaxSize) - { - LL_ERRS() << "mBufferSize exceeding mMaxSize!" << LL_ENDL; - } - mLoadSize = 0; - } - return mBufferSize; - } - - U8 *mBuffer; - U32 mBufferSize; - U8 mLoad; - U32 mLoadSize; - U32 mTotalBits; - U32 mMaxSize; + mLoad = *(mBuffer + mBufferSize++); + mLoadSize = MAX_DATA_BITS; + } + *retval <<= 1; + *retval |= (mLoad >> (MAX_DATA_BITS - 1)); + mLoadSize--; + mLoad <<= 1; + dsize--; + } + } + return mBufferSize; + } + + U32 flushBitPack() + { + if (mLoadSize) + { + mLoad <<= (MAX_DATA_BITS - mLoadSize); + *(mBuffer + mBufferSize++) = mLoad; + if (mBufferSize > mMaxSize) + { + LL_ERRS() << "mBufferSize exceeding mMaxSize!" << LL_ENDL; + } + mLoadSize = 0; + } + return mBufferSize; + } + + U8 *mBuffer; + U32 mBufferSize; + U8 mLoad; + U32 mLoadSize; + U32 mTotalBits; + U32 mMaxSize; }; #endif diff --git a/indra/llcommon/llboost.h b/indra/llcommon/llboost.h index 57d958a51a..980fc9e1c4 100644 --- a/indra/llcommon/llboost.h +++ b/indra/llcommon/llboost.h @@ -1,25 +1,25 @@ -/** +/** * @file llboost.h * @brief helper object & functions for use with boost * * $LicenseInfo:firstyear=2005&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -31,12 +31,12 @@ // boost_tokenizer typedef /* example usage: - boost_tokenizer tokens(input_string, boost::char_separator(" \t\n")); - for (boost_tokenizer::iterator token_iter = tokens.begin(); token_iter != tokens.end(); ++token_iter) - { - std::string tok = *token_iter; - process_token_string( tok ); - } + boost_tokenizer tokens(input_string, boost::char_separator(" \t\n")); + for (boost_tokenizer::iterator token_iter = tokens.begin(); token_iter != tokens.end(); ++token_iter) + { + std::string tok = *token_iter; + process_token_string( tok ); + } */ typedef boost::tokenizer > boost_tokenizer; @@ -44,15 +44,15 @@ typedef boost::tokenizer > boost_tokenizer; // returns false if any of the callbacks return false struct boost_boolean_combiner { - typedef bool result_type; - template - bool operator()(InputIterator first, InputIterator last) const - { - bool res = true; - while (first != last) - res &= *first++; - return res; - } + typedef bool result_type; + template + bool operator()(InputIterator first, InputIterator last) const + { + bool res = true; + while (first != last) + res &= *first++; + return res; + } }; #endif // LL_LLBOOST_H diff --git a/indra/llcommon/llcallbacklist.cpp b/indra/llcommon/llcallbacklist.cpp index 9f23ce5317..b5a58e90b3 100644 --- a/indra/llcommon/llcallbacklist.cpp +++ b/indra/llcommon/llcallbacklist.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llcallbacklist.cpp * @brief A simple list of callback functions to call. * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -38,7 +38,7 @@ LLCallbackList gIdleCallbacks; LLCallbackList::LLCallbackList() { - // nothing + // nothing } LLCallbackList::~LLCallbackList() @@ -48,72 +48,72 @@ LLCallbackList::~LLCallbackList() void LLCallbackList::addFunction( callback_t func, void *data) { - if (!func) - { - return; - } - - // only add one callback per func/data pair - // - if (containsFunction(func, data)) - { - return; - } - - callback_pair_t t(func, data); - mCallbackList.push_back(t); + if (!func) + { + return; + } + + // only add one callback per func/data pair + // + if (containsFunction(func, data)) + { + return; + } + + callback_pair_t t(func, data); + mCallbackList.push_back(t); } bool LLCallbackList::containsFunction( callback_t func, void *data) { - callback_pair_t t(func, data); - callback_list_t::iterator iter = find(func,data); - if (iter != mCallbackList.end()) - { - return TRUE; - } - else - { - return FALSE; - } + callback_pair_t t(func, data); + callback_list_t::iterator iter = find(func,data); + if (iter != mCallbackList.end()) + { + return TRUE; + } + else + { + return FALSE; + } } bool LLCallbackList::deleteFunction( callback_t func, void *data) { - callback_list_t::iterator iter = find(func,data); - if (iter != mCallbackList.end()) - { - mCallbackList.erase(iter); - return TRUE; - } - else - { - return FALSE; - } + callback_list_t::iterator iter = find(func,data); + if (iter != mCallbackList.end()) + { + mCallbackList.erase(iter); + return TRUE; + } + else + { + return FALSE; + } } -inline +inline LLCallbackList::callback_list_t::iterator LLCallbackList::find(callback_t func, void *data) { - callback_pair_t t(func, data); - return std::find(mCallbackList.begin(), mCallbackList.end(), t); + callback_pair_t t(func, data); + return std::find(mCallbackList.begin(), mCallbackList.end(), t); } void LLCallbackList::deleteAllFunctions() { - mCallbackList.clear(); + mCallbackList.clear(); } void LLCallbackList::callFunctions() { - for (callback_list_t::iterator iter = mCallbackList.begin(); iter != mCallbackList.end(); ) - { - callback_list_t::iterator curiter = iter++; - curiter->first(curiter->second); - } + for (callback_list_t::iterator iter = mCallbackList.begin(); iter != mCallbackList.end(); ) + { + callback_list_t::iterator curiter = iter++; + curiter->first(curiter->second); + } } // Shim class to allow arbitrary boost::bind @@ -121,29 +121,29 @@ void LLCallbackList::callFunctions() class OnIdleCallbackOneTime { public: - OnIdleCallbackOneTime(nullary_func_t callable): - mCallable(callable) - { - } - static void onIdle(void *data) - { - gIdleCallbacks.deleteFunction(onIdle, data); - OnIdleCallbackOneTime* self = reinterpret_cast(data); - self->call(); - delete self; - } - void call() - { - mCallable(); - } + OnIdleCallbackOneTime(nullary_func_t callable): + mCallable(callable) + { + } + static void onIdle(void *data) + { + gIdleCallbacks.deleteFunction(onIdle, data); + OnIdleCallbackOneTime* self = reinterpret_cast(data); + self->call(); + delete self; + } + void call() + { + mCallable(); + } private: - nullary_func_t mCallable; + nullary_func_t mCallable; }; void doOnIdleOneTime(nullary_func_t callable) { - OnIdleCallbackOneTime* cb_functor = new OnIdleCallbackOneTime(callable); - gIdleCallbacks.addFunction(&OnIdleCallbackOneTime::onIdle,cb_functor); + OnIdleCallbackOneTime* cb_functor = new OnIdleCallbackOneTime(callable); + gIdleCallbacks.addFunction(&OnIdleCallbackOneTime::onIdle,cb_functor); } // Shim class to allow generic boost functions to be run as @@ -152,79 +152,79 @@ void doOnIdleOneTime(nullary_func_t callable) class OnIdleCallbackRepeating { public: - OnIdleCallbackRepeating(bool_func_t callable): - mCallable(callable) - { - } - // Will keep getting called until the callable returns true. - static void onIdle(void *data) - { - OnIdleCallbackRepeating* self = reinterpret_cast(data); - bool done = self->call(); - if (done) - { - gIdleCallbacks.deleteFunction(onIdle, data); - delete self; - } - } - bool call() - { - return mCallable(); - } + OnIdleCallbackRepeating(bool_func_t callable): + mCallable(callable) + { + } + // Will keep getting called until the callable returns true. + static void onIdle(void *data) + { + OnIdleCallbackRepeating* self = reinterpret_cast(data); + bool done = self->call(); + if (done) + { + gIdleCallbacks.deleteFunction(onIdle, data); + delete self; + } + } + bool call() + { + return mCallable(); + } private: - bool_func_t mCallable; + bool_func_t mCallable; }; void doOnIdleRepeating(bool_func_t callable) { - OnIdleCallbackRepeating* cb_functor = new OnIdleCallbackRepeating(callable); - gIdleCallbacks.addFunction(&OnIdleCallbackRepeating::onIdle,cb_functor); + OnIdleCallbackRepeating* cb_functor = new OnIdleCallbackRepeating(callable); + gIdleCallbacks.addFunction(&OnIdleCallbackRepeating::onIdle,cb_functor); } class NullaryFuncEventTimer: public LLEventTimer { public: - NullaryFuncEventTimer(nullary_func_t callable, F32 seconds): - LLEventTimer(seconds), - mCallable(callable) - { - } + NullaryFuncEventTimer(nullary_func_t callable, F32 seconds): + LLEventTimer(seconds), + mCallable(callable) + { + } private: - BOOL tick() - { - mCallable(); - return TRUE; - } + BOOL tick() + { + mCallable(); + return TRUE; + } - nullary_func_t mCallable; + nullary_func_t mCallable; }; // Call a given callable once after specified interval. void doAfterInterval(nullary_func_t callable, F32 seconds) { - new NullaryFuncEventTimer(callable, seconds); + new NullaryFuncEventTimer(callable, seconds); } class BoolFuncEventTimer: public LLEventTimer { public: - BoolFuncEventTimer(bool_func_t callable, F32 seconds): - LLEventTimer(seconds), - mCallable(callable) - { - } + BoolFuncEventTimer(bool_func_t callable, F32 seconds): + LLEventTimer(seconds), + mCallable(callable) + { + } private: - BOOL tick() - { - return mCallable(); - } + BOOL tick() + { + return mCallable(); + } - bool_func_t mCallable; + bool_func_t mCallable; }; // Call a given callable every specified number of seconds, until it returns true. void doPeriodically(bool_func_t callable, F32 seconds) { - new BoolFuncEventTimer(callable, seconds); + new BoolFuncEventTimer(callable, seconds); } diff --git a/indra/llcommon/llcallbacklist.h b/indra/llcommon/llcallbacklist.h index 89716cd74c..d6c415f7c5 100644 --- a/indra/llcommon/llcallbacklist.h +++ b/indra/llcommon/llcallbacklist.h @@ -1,25 +1,25 @@ -/** +/** * @file llcallbacklist.h * @brief A simple list of callback functions to call. * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -34,29 +34,29 @@ class LLCallbackList { public: - typedef void (*callback_t)(void*); + typedef void (*callback_t)(void*); + + typedef std::pair< callback_t,void* > callback_pair_t; + // NOTE: It is confirmed that we DEPEND on the order provided by using a list :( + // + typedef std::list< callback_pair_t > callback_list_t; - typedef std::pair< callback_t,void* > callback_pair_t; - // NOTE: It is confirmed that we DEPEND on the order provided by using a list :( - // - typedef std::list< callback_pair_t > callback_list_t; - - LLCallbackList(); - ~LLCallbackList(); + LLCallbackList(); + ~LLCallbackList(); - void addFunction( callback_t func, void *data = NULL ); // register a callback, which will be called as func(data) - bool containsFunction( callback_t func, void *data = NULL ); // true if list already contains the function/data pair - bool deleteFunction( callback_t func, void *data = NULL ); // removes the first instance of this function/data pair from the list, false if not found - void callFunctions(); // calls all functions - void deleteAllFunctions(); + void addFunction( callback_t func, void *data = NULL ); // register a callback, which will be called as func(data) + bool containsFunction( callback_t func, void *data = NULL ); // true if list already contains the function/data pair + bool deleteFunction( callback_t func, void *data = NULL ); // removes the first instance of this function/data pair from the list, false if not found + void callFunctions(); // calls all functions + void deleteAllFunctions(); - static void test(); + static void test(); protected: - inline callback_list_t::iterator find(callback_t func, void *data); + inline callback_list_t::iterator find(callback_t func, void *data); - callback_list_t mCallbackList; + callback_list_t mCallbackList; }; typedef boost::function nullary_func_t; diff --git a/indra/llcommon/llcallstack.cpp b/indra/llcommon/llcallstack.cpp index 83d5ae2a63..c0be4f598e 100644 --- a/indra/llcommon/llcallstack.cpp +++ b/indra/llcommon/llcallstack.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llcallstack.cpp * @brief run-time extraction of the current callstack * * $LicenseInfo:firstyear=2016&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2016, 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$ */ @@ -91,7 +91,7 @@ LLCallStack::LLCallStack(S32 skip_count, bool verbose): bool LLCallStack::contains(const std::string& str) { - for (const std::string& src_str : m_strings) + for (const std::string& src_str : m_strings) { if (src_str.find(str) != std::string::npos) { @@ -104,7 +104,7 @@ bool LLCallStack::contains(const std::string& str) std::ostream& operator<<(std::ostream& s, const LLCallStack& call_stack) { #ifndef LL_RELEASE_FOR_DOWNLOAD - for (const std::string& str : call_stack.m_strings) + for (const std::string& str : call_stack.m_strings) { s << str; } @@ -121,27 +121,27 @@ LLContextStrings::LLContextStrings() // static LLContextStrings* LLContextStrings::getThreadLocalInstance() { - LLContextStrings *cons = LLThreadLocalSingletonPointer::getInstance(); + LLContextStrings *cons = LLThreadLocalSingletonPointer::getInstance(); if (!cons) { LLThreadLocalSingletonPointer::setInstance(new LLContextStrings); } - return LLThreadLocalSingletonPointer::getInstance(); + return LLThreadLocalSingletonPointer::getInstance(); } // static void LLContextStrings::addContextString(const std::string& str) { - LLContextStrings *cons = getThreadLocalInstance(); + LLContextStrings *cons = getThreadLocalInstance(); //LL_INFOS() << "CTX " << (S32)cons << " ADD " << str << " CNT " << cons->m_contextStrings[str] << LL_ENDL; - cons->m_contextStrings[str]++; + cons->m_contextStrings[str]++; } // static void LLContextStrings::removeContextString(const std::string& str) { - LLContextStrings *cons = getThreadLocalInstance(); - cons->m_contextStrings[str]--; + LLContextStrings *cons = getThreadLocalInstance(); + cons->m_contextStrings[str]--; //LL_INFOS() << "CTX " << (S32)cons << " REMOVE " << str << " CNT " << cons->m_contextStrings[str] << LL_ENDL; if (cons->m_contextStrings[str] == 0) { @@ -175,7 +175,7 @@ void LLContextStrings::output(std::ostream& os) } } -// static +// static std::ostream& operator<<(std::ostream& s, const LLContextStatus& context_status) { LLThreadLocalSingletonPointer::getInstance()->output(s); diff --git a/indra/llcommon/llcallstack.h b/indra/llcommon/llcallstack.h index d5a2b7b157..ad10a9dbf7 100644 --- a/indra/llcommon/llcallstack.h +++ b/indra/llcommon/llcallstack.h @@ -1,25 +1,25 @@ -/** +/** * @file llcallstack.h * @brief run-time extraction of the current callstack * * $LicenseInfo:firstyear=2016&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2016, 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$ */ diff --git a/indra/llcommon/llcleanup.cpp b/indra/llcommon/llcleanup.cpp index 1f34c2036a..38b2ccbeff 100644 --- a/indra/llcommon/llcleanup.cpp +++ b/indra/llcommon/llcleanup.cpp @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2016-08-30 * @brief Implementation for llcleanup. - * + * * $LicenseInfo:firstyear=2016&license=viewerlgpl$ * Copyright (c) 2016, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/llcleanup.h b/indra/llcommon/llcleanup.h index 0f567ed5f6..b120a5c4fe 100644 --- a/indra/llcommon/llcleanup.h +++ b/indra/llcommon/llcleanup.h @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2015-05-20 * @brief Mechanism for cleaning up subsystem resources - * + * * $LicenseInfo:firstyear=2015&license=viewerlgpl$ * Copyright (c) 2015, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/llclickaction.h b/indra/llcommon/llclickaction.h index 2f83113af9..daa4e88f80 100644 --- a/indra/llcommon/llclickaction.h +++ b/indra/llcommon/llclickaction.h @@ -1,4 +1,4 @@ -/** +/** * @file llclickaction.h * @author James Cook * @brief Constants for single-click actions on objects @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcommon/llcommon.cpp b/indra/llcommon/llcommon.cpp index 6e988260a9..14bdeb5c60 100644 --- a/indra/llcommon/llcommon.cpp +++ b/indra/llcommon/llcommon.cpp @@ -1,24 +1,24 @@ -/** +/** * @file llcommon.cpp * * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -122,32 +122,32 @@ static LLTrace::ThreadRecorder* sMasterThreadRecorder = NULL; //static void LLCommon::initClass() { - if (!sAprInitialized) - { - ll_init_apr(); - sAprInitialized = TRUE; - } - LLTimer::initClass(); - LLThreadSafeRefCount::initThreadSafeRefCount(); - assert_main_thread(); // Make sure we record the main thread - if (!sMasterThreadRecorder) - { - sMasterThreadRecorder = new LLTrace::ThreadRecorder(); - LLTrace::set_master_thread_recorder(sMasterThreadRecorder); - } + if (!sAprInitialized) + { + ll_init_apr(); + sAprInitialized = TRUE; + } + LLTimer::initClass(); + LLThreadSafeRefCount::initThreadSafeRefCount(); + assert_main_thread(); // Make sure we record the main thread + if (!sMasterThreadRecorder) + { + sMasterThreadRecorder = new LLTrace::ThreadRecorder(); + LLTrace::set_master_thread_recorder(sMasterThreadRecorder); + } } //static void LLCommon::cleanupClass() { - delete sMasterThreadRecorder; - sMasterThreadRecorder = NULL; - LLTrace::set_master_thread_recorder(NULL); - LLThreadSafeRefCount::cleanupThreadSafeRefCount(); - SUBSYSTEM_CLEANUP_DBG(LLTimer); - if (sAprInitialized) - { - ll_cleanup_apr(); - sAprInitialized = FALSE; - } + delete sMasterThreadRecorder; + sMasterThreadRecorder = NULL; + LLTrace::set_master_thread_recorder(NULL); + LLThreadSafeRefCount::cleanupThreadSafeRefCount(); + SUBSYSTEM_CLEANUP_DBG(LLTimer); + if (sAprInitialized) + { + ll_cleanup_apr(); + sAprInitialized = FALSE; + } } diff --git a/indra/llcommon/llcommon.h b/indra/llcommon/llcommon.h index ca9cad5d05..129e71f703 100644 --- a/indra/llcommon/llcommon.h +++ b/indra/llcommon/llcommon.h @@ -1,24 +1,24 @@ -/** +/** * @file llcommon.h * * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -33,10 +33,10 @@ class LL_COMMON_API LLCommon { public: - static void initClass(); - static void cleanupClass(); + static void initClass(); + static void cleanupClass(); private: - static BOOL sAprInitialized; + static BOOL sAprInitialized; }; #endif diff --git a/indra/llcommon/llcommonutils.cpp b/indra/llcommon/llcommonutils.cpp index d82554c202..a38879c89f 100644 --- a/indra/llcommon/llcommonutils.cpp +++ b/indra/llcommon/llcommonutils.cpp @@ -5,21 +5,21 @@ * $LicenseInfo:firstyear=2010&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -28,29 +28,29 @@ #include "llcommonutils.h" void LLCommonUtils::computeDifference( - const uuid_vec_t& vnew, - const uuid_vec_t& vcur, - uuid_vec_t& vadded, - uuid_vec_t& vremoved) + const uuid_vec_t& vnew, + const uuid_vec_t& vcur, + uuid_vec_t& vadded, + uuid_vec_t& vremoved) { - uuid_vec_t vnew_copy(vnew); - uuid_vec_t vcur_copy(vcur); + uuid_vec_t vnew_copy(vnew); + uuid_vec_t vcur_copy(vcur); - std::sort(vnew_copy.begin(), vnew_copy.end()); - std::sort(vcur_copy.begin(), vcur_copy.end()); + std::sort(vnew_copy.begin(), vnew_copy.end()); + std::sort(vcur_copy.begin(), vcur_copy.end()); - size_t maxsize = llmax(vnew_copy.size(), vcur_copy.size()); - vadded.resize(maxsize); - vremoved.resize(maxsize); + size_t maxsize = llmax(vnew_copy.size(), vcur_copy.size()); + vadded.resize(maxsize); + vremoved.resize(maxsize); - uuid_vec_t::iterator it; - // what was removed - it = set_difference(vcur_copy.begin(), vcur_copy.end(), vnew_copy.begin(), vnew_copy.end(), vremoved.begin()); - vremoved.erase(it, vremoved.end()); + uuid_vec_t::iterator it; + // what was removed + it = set_difference(vcur_copy.begin(), vcur_copy.end(), vnew_copy.begin(), vnew_copy.end(), vremoved.begin()); + vremoved.erase(it, vremoved.end()); - // what was added - it = set_difference(vnew_copy.begin(), vnew_copy.end(), vcur_copy.begin(), vcur_copy.end(), vadded.begin()); - vadded.erase(it, vadded.end()); + // what was added + it = set_difference(vnew_copy.begin(), vnew_copy.end(), vcur_copy.begin(), vcur_copy.end(), vadded.begin()); + vadded.erase(it, vadded.end()); } // EOF diff --git a/indra/llcommon/llcommonutils.h b/indra/llcommon/llcommonutils.h index 20ada27830..5f6fd41aa3 100644 --- a/indra/llcommon/llcommonutils.h +++ b/indra/llcommon/llcommonutils.h @@ -5,21 +5,21 @@ * $LicenseInfo:firstyear=2010&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -31,21 +31,21 @@ namespace LLCommonUtils { - /** - * Computes difference between 'vnew' and 'vcur' vectors. - * Items present in 'vnew' and missing in 'vcur' are treated as added and are copied into 'vadded' - * Items missing in 'vnew' and present in 'vcur' are treated as removed and are copied into 'vremoved' - * - * @param vnew[in] - incoming IDs - * @param vcur[in] - current IDs - * @param vadded[out] - difference between incoming and current IDS - added IDs - * @param vremoved[out] - difference between incoming and current IDS - removed IDs - */ - LL_COMMON_API void computeDifference( - const uuid_vec_t& vnew, - const uuid_vec_t& vcur, - uuid_vec_t& vadded, - uuid_vec_t& vremoved); + /** + * Computes difference between 'vnew' and 'vcur' vectors. + * Items present in 'vnew' and missing in 'vcur' are treated as added and are copied into 'vadded' + * Items missing in 'vnew' and present in 'vcur' are treated as removed and are copied into 'vremoved' + * + * @param vnew[in] - incoming IDs + * @param vcur[in] - current IDs + * @param vadded[out] - difference between incoming and current IDS - added IDs + * @param vremoved[out] - difference between incoming and current IDS - removed IDs + */ + LL_COMMON_API void computeDifference( + const uuid_vec_t& vnew, + const uuid_vec_t& vcur, + uuid_vec_t& vadded, + uuid_vec_t& vremoved); }; #endif //LL_LLCOMMONUTILS_H diff --git a/indra/llcommon/llcond.h b/indra/llcommon/llcond.h index da6e6affe1..2df1719941 100644 --- a/indra/llcommon/llcond.h +++ b/indra/llcommon/llcond.h @@ -5,7 +5,7 @@ * @brief LLCond is a wrapper around condition_variable to encapsulate the * obligatory condition_variable usage pattern. We also provide * simplified versions LLScalarCond, LLBoolCond and LLOneShotCond. - * + * * $LicenseInfo:firstyear=2019&license=viewerlgpl$ * Copyright (c) 2019, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/llcoros.cpp b/indra/llcommon/llcoros.cpp index c13900f74a..20340397db 100644 --- a/indra/llcommon/llcoros.cpp +++ b/indra/llcommon/llcoros.cpp @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2009-06-03 * @brief Implementation for llcoros. - * + * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcommon/llcoros.h b/indra/llcommon/llcoros.h index fd878f20ad..71c1c1c443 100644 --- a/indra/llcommon/llcoros.h +++ b/indra/llcommon/llcoros.h @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2009-06-02 * @brief Manage running boost::coroutine instances - * + * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -158,7 +158,7 @@ public: * LLCoros::launch()). */ static std::string getName(); - + /** * rethrow() is called by the thread's main fiber to propagate an * exception from any coroutine into the main fiber, where it can engage diff --git a/indra/llcommon/llcrc.cpp b/indra/llcommon/llcrc.cpp index 626bb1e564..34aa7b46e8 100644 --- a/indra/llcommon/llcrc.cpp +++ b/indra/llcommon/llcrc.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llcrc.cpp * @brief implementation of the crc class. * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -142,77 +142,77 @@ LLCRC::LLCRC() : mCurrent(0xffffffff) U32 LLCRC::getCRC() const { - return ~mCurrent; + return ~mCurrent; } void LLCRC::update(U8 next_byte) { - mCurrent = UPDC32(next_byte, mCurrent); + mCurrent = UPDC32(next_byte, mCurrent); } void LLCRC::update(const U8* buffer, size_t buffer_size) { - for (size_t i = 0; i < buffer_size; i++) - { - mCurrent = UPDC32(buffer[i], mCurrent); - } + for (size_t i = 0; i < buffer_size; i++) + { + mCurrent = UPDC32(buffer[i], mCurrent); + } } void LLCRC::update(const std::string& filename) { - if (filename.empty()) - { - LL_ERRS() << "No filename specified" << LL_ENDL; - return; - } - - FILE* fp = LLFile::fopen(filename, "rb"); /* Flawfinder: ignore */ - - if (fp) - { - fseek(fp, 0, SEEK_END); - long size = ftell(fp); - - fseek(fp, 0, SEEK_SET); - - if (size > 0) - { - U8* data = new U8[size]; - size_t nread; - - nread = fread(data, 1, size, fp); - fclose(fp); - - if (nread < (size_t) size) - { - LL_WARNS() << "Short read on " << filename << LL_ENDL; - } - - update(data, nread); - delete[] data; - } - else - { - fclose(fp); - } - } + if (filename.empty()) + { + LL_ERRS() << "No filename specified" << LL_ENDL; + return; + } + + FILE* fp = LLFile::fopen(filename, "rb"); /* Flawfinder: ignore */ + + if (fp) + { + fseek(fp, 0, SEEK_END); + long size = ftell(fp); + + fseek(fp, 0, SEEK_SET); + + if (size > 0) + { + U8* data = new U8[size]; + size_t nread; + + nread = fread(data, 1, size, fp); + fclose(fp); + + if (nread < (size_t) size) + { + LL_WARNS() << "Short read on " << filename << LL_ENDL; + } + + update(data, nread); + delete[] data; + } + else + { + fclose(fp); + } + } } #ifdef _DEBUG BOOL LLCRC::testHarness() { - const S32 TEST_BUFFER_SIZE = 16; - const char TEST_BUFFER[TEST_BUFFER_SIZE] = "hello &#$)$&Nd0"; /* Flawfinder: ignore */ - LLCRC c1, c2; - c1.update((U8*)TEST_BUFFER, TEST_BUFFER_SIZE - 1); - char* rh = (char*)TEST_BUFFER; - while(*rh != '\0') - { - c2.update(*rh); - ++rh; - } - return(c1.getCRC() == c2.getCRC()); + const S32 TEST_BUFFER_SIZE = 16; + const char TEST_BUFFER[TEST_BUFFER_SIZE] = "hello &#$)$&Nd0"; /* Flawfinder: ignore */ + LLCRC c1, c2; + c1.update((U8*)TEST_BUFFER, TEST_BUFFER_SIZE - 1); + char* rh = (char*)TEST_BUFFER; + while(*rh != '\0') + { + c2.update(*rh); + ++rh; + } + return(c1.getCRC() == c2.getCRC()); } #endif diff --git a/indra/llcommon/llcrc.h b/indra/llcommon/llcrc.h index 3f41b28ffa..3b48b778ff 100644 --- a/indra/llcommon/llcrc.h +++ b/indra/llcommon/llcrc.h @@ -1,25 +1,25 @@ -/** +/** * @file llcrc.h * @brief LLCRC class header file. * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -47,20 +47,20 @@ class LL_COMMON_API LLCRC { protected: - U32 mCurrent; - + U32 mCurrent; + public: - LLCRC(); + LLCRC(); - U32 getCRC() const; - void update(U8 next_byte); - void update(const U8* buffer, size_t buffer_size); - void update(const std::string& filename); + U32 getCRC() const; + void update(U8 next_byte); + void update(const U8* buffer, size_t buffer_size); + void update(const std::string& filename); #ifdef _DEBUG - // This function runs tests to make sure the crc is - // working. Returns TRUE if it is. - static BOOL testHarness(); + // This function runs tests to make sure the crc is + // working. Returns TRUE if it is. + static BOOL testHarness(); #endif }; diff --git a/indra/llcommon/llcriticaldamp.cpp b/indra/llcommon/llcriticaldamp.cpp index 54be855f67..bb5f2b647a 100644 --- a/indra/llcommon/llcriticaldamp.cpp +++ b/indra/llcommon/llcriticaldamp.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llcriticaldamp.cpp * @brief Implementation of the critical damping functionality. * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -39,20 +39,20 @@ F32 LLSmoothInterpolation::sTimeDelta; // helper functors struct LLSmoothInterpolation::CompareTimeConstants { - bool operator()(const F32& a, const LLSmoothInterpolation::Interpolant& b) const - { - return a < b.mTimeScale; - } + bool operator()(const F32& a, const LLSmoothInterpolation::Interpolant& b) const + { + return a < b.mTimeScale; + } - bool operator()(const LLSmoothInterpolation::Interpolant& a, const F32& b) const - { - return a.mTimeScale < b; // bottom of a is higher than bottom of b - } + bool operator()(const LLSmoothInterpolation::Interpolant& a, const F32& b) const + { + return a.mTimeScale < b; // bottom of a is higher than bottom of b + } - bool operator()(const LLSmoothInterpolation::Interpolant& a, const LLSmoothInterpolation::Interpolant& b) const - { - return a.mTimeScale < b.mTimeScale; // bottom of a is higher than bottom of b - } + bool operator()(const LLSmoothInterpolation::Interpolant& a, const LLSmoothInterpolation::Interpolant& b) const + { + return a.mTimeScale < b.mTimeScale; // bottom of a is higher than bottom of b + } }; //----------------------------------------------------------------------------- @@ -60,7 +60,7 @@ struct LLSmoothInterpolation::CompareTimeConstants //----------------------------------------------------------------------------- LLSmoothInterpolation::LLSmoothInterpolation() { - sTimeDelta = 0.f; + sTimeDelta = 0.f; } // static @@ -69,46 +69,46 @@ LLSmoothInterpolation::LLSmoothInterpolation() //----------------------------------------------------------------------------- void LLSmoothInterpolation::updateInterpolants() { - sTimeDelta = sInternalTimer.getElapsedTimeAndResetF32(); + sTimeDelta = sInternalTimer.getElapsedTimeAndResetF32(); - for (S32 i = 0; i < sInterpolants.size(); i++) - { - Interpolant& interp = sInterpolants[i]; - interp.mInterpolant = calcInterpolant(interp.mTimeScale); - } -} + for (S32 i = 0; i < sInterpolants.size(); i++) + { + Interpolant& interp = sInterpolants[i]; + interp.mInterpolant = calcInterpolant(interp.mTimeScale); + } +} //----------------------------------------------------------------------------- // getInterpolant() //----------------------------------------------------------------------------- F32 LLSmoothInterpolation::getInterpolant(F32SecondsImplicit time_constant, bool use_cache) { - if (time_constant == 0.f) - { - return 1.f; - } + if (time_constant == 0.f) + { + return 1.f; + } - if (use_cache) - { - interpolant_vec_t::iterator find_it = std::lower_bound(sInterpolants.begin(), sInterpolants.end(), time_constant.value(), CompareTimeConstants()); - if (find_it != sInterpolants.end() && find_it->mTimeScale == time_constant) - { - return find_it->mInterpolant; - } - else - { - Interpolant interp; - interp.mTimeScale = time_constant.value(); - interp.mInterpolant = calcInterpolant(time_constant.value()); - sInterpolants.insert(find_it, interp); - return interp.mInterpolant; - } - } - else - { - return calcInterpolant(time_constant.value()); + if (use_cache) + { + interpolant_vec_t::iterator find_it = std::lower_bound(sInterpolants.begin(), sInterpolants.end(), time_constant.value(), CompareTimeConstants()); + if (find_it != sInterpolants.end() && find_it->mTimeScale == time_constant) + { + return find_it->mInterpolant; + } + else + { + Interpolant interp; + interp.mTimeScale = time_constant.value(); + interp.mInterpolant = calcInterpolant(time_constant.value()); + sInterpolants.insert(find_it, interp); + return interp.mInterpolant; + } + } + else + { + return calcInterpolant(time_constant.value()); - } + } } //----------------------------------------------------------------------------- @@ -116,6 +116,6 @@ F32 LLSmoothInterpolation::getInterpolant(F32SecondsImplicit time_constant, bool //----------------------------------------------------------------------------- F32 LLSmoothInterpolation::calcInterpolant(F32 time_constant) { - return llclamp(1.f - powf(2.f, -sTimeDelta / time_constant), 0.f, 1.f); + return llclamp(1.f - powf(2.f, -sTimeDelta / time_constant), 0.f, 1.f); } diff --git a/indra/llcommon/llcriticaldamp.h b/indra/llcommon/llcriticaldamp.h index 1fb6a1af29..2c37d276c4 100644 --- a/indra/llcommon/llcriticaldamp.h +++ b/indra/llcommon/llcriticaldamp.h @@ -1,26 +1,26 @@ -/** +/** * @file llcriticaldamp.h * @brief A lightweight class that calculates critical damping constants once - * per frame. + * per frame. * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -33,39 +33,39 @@ #include "llframetimer.h" #include "llunits.h" -class LL_COMMON_API LLSmoothInterpolation +class LL_COMMON_API LLSmoothInterpolation { public: - LLSmoothInterpolation(); + LLSmoothInterpolation(); - // MANIPULATORS - static void updateInterpolants(); + // MANIPULATORS + static void updateInterpolants(); - // ACCESSORS - static F32 getInterpolant(F32SecondsImplicit time_constant, bool use_cache = true); + // ACCESSORS + static F32 getInterpolant(F32SecondsImplicit time_constant, bool use_cache = true); - template - static T lerp(T a, T b, F32SecondsImplicit time_constant, bool use_cache = true) - { - F32 interpolant = getInterpolant(time_constant, use_cache); - return ((a * (1.f - interpolant)) - + (b * interpolant)); - } + template + static T lerp(T a, T b, F32SecondsImplicit time_constant, bool use_cache = true) + { + F32 interpolant = getInterpolant(time_constant, use_cache); + return ((a * (1.f - interpolant)) + + (b * interpolant)); + } protected: - static F32 calcInterpolant(F32 time_constant); + static F32 calcInterpolant(F32 time_constant); - struct CompareTimeConstants; - static LLFrameTimer sInternalTimer; // frame timer for calculating deltas + struct CompareTimeConstants; + static LLFrameTimer sInternalTimer; // frame timer for calculating deltas - struct Interpolant - { - F32 mTimeScale; - F32 mInterpolant; - }; - typedef std::vector interpolant_vec_t; - static interpolant_vec_t sInterpolants; - static F32 sTimeDelta; + struct Interpolant + { + F32 mTimeScale; + F32 mInterpolant; + }; + typedef std::vector interpolant_vec_t; + static interpolant_vec_t sInterpolants; + static F32 sTimeDelta; }; typedef LLSmoothInterpolation LLCriticalDamp; diff --git a/indra/llcommon/lldate.cpp b/indra/llcommon/lldate.cpp index 2ddcf40895..c63c7012d1 100644 --- a/indra/llcommon/lldate.cpp +++ b/indra/llcommon/lldate.cpp @@ -1,4 +1,4 @@ -/** +/** * @file lldate.cpp * @author Phoenix * @date 2006-02-05 @@ -7,21 +7,21 @@ * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -44,36 +44,36 @@ static const F64 DATE_EPOCH = 0.0; static const F64 LL_APR_USEC_PER_SEC = 1000000.0; - // should be APR_USEC_PER_SEC, but that relies on INT64_C which - // isn't defined in glib under our build set up for some reason + // should be APR_USEC_PER_SEC, but that relies on INT64_C which + // isn't defined in glib under our build set up for some reason LLDate::LLDate() : mSecondsSinceEpoch(DATE_EPOCH) {} LLDate::LLDate(const LLDate& date) : - mSecondsSinceEpoch(date.mSecondsSinceEpoch) + mSecondsSinceEpoch(date.mSecondsSinceEpoch) {} LLDate::LLDate(F64SecondsImplicit seconds_since_epoch) : - mSecondsSinceEpoch(seconds_since_epoch.value()) + mSecondsSinceEpoch(seconds_since_epoch.value()) {} LLDate::LLDate(const std::string& iso8601_date) { - if(!fromString(iso8601_date)) - { - LL_WARNS() << "date " << iso8601_date << " failed to parse; " - << "ZEROING IT OUT" << LL_ENDL; - mSecondsSinceEpoch = DATE_EPOCH; - } + if(!fromString(iso8601_date)) + { + LL_WARNS() << "date " << iso8601_date << " failed to parse; " + << "ZEROING IT OUT" << LL_ENDL; + mSecondsSinceEpoch = DATE_EPOCH; + } } std::string LLDate::asString() const { - std::ostringstream stream; - toStream(stream); - return stream.str(); + std::ostringstream stream; + toStream(stream); + return stream.str(); } //@ brief Converts time in seconds since EPOCH @@ -83,236 +83,236 @@ std::string LLDate::asString() const // is one of the standards used and the prefered format std::string LLDate::asRFC1123() const { - return toHTTPDateString (std::string ("%A, %d %b %Y %H:%M:%S GMT")); + return toHTTPDateString (std::string ("%A, %d %b %Y %H:%M:%S GMT")); } std::string LLDate::toHTTPDateString (std::string fmt) const { LL_PROFILE_ZONE_SCOPED; - - time_t locSeconds = (time_t) mSecondsSinceEpoch; - struct tm * gmt = gmtime (&locSeconds); - return toHTTPDateString(gmt, fmt); + + time_t locSeconds = (time_t) mSecondsSinceEpoch; + struct tm * gmt = gmtime (&locSeconds); + return toHTTPDateString(gmt, fmt); } std::string LLDate::toHTTPDateString (tm * gmt, std::string fmt) { LL_PROFILE_ZONE_SCOPED; - // 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; - } - - // use strftime() as it appears to be faster than std::time_put - char buffer[128]; - strftime(buffer, 128, fmt.c_str(), gmt); - std::string res(buffer); + // 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; + } + + // use strftime() as it appears to be faster than std::time_put + char buffer[128]; + strftime(buffer, 128, fmt.c_str(), gmt); + std::string res(buffer); #if LL_WINDOWS - // Convert from locale-dependant charset to UTF-8 (EXT-8524). - res = ll_convert_string_to_utf8_string(res); + // Convert from locale-dependant charset to UTF-8 (EXT-8524). + res = ll_convert_string_to_utf8_string(res); #endif - return res; + return res; } void LLDate::toStream(std::ostream& s) 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) - { - s << "1970-01-01T00:00:00Z"; - return; - } - - s << std::dec << std::setfill('0'); + 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) + { + s << "1970-01-01T00:00:00Z"; + return; + } + + s << std::dec << std::setfill('0'); #if( LL_WINDOWS || __GNUC__ > 2) - s << std::right; + s << std::right; #else - s.setf(ios::right); + s.setf(ios::right); #endif - s << std::setw(4) << (exp_time.tm_year + 1900) - << '-' << std::setw(2) << (exp_time.tm_mon + 1) - << '-' << std::setw(2) << (exp_time.tm_mday) - << 'T' << std::setw(2) << (exp_time.tm_hour) - << ':' << std::setw(2) << (exp_time.tm_min) - << ':' << std::setw(2) << (exp_time.tm_sec); - if (exp_time.tm_usec > 0) - { - s << '.' << std::setw(2) - << (int)(exp_time.tm_usec / (LL_APR_USEC_PER_SEC / 100)); - } - s << 'Z' - << std::setfill(' '); + s << std::setw(4) << (exp_time.tm_year + 1900) + << '-' << std::setw(2) << (exp_time.tm_mon + 1) + << '-' << std::setw(2) << (exp_time.tm_mday) + << 'T' << std::setw(2) << (exp_time.tm_hour) + << ':' << std::setw(2) << (exp_time.tm_min) + << ':' << std::setw(2) << (exp_time.tm_sec); + if (exp_time.tm_usec > 0) + { + s << '.' << std::setw(2) + << (int)(exp_time.tm_usec / (LL_APR_USEC_PER_SEC / 100)); + } + s << 'Z' + << std::setfill(' '); } 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; - } + 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 (year) + *year = exp_time.tm_year + 1900; - if (month) - *month = exp_time.tm_mon + 1; + if (month) + *month = exp_time.tm_mon + 1; - if (day) - *day = exp_time.tm_mday; + if (day) + *day = exp_time.tm_mday; - if (hour) - *hour = exp_time.tm_hour; + if (hour) + *hour = exp_time.tm_hour; - if (min) - *min = exp_time.tm_min; + if (min) + *min = exp_time.tm_min; - if (sec) - *sec = exp_time.tm_sec; + if (sec) + *sec = exp_time.tm_sec; - return true; + return true; } bool LLDate::fromString(const std::string& iso8601_date) { - std::istringstream stream(iso8601_date); - return fromStream(stream); + std::istringstream stream(iso8601_date); + return fromStream(stream); } bool LLDate::fromStream(std::istream& s) { - struct apr_time_exp_t exp_time; - apr_int32_t tm_part; - int c; - - s >> tm_part; - exp_time.tm_year = tm_part - 1900; - c = s.get(); // skip the hypen - if (c != '-') { return false; } - s >> tm_part; - exp_time.tm_mon = tm_part - 1; - c = s.get(); // skip the hypen - if (c != '-') { return false; } - s >> tm_part; - exp_time.tm_mday = tm_part; - - c = s.get(); // skip the T - if (c != 'T') { return false; } - - s >> tm_part; - exp_time.tm_hour = tm_part; - c = s.get(); // skip the : - if (c != ':') { return false; } - s >> tm_part; - exp_time.tm_min = tm_part; - c = s.get(); // skip the : - if (c != ':') { return false; } - s >> tm_part; - exp_time.tm_sec = tm_part; - - // zero out the unused fields - exp_time.tm_usec = 0; - exp_time.tm_wday = 0; - exp_time.tm_yday = 0; - exp_time.tm_isdst = 0; - exp_time.tm_gmtoff = 0; - - // generate a time_t from that - apr_time_t time; - if (apr_time_exp_gmt_get(&time, &exp_time) != APR_SUCCESS) - { - return false; - } - - F64 seconds_since_epoch = time / LL_APR_USEC_PER_SEC; - - // check for fractional - c = s.peek(); - if(c == '.') - { - F64 fractional = 0.0; - s >> fractional; - seconds_since_epoch += fractional; - } - - c = s.peek(); // check for offset - if (c == '+' || c == '-') - { - S32 offset_sign = (c == '+') ? 1 : -1; - S32 offset_hours = 0; - S32 offset_minutes = 0; - S32 offset_in_seconds = 0; - - s >> offset_hours; - - c = s.get(); // skip the colon a get the minutes if there are any - if (c == ':') - { - s >> offset_minutes; - } - - offset_in_seconds = (offset_hours * 60 + offset_sign * offset_minutes) * 60; - seconds_since_epoch -= offset_in_seconds; - } - else if (c != 'Z') { return false; } // skip the Z - - mSecondsSinceEpoch = seconds_since_epoch; - return true; + struct apr_time_exp_t exp_time; + apr_int32_t tm_part; + int c; + + s >> tm_part; + exp_time.tm_year = tm_part - 1900; + c = s.get(); // skip the hypen + if (c != '-') { return false; } + s >> tm_part; + exp_time.tm_mon = tm_part - 1; + c = s.get(); // skip the hypen + if (c != '-') { return false; } + s >> tm_part; + exp_time.tm_mday = tm_part; + + c = s.get(); // skip the T + if (c != 'T') { return false; } + + s >> tm_part; + exp_time.tm_hour = tm_part; + c = s.get(); // skip the : + if (c != ':') { return false; } + s >> tm_part; + exp_time.tm_min = tm_part; + c = s.get(); // skip the : + if (c != ':') { return false; } + s >> tm_part; + exp_time.tm_sec = tm_part; + + // zero out the unused fields + exp_time.tm_usec = 0; + exp_time.tm_wday = 0; + exp_time.tm_yday = 0; + exp_time.tm_isdst = 0; + exp_time.tm_gmtoff = 0; + + // generate a time_t from that + apr_time_t time; + if (apr_time_exp_gmt_get(&time, &exp_time) != APR_SUCCESS) + { + return false; + } + + F64 seconds_since_epoch = time / LL_APR_USEC_PER_SEC; + + // check for fractional + c = s.peek(); + if(c == '.') + { + F64 fractional = 0.0; + s >> fractional; + seconds_since_epoch += fractional; + } + + c = s.peek(); // check for offset + if (c == '+' || c == '-') + { + S32 offset_sign = (c == '+') ? 1 : -1; + S32 offset_hours = 0; + S32 offset_minutes = 0; + S32 offset_in_seconds = 0; + + s >> offset_hours; + + c = s.get(); // skip the colon a get the minutes if there are any + if (c == ':') + { + s >> offset_minutes; + } + + offset_in_seconds = (offset_hours * 60 + offset_sign * offset_minutes) * 60; + seconds_since_epoch -= offset_in_seconds; + } + else if (c != 'Z') { return false; } // skip the Z + + mSecondsSinceEpoch = seconds_since_epoch; + return true; } bool LLDate::fromYMDHMS(S32 year, S32 month, S32 day, S32 hour, S32 min, S32 sec) { - struct apr_time_exp_t exp_time; - - exp_time.tm_year = year - 1900; - exp_time.tm_mon = month - 1; - exp_time.tm_mday = day; - exp_time.tm_hour = hour; - exp_time.tm_min = min; - exp_time.tm_sec = sec; - - // zero out the unused fields - exp_time.tm_usec = 0; - exp_time.tm_wday = 0; - exp_time.tm_yday = 0; - exp_time.tm_isdst = 0; - exp_time.tm_gmtoff = 0; - - // generate a time_t from that - apr_time_t time; - if (apr_time_exp_gmt_get(&time, &exp_time) != APR_SUCCESS) - { - return false; - } - - mSecondsSinceEpoch = time / LL_APR_USEC_PER_SEC; - - return true; + struct apr_time_exp_t exp_time; + + exp_time.tm_year = year - 1900; + exp_time.tm_mon = month - 1; + exp_time.tm_mday = day; + exp_time.tm_hour = hour; + exp_time.tm_min = min; + exp_time.tm_sec = sec; + + // zero out the unused fields + exp_time.tm_usec = 0; + exp_time.tm_wday = 0; + exp_time.tm_yday = 0; + exp_time.tm_isdst = 0; + exp_time.tm_gmtoff = 0; + + // generate a time_t from that + apr_time_t time; + if (apr_time_exp_gmt_get(&time, &exp_time) != APR_SUCCESS) + { + return false; + } + + mSecondsSinceEpoch = time / LL_APR_USEC_PER_SEC; + + return true; } F64 LLDate::secondsSinceEpoch() const { - return mSecondsSinceEpoch; + return mSecondsSinceEpoch; } void LLDate::secondsSinceEpoch(F64 seconds) { - mSecondsSinceEpoch = seconds; + mSecondsSinceEpoch = seconds; } /* static */ LLDate LLDate::now() { - // time() returns seconds, we want fractions of a second, which LLTimer provides --RN - return LLDate(LLTimer::getTotalSeconds()); + // time() returns seconds, we want fractions of a second, which LLTimer provides --RN + return LLDate(LLTimer::getTotalSeconds()); } bool LLDate::operator<(const LLDate& rhs) const @@ -322,13 +322,13 @@ bool LLDate::operator<(const LLDate& rhs) const std::ostream& operator<<(std::ostream& s, const LLDate& date) { - date.toStream(s); - return s; + date.toStream(s); + return s; } std::istream& operator>>(std::istream& s, LLDate& date) { - date.fromStream(s); - return s; + date.fromStream(s); + return s; } diff --git a/indra/llcommon/lldate.h b/indra/llcommon/lldate.h index be2cd2d051..81f2dd0d1c 100644 --- a/indra/llcommon/lldate.h +++ b/indra/llcommon/lldate.h @@ -1,4 +1,4 @@ -/** +/** * @file lldate.h * @author Phoenix * @date 2006-02-05 @@ -7,21 +7,21 @@ * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -35,7 +35,7 @@ #include "stdtypes.h" #include "llunits.h" -/** +/** * @class LLDate * @brief This class represents a particular point in time in UTC. * @@ -44,110 +44,110 @@ class LL_COMMON_API LLDate { public: - /** - * @brief Construct a date equal to epoch. - */ - LLDate(); - - /** - * @brief Construct a date equal to the source date. - */ - LLDate(const LLDate& date); - - /** - * @brief Construct a date from a seconds since epoch value. - * - * @param seconds_since_epoch The number of seconds since UTC epoch. - */ - LLDate(F64SecondsImplicit seconds_since_epoch); - - /** - * @brief Construct a date from a string representation - * - * The date is constructed in the fromString() - * method. See that method for details of supported formats. - * If that method fails to parse the date, the date is set to epoch. - * @param iso8601_date An iso-8601 compatible representation of the date. - */ - LLDate(const std::string& iso8601_date); - - /** - * @brief Return the date as in ISO-8601 string. - * - * @return A string representation of the date. - */ - 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); - /** - * @brief Set the date from an ISO-8601 string. - * - * The parser only supports strings conforming to - * YYYYF-MM-DDTHH:MM:SS.FFZ where Y is year, M is month, D is day, - * H is hour, M is minute, S is second, F is sub-second, and all - * other characters are literal. - * If this method fails to parse the date, the previous date is - * retained. - * @param iso8601_date An iso-8601 compatible representation of the date. - * @return Returns true if the string was successfully parsed. - */ - bool fromString(const std::string& iso8601_date); - bool fromStream(std::istream&); - bool fromYMDHMS(S32 year, S32 month = 1, S32 day = 0, S32 hour = 0, S32 min = 0, S32 sec = 0); - - /** - * @brief Return the date in seconds since epoch. - * - * @return The number of seconds since epoch UTC. - */ - F64 secondsSinceEpoch() const; - - /** - * @brief Set the date in seconds since epoch. - * - * @param seconds The number of seconds since epoch UTC. - */ - void secondsSinceEpoch(F64 seconds); - + /** + * @brief Construct a date equal to epoch. + */ + LLDate(); + + /** + * @brief Construct a date equal to the source date. + */ + LLDate(const LLDate& date); + + /** + * @brief Construct a date from a seconds since epoch value. + * + * @param seconds_since_epoch The number of seconds since UTC epoch. + */ + LLDate(F64SecondsImplicit seconds_since_epoch); + + /** + * @brief Construct a date from a string representation + * + * The date is constructed in the fromString() + * method. See that method for details of supported formats. + * If that method fails to parse the date, the date is set to epoch. + * @param iso8601_date An iso-8601 compatible representation of the date. + */ + LLDate(const std::string& iso8601_date); + + /** + * @brief Return the date as in ISO-8601 string. + * + * @return A string representation of the date. + */ + 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); + /** + * @brief Set the date from an ISO-8601 string. + * + * The parser only supports strings conforming to + * YYYYF-MM-DDTHH:MM:SS.FFZ where Y is year, M is month, D is day, + * H is hour, M is minute, S is second, F is sub-second, and all + * other characters are literal. + * If this method fails to parse the date, the previous date is + * retained. + * @param iso8601_date An iso-8601 compatible representation of the date. + * @return Returns true if the string was successfully parsed. + */ + bool fromString(const std::string& iso8601_date); + bool fromStream(std::istream&); + bool fromYMDHMS(S32 year, S32 month = 1, S32 day = 0, S32 hour = 0, S32 min = 0, S32 sec = 0); + + /** + * @brief Return the date in seconds since epoch. + * + * @return The number of seconds since epoch UTC. + */ + F64 secondsSinceEpoch() const; + + /** + * @brief Set the date in seconds since epoch. + * + * @param seconds The number of seconds since epoch UTC. + */ + void secondsSinceEpoch(F64 seconds); + /** * @brief Create an LLDate object set to the current time. - * - * @return The number of seconds since epoch UTC. - */ + * + * @return The number of seconds since epoch UTC. + */ static LLDate now(); - /** - * @brief Compare dates using operator< so we can order them using STL. - * - * @param rhs -- the right hand side of the comparison operator - */ - bool operator<(const LLDate& rhs) const; - - /** - * @brief Remaining comparison operators in terms of operator< + /** + * @brief Compare dates using operator< so we can order them using STL. + * + * @param rhs -- the right hand side of the comparison operator + */ + bool operator<(const LLDate& rhs) const; + + /** + * @brief Remaining comparison operators in terms of operator< * This conforms to the expectation of STL. - * - * @param rhs -- the right hand side of the comparison operator - */ + * + * @param rhs -- the right hand side of the comparison operator + */ bool operator>(const LLDate& rhs) const { return rhs < *this; } bool operator<=(const LLDate& rhs) const { return !(rhs < *this); } bool operator>=(const LLDate& rhs) const { return !(*this < rhs); } bool operator!=(const LLDate& rhs) const { return (*this < rhs) || (rhs < *this); } bool operator==(const LLDate& rhs) const { return !(*this != rhs); } - /** - * @brief Compare to epoch UTC. - */ + /** + * @brief Compare to epoch UTC. + */ + + bool isNull() const { return mSecondsSinceEpoch == 0.0; } + bool notNull() const { return mSecondsSinceEpoch != 0.0; } - bool isNull() const { return mSecondsSinceEpoch == 0.0; } - bool notNull() const { return mSecondsSinceEpoch != 0.0; } - private: - F64 mSecondsSinceEpoch; + F64 mSecondsSinceEpoch; }; // Helper function to stream out a date diff --git a/indra/llcommon/lldeadmantimer.cpp b/indra/llcommon/lldeadmantimer.cpp index 830443b956..f9c14d7c24 100644 --- a/indra/llcommon/lldeadmantimer.cpp +++ b/indra/llcommon/lldeadmantimer.cpp @@ -1,4 +1,4 @@ -/** +/** * @file lldeadmantimer.cpp * @brief Simple deadman-switch timer. * @author monty@lindenlab.com @@ -43,146 +43,146 @@ // true true Not allowed // LLDeadmanTimer::LLDeadmanTimer(F64 horizon, bool inc_cpu) - : mHorizon(time_type(llmax(horizon, F64(0.0)) * get_timer_info().mClockFrequency)), - mActive(false), // If true, a timer is running. - mDone(false), // If true, timer has completed and can be read (once) - mStarted(U64L(0)), - mExpires(U64L(0)), - mStopped(U64L(0)), - mCount(U64L(0)), - mIncCPU(inc_cpu), - mUStartCPU(LLProcInfo::time_type(U64L(0))), - mUEndCPU(LLProcInfo::time_type(U64L(0))), - mSStartCPU(LLProcInfo::time_type(U64L(0))), - mSEndCPU(LLProcInfo::time_type(U64L(0))) + : mHorizon(time_type(llmax(horizon, F64(0.0)) * get_timer_info().mClockFrequency)), + mActive(false), // If true, a timer is running. + mDone(false), // If true, timer has completed and can be read (once) + mStarted(U64L(0)), + mExpires(U64L(0)), + mStopped(U64L(0)), + mCount(U64L(0)), + mIncCPU(inc_cpu), + mUStartCPU(LLProcInfo::time_type(U64L(0))), + mUEndCPU(LLProcInfo::time_type(U64L(0))), + mSStartCPU(LLProcInfo::time_type(U64L(0))), + mSEndCPU(LLProcInfo::time_type(U64L(0))) {} // static LLDeadmanTimer::time_type LLDeadmanTimer::getNow() { - return LLTimer::getCurrentClockCount(); + return LLTimer::getCurrentClockCount(); } void LLDeadmanTimer::start(time_type now) { - // *TODO: If active, let's complete an existing timer and save - // the result to the side. I think this will be useful later. - // For now, wipe out anything in progress, start fresh. - - if (! now) - { - now = LLTimer::getCurrentClockCount(); - } - mActive = true; - mDone = false; - mStarted = now; - mExpires = now + mHorizon; - mStopped = now; - mCount = U64L(0); - if (mIncCPU) - { - LLProcInfo::getCPUUsage(mUStartCPU, mSStartCPU); - } + // *TODO: If active, let's complete an existing timer and save + // the result to the side. I think this will be useful later. + // For now, wipe out anything in progress, start fresh. + + if (! now) + { + now = LLTimer::getCurrentClockCount(); + } + mActive = true; + mDone = false; + mStarted = now; + mExpires = now + mHorizon; + mStopped = now; + mCount = U64L(0); + if (mIncCPU) + { + LLProcInfo::getCPUUsage(mUStartCPU, mSStartCPU); + } } void LLDeadmanTimer::stop(time_type now) { - if (! mActive) - { - return; - } - - if (! now) - { - now = getNow(); - } - mStopped = now; - mActive = false; - mDone = true; - if (mIncCPU) - { - LLProcInfo::getCPUUsage(mUEndCPU, mSEndCPU); - } + if (! mActive) + { + return; + } + + if (! now) + { + now = getNow(); + } + mStopped = now; + mActive = false; + mDone = true; + if (mIncCPU) + { + LLProcInfo::getCPUUsage(mUEndCPU, mSEndCPU); + } } bool LLDeadmanTimer::isExpired(time_type now, F64 & started, F64 & stopped, U64 & count, - U64 & user_cpu, U64 & sys_cpu) + U64 & user_cpu, U64 & sys_cpu) { - const bool status(isExpired(now, started, stopped, count)); - if (status) - { - user_cpu = U64(mUEndCPU - mUStartCPU); - sys_cpu = U64(mSEndCPU - mSStartCPU); - } - return status; + const bool status(isExpired(now, started, stopped, count)); + if (status) + { + user_cpu = U64(mUEndCPU - mUStartCPU); + sys_cpu = U64(mSEndCPU - mSStartCPU); + } + return status; } - + bool LLDeadmanTimer::isExpired(time_type now, F64 & started, F64 & stopped, U64 & count) { - if (mActive && ! mDone) - { - if (! now) - { - now = getNow(); - } - - if (now >= mExpires) - { - // mStopped from ringBell() is the value we want - mActive = false; - mDone = true; - } - } - - if (! mDone) - { - return false; - } - - started = mStarted * get_timer_info().mClockFrequencyInv; - stopped = mStopped * get_timer_info().mClockFrequencyInv; - count = mCount; - mDone = false; - - return true; + if (mActive && ! mDone) + { + if (! now) + { + now = getNow(); + } + + if (now >= mExpires) + { + // mStopped from ringBell() is the value we want + mActive = false; + mDone = true; + } + } + + if (! mDone) + { + return false; + } + + started = mStarted * get_timer_info().mClockFrequencyInv; + stopped = mStopped * get_timer_info().mClockFrequencyInv; + count = mCount; + mDone = false; + + return true; } - + void LLDeadmanTimer::ringBell(time_type now, unsigned int count) { - if (! mActive) - { - return; - } - - if (! now) - { - now = getNow(); - } - - if (now >= mExpires) - { - // Timer has expired, this event will be dropped - mActive = false; - mDone = true; - } - else - { - // Timer renewed, keep going - mStopped = now; - mExpires = now + mHorizon; - mCount += count; - if (mIncCPU) - { - LLProcInfo::getCPUUsage(mUEndCPU, mSEndCPU); - } - } - - return; + if (! mActive) + { + return; + } + + if (! now) + { + now = getNow(); + } + + if (now >= mExpires) + { + // Timer has expired, this event will be dropped + mActive = false; + mDone = true; + } + else + { + // Timer renewed, keep going + mStopped = now; + mExpires = now + mHorizon; + mCount += count; + if (mIncCPU) + { + LLProcInfo::getCPUUsage(mUEndCPU, mSEndCPU); + } + } + + return; } diff --git a/indra/llcommon/lldeadmantimer.h b/indra/llcommon/lldeadmantimer.h index 980976e176..3f10420d41 100644 --- a/indra/llcommon/lldeadmantimer.h +++ b/indra/llcommon/lldeadmantimer.h @@ -1,4 +1,4 @@ -/** +/** * @file lldeadmantimer.h * @brief Interface to a simple event timer with a deadman's switch * @author monty@lindenlab.com @@ -25,8 +25,8 @@ * $/LicenseInfo$ */ -#ifndef LL_DEADMANTIMER_H -#define LL_DEADMANTIMER_H +#ifndef LL_DEADMANTIMER_H +#define LL_DEADMANTIMER_H #include "linden_common.h" @@ -78,137 +78,137 @@ class LL_COMMON_API LLDeadmanTimer { public: - /// Public types - - /// Low-level time type chosen for compatibility with - /// LLTimer::getCurrentClockCount() which is the basis - /// of time operations in this class. This is likely - /// to change in a future version in a move to TSC-based - /// timing. - typedef U64 time_type; - + /// Public types + + /// Low-level time type chosen for compatibility with + /// LLTimer::getCurrentClockCount() which is the basis + /// of time operations in this class. This is likely + /// to change in a future version in a move to TSC-based + /// timing. + typedef U64 time_type; + public: - /// Construct and initialize an LLDeadmanTimer - /// - /// @param horizon Time, in seconds, after the last @see ringBell() - /// call at which point the timer will consider itself - /// expired. - /// - /// @param inc_cpu If true, gather system and user cpu stats while - /// running the timer. This does require more syscalls - /// during updates. If false, cpu usage data isn't - /// collected and will be zero if queried. - LLDeadmanTimer(F64 horizon, bool inc_cpu); - - ~LLDeadmanTimer() - {} - + /// Construct and initialize an LLDeadmanTimer + /// + /// @param horizon Time, in seconds, after the last @see ringBell() + /// call at which point the timer will consider itself + /// expired. + /// + /// @param inc_cpu If true, gather system and user cpu stats while + /// running the timer. This does require more syscalls + /// during updates. If false, cpu usage data isn't + /// collected and will be zero if queried. + LLDeadmanTimer(F64 horizon, bool inc_cpu); + + ~LLDeadmanTimer() + {} + private: - LLDeadmanTimer(const LLDeadmanTimer &); // Not defined - void operator=(const LLDeadmanTimer &); // Not defined + LLDeadmanTimer(const LLDeadmanTimer &); // Not defined + void operator=(const LLDeadmanTimer &); // Not defined public: - /// Get the current time. Zero-basis for this time - /// representation is not defined and is different on - /// different platforms. Do not attempt to compute - /// negative times relative to the first value returned, - /// there may not be enough 'front porch' on the range - /// to prevent wraparound. - /// - /// Note: Implementation is expected to change in a - /// future release as well. - /// - static time_type getNow(); - - /// Begin timing. If the timer is already active, it is reset - /// and timing begins now. - /// - /// @param now Current time as returned by @see - /// LLTimer::getCurrentClockCount(). If zero, - /// method will lookup current time. - /// - void start(time_type now); - - /// End timing. Actively declare the end of the event independent - /// of the deadman's switch operation. @see isExpired() will return - /// true and appropriate values will be returned. - /// - /// @param now Current time as returned by @see - /// LLTimer::getCurrentClockCount(). If zero, - /// method will lookup current time. - /// - void stop(time_type now); - - /// Declare that something interesting happened. This has two - /// effects on an unexpired-timer. 1) The expiration time - /// is extended for 'horizon' seconds after the 'now' value. - /// 2) An internal counter associated with the event is incremented - /// by the @ref count parameter. This count is returned via the - /// @see isExpired() method. - /// - /// @param now Current time as returned by @see - /// LLTimer::getCurrentClockCount(). If zero, - /// method will lookup current time. - /// - /// @param count Count of events to be associated with - /// this bell ringing. - /// - void ringBell(time_type now, unsigned int count); - - /// Checks the status of the timer. If the timer has expired, - /// also returns various timer-related stats. Unlike ringBell(), - /// does not extend the horizon, it only checks for expiration. - /// - /// @param now Current time as returned by @see - /// LLTimer::getCurrentClockCount(). If zero, - /// method will lookup current time. - /// - /// @param started If expired, the starting time of the event is - /// returned to the caller via this reference. - /// - /// @param stopped If expired, the ending time of the event is - /// returned to the caller via this reference. - /// Ending time will be that provided in the - /// stop() method or the last ringBell() call - /// leading to expiration, whichever (stop() call - /// or notice of expiration) happened first. - /// - /// @param count If expired, the number of ringBell() calls - /// made prior to expiration. - /// - /// @param user_cpu Amount of CPU spent in user mode by the process - /// during the event. Value in microseconds and will - /// read zero if not enabled by the constructor. - /// - /// @param sys_cpu Amount of CPU spent in system mode by the process. - /// - /// @return true if the timer has expired, false otherwise. - /// If true, it also returns the started, - /// stopped and count values otherwise these are - /// left unchanged. - /// - bool isExpired(time_type now, F64 & started, F64 & stopped, U64 & count, - U64 & user_cpu, U64 & sys_cpu); - - /// Identical to the six-arugment form except it does without the - /// CPU time return if the caller isn't interested in it. - bool isExpired(time_type now, F64 & started, F64 & stopped, U64 & count); + /// Get the current time. Zero-basis for this time + /// representation is not defined and is different on + /// different platforms. Do not attempt to compute + /// negative times relative to the first value returned, + /// there may not be enough 'front porch' on the range + /// to prevent wraparound. + /// + /// Note: Implementation is expected to change in a + /// future release as well. + /// + static time_type getNow(); + + /// Begin timing. If the timer is already active, it is reset + /// and timing begins now. + /// + /// @param now Current time as returned by @see + /// LLTimer::getCurrentClockCount(). If zero, + /// method will lookup current time. + /// + void start(time_type now); + + /// End timing. Actively declare the end of the event independent + /// of the deadman's switch operation. @see isExpired() will return + /// true and appropriate values will be returned. + /// + /// @param now Current time as returned by @see + /// LLTimer::getCurrentClockCount(). If zero, + /// method will lookup current time. + /// + void stop(time_type now); + + /// Declare that something interesting happened. This has two + /// effects on an unexpired-timer. 1) The expiration time + /// is extended for 'horizon' seconds after the 'now' value. + /// 2) An internal counter associated with the event is incremented + /// by the @ref count parameter. This count is returned via the + /// @see isExpired() method. + /// + /// @param now Current time as returned by @see + /// LLTimer::getCurrentClockCount(). If zero, + /// method will lookup current time. + /// + /// @param count Count of events to be associated with + /// this bell ringing. + /// + void ringBell(time_type now, unsigned int count); + + /// Checks the status of the timer. If the timer has expired, + /// also returns various timer-related stats. Unlike ringBell(), + /// does not extend the horizon, it only checks for expiration. + /// + /// @param now Current time as returned by @see + /// LLTimer::getCurrentClockCount(). If zero, + /// method will lookup current time. + /// + /// @param started If expired, the starting time of the event is + /// returned to the caller via this reference. + /// + /// @param stopped If expired, the ending time of the event is + /// returned to the caller via this reference. + /// Ending time will be that provided in the + /// stop() method or the last ringBell() call + /// leading to expiration, whichever (stop() call + /// or notice of expiration) happened first. + /// + /// @param count If expired, the number of ringBell() calls + /// made prior to expiration. + /// + /// @param user_cpu Amount of CPU spent in user mode by the process + /// during the event. Value in microseconds and will + /// read zero if not enabled by the constructor. + /// + /// @param sys_cpu Amount of CPU spent in system mode by the process. + /// + /// @return true if the timer has expired, false otherwise. + /// If true, it also returns the started, + /// stopped and count values otherwise these are + /// left unchanged. + /// + bool isExpired(time_type now, F64 & started, F64 & stopped, U64 & count, + U64 & user_cpu, U64 & sys_cpu); + + /// Identical to the six-arugment form except it does without the + /// CPU time return if the caller isn't interested in it. + bool isExpired(time_type now, F64 & started, F64 & stopped, U64 & count); protected: - time_type mHorizon; - bool mActive; - bool mDone; - time_type mStarted; - time_type mExpires; - time_type mStopped; - time_type mCount; - - const bool mIncCPU; // Include CPU metrics in timer - LLProcInfo::time_type mUStartCPU; - LLProcInfo::time_type mUEndCPU; - LLProcInfo::time_type mSStartCPU; - LLProcInfo::time_type mSEndCPU; + time_type mHorizon; + bool mActive; + bool mDone; + time_type mStarted; + time_type mExpires; + time_type mStopped; + time_type mCount; + + const bool mIncCPU; // Include CPU metrics in timer + LLProcInfo::time_type mUStartCPU; + LLProcInfo::time_type mUEndCPU; + LLProcInfo::time_type mSStartCPU; + LLProcInfo::time_type mSEndCPU; }; - -#endif // LL_DEADMANTIMER_H + +#endif // LL_DEADMANTIMER_H diff --git a/indra/llcommon/lldefs.h b/indra/llcommon/lldefs.h index 4e25001fff..0ba756d472 100644 --- a/indra/llcommon/lldefs.h +++ b/indra/llcommon/lldefs.h @@ -1,25 +1,25 @@ -/** +/** * @file lldefs.h * @brief Various generic constant definitions. * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -31,73 +31,73 @@ #include // Often used array indices -const U32 VX = 0; -const U32 VY = 1; -const U32 VZ = 2; -const U32 VW = 3; -const U32 VS = 3; - -const U32 VRED = 0; -const U32 VGREEN = 1; -const U32 VBLUE = 2; -const U32 VALPHA = 3; - -const U32 INVALID_DIRECTION = 0xFFFFFFFF; -const U32 EAST = 0; -const U32 NORTH = 1; -const U32 WEST = 2; -const U32 SOUTH = 3; - -const U32 NORTHEAST = 4; -const U32 NORTHWEST = 5; -const U32 SOUTHWEST = 6; -const U32 SOUTHEAST = 7; -const U32 MIDDLE = 8; - -const U8 EAST_MASK = 0x1< X -// |/| | -4- |/| | +// | |/| | / | |/| +// | 2 | | *-------|-1--------> X +// |/| | -4- |/| | // | +----|---------|---+ // | / / | / // | / -6- | / -// |/ / |/ +// |/ / |/ // +------------------+ -const U32 NO_SIDE = 0; -const U32 FRONT_SIDE = 1; -const U32 BACK_SIDE = 2; -const U32 LEFT_SIDE = 3; -const U32 RIGHT_SIDE = 4; -const U32 TOP_SIDE = 5; -const U32 BOTTOM_SIDE = 6; +const U32 NO_SIDE = 0; +const U32 FRONT_SIDE = 1; +const U32 BACK_SIDE = 2; +const U32 LEFT_SIDE = 3; +const U32 RIGHT_SIDE = 4; +const U32 TOP_SIDE = 5; +const U32 BOTTOM_SIDE = 6; const U8 LL_SOUND_FLAG_NONE = 0x0; const U8 LL_SOUND_FLAG_LOOP = 1<<0; @@ -141,17 +141,17 @@ const U8 LL_SOUND_FLAG_SYNC_MASK = LL_SOUND_FLAG_SYNC_MASTER | LL_SOUND_FLAG_SYN // DO NOT CHANGE. // -------------- // -const U32 LL_MAX_PATH = 1024; // buffer size of maximum path + filename string length +const U32 LL_MAX_PATH = 1024; // buffer size of maximum path + filename string length // For strings we send in messages -const U32 STD_STRING_BUF_SIZE = 255; // Buffer size -const U32 STD_STRING_STR_LEN = 254; // Length of the string (not including \0) +const U32 STD_STRING_BUF_SIZE = 255; // Buffer size +const U32 STD_STRING_STR_LEN = 254; // Length of the string (not including \0) // *NOTE: This value is used as hard-coded numbers in scanf() variants. // DO NOT CHANGE. -const U32 MAX_STRING = STD_STRING_BUF_SIZE; // Buffer size +const U32 MAX_STRING = STD_STRING_BUF_SIZE; // Buffer size -const U32 MAXADDRSTR = 17; // 123.567.901.345 = 15 chars + \0 + 1 for good luck +const U32 MAXADDRSTR = 17; // 123.567.901.345 = 15 chars + \0 + 1 for good luck // C++ is our friend. . . use template functions to make life easier! @@ -176,7 +176,7 @@ inline auto llmax(T data) return data; } -template +template inline auto llmax(T0 d0, T1 d1, Ts... rest) { auto maxrest = llmax(d1, rest...); @@ -190,44 +190,44 @@ inline auto llmin(T data) return data; } -template +template inline auto llmin(T0 d0, T1 d1, Ts... rest) { auto minrest = llmin(d1, rest...); return (d0 < minrest) ? d0 : minrest; } -template +template inline A llclamp(A a, MIN minval, MAX maxval) { - A aminval{ static_cast(minval) }, amaxval{ static_cast(maxval) }; - if ( a < aminval ) - { - return aminval; - } - else if ( a > amaxval ) - { - return amaxval; - } - return a; + A aminval{ static_cast(minval) }, amaxval{ static_cast(maxval) }; + if ( a < aminval ) + { + return aminval; + } + else if ( a > amaxval ) + { + return amaxval; + } + return a; } -template +template inline LLDATATYPE llclampf(LLDATATYPE a) { - return llmin(llmax(a, LLDATATYPE(0)), LLDATATYPE(1)); + return llmin(llmax(a, LLDATATYPE(0)), LLDATATYPE(1)); } -template +template inline LLDATATYPE llclampb(LLDATATYPE a) { - return llmin(llmax(a, LLDATATYPE(0)), LLDATATYPE(255)); + return llmin(llmax(a, LLDATATYPE(0)), LLDATATYPE(255)); } -template +template inline void llswap(LLDATATYPE& lhs, LLDATATYPE& rhs) { - std::swap(lhs, rhs); + std::swap(lhs, rhs); } #endif // LL_LLDEFS_H diff --git a/indra/llcommon/lldependencies.cpp b/indra/llcommon/lldependencies.cpp index db546c5c3b..dec0748374 100644 --- a/indra/llcommon/lldependencies.cpp +++ b/indra/llcommon/lldependencies.cpp @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2008-09-17 * @brief Implementation for lldependencies. - * + * * $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$ */ diff --git a/indra/llcommon/lldependencies.h b/indra/llcommon/lldependencies.h index 950af4a4ad..47b6fedc7d 100644 --- a/indra/llcommon/lldependencies.h +++ b/indra/llcommon/lldependencies.h @@ -8,21 +8,21 @@ * $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$ */ @@ -177,7 +177,7 @@ struct LLDependenciesEmpty * values such as NULL or 0 rather than having to write * LLDependenciesEmpty(). */ - LLDependenciesEmpty(void*) {} + LLDependenciesEmpty(void*) {} }; /** @@ -209,7 +209,7 @@ class LLDependencies: public LLDependenciesBase before(before_) {} NODE node; - dep_set after, before; + dep_set after, before; }; typedef std::map DepNodeMap; typedef typename DepNodeMap::value_type DepNodeMapEntry; @@ -239,7 +239,7 @@ public: * NODE& reference. * * @note - * Actual dependency analysis is deferred to the sort() method, so + * Actual dependency analysis is deferred to the sort() method, so * you can add an arbitrary number of nodes without incurring analysis * overhead for each. The flip side of this is that add()ing nodes that * define a cycle leaves this object in a state in which sort() will @@ -598,7 +598,7 @@ public: return sorted_range(begin, end); } - using LLDependenciesBase::describe; // unhide virtual std::string describe(bool full=true) const; + using LLDependenciesBase::describe; // unhide virtual std::string describe(bool full=true) const; /// Override base-class describe() with actual implementation virtual std::ostream& describe(std::ostream& out, bool full=true) const diff --git a/indra/llcommon/lldepthstack.h b/indra/llcommon/lldepthstack.h index b65840d342..66a7a4ce15 100644 --- a/indra/llcommon/lldepthstack.h +++ b/indra/llcommon/lldepthstack.h @@ -1,25 +1,25 @@ -/** +/** * @file lldepthstack.h * @brief Declaration of the LLDepthStack class * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -32,65 +32,65 @@ template class LLDepthStack { private: - std::deque mStack; - U32 mCurrentDepth; - U32 mMaxDepth; + std::deque mStack; + U32 mCurrentDepth; + U32 mMaxDepth; public: - LLDepthStack() - : mCurrentDepth(0), mMaxDepth(0) - {} + LLDepthStack() + : mCurrentDepth(0), mMaxDepth(0) + {} + + void setDepth(U32 depth) + { + mMaxDepth = depth; + } + + U32 getDepth(void) const + { + return mCurrentDepth; + } - void setDepth(U32 depth) - { - mMaxDepth = depth; - } + void push(DATA_TYPE *data) + { + if (mCurrentDepth < mMaxDepth) + { + mStack.push_back(data); + mCurrentDepth++; + } + else + { + // the last item falls off stack and is deleted + if (!mStack.empty()) + { + mStack.pop_front(); + } + mStack.push_back(data); + } + } - U32 getDepth(void) const - { - return mCurrentDepth; - } + DATA_TYPE *pop() + { + DATA_TYPE *tempp = NULL; + if (!mStack.empty()) + { + tempp = mStack.back(); + mStack.pop_back(); + mCurrentDepth--; + } + return tempp; + } - void push(DATA_TYPE *data) - { - if (mCurrentDepth < mMaxDepth) - { - mStack.push_back(data); - mCurrentDepth++; - } - else - { - // the last item falls off stack and is deleted - if (!mStack.empty()) - { - mStack.pop_front(); - } - mStack.push_back(data); - } - } - - DATA_TYPE *pop() - { - DATA_TYPE *tempp = NULL; - if (!mStack.empty()) - { - tempp = mStack.back(); - mStack.pop_back(); - mCurrentDepth--; - } - return tempp; - } - - DATA_TYPE *check() - { - return mStack.empty() ? NULL : mStack.back(); - } + DATA_TYPE *check() + { + return mStack.empty() ? NULL : mStack.back(); + } - void removeAllNodes() - { - mCurrentDepth = 0; - mStack.clear(); - } + void removeAllNodes() + { + mCurrentDepth = 0; + mStack.clear(); + } }; #endif diff --git a/indra/llcommon/lldictionary.cpp b/indra/llcommon/lldictionary.cpp index e16c35ed6a..1970aa58f2 100644 --- a/indra/llcommon/lldictionary.cpp +++ b/indra/llcommon/lldictionary.cpp @@ -1,25 +1,25 @@ -/** +/** * @file lldictionary.cpp * @brief Lldictionary class header file * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -32,16 +32,16 @@ // Define in .cpp file to prevent header include of llstring.h LLDictionaryEntry::LLDictionaryEntry(const std::string &name) -: mName(name) +: mName(name) { - mNameCapitalized = mName; - LLStringUtil::replaceChar(mNameCapitalized, '-', ' '); - LLStringUtil::replaceChar(mNameCapitalized, '_', ' '); - for (U32 i=0; i < mNameCapitalized.size(); i++) - { - if (i == 0 || mNameCapitalized[i-1] == ' ') // don't change ordering of this statement or crash - { - mNameCapitalized[i] = toupper(mNameCapitalized[i]); - } - } + mNameCapitalized = mName; + LLStringUtil::replaceChar(mNameCapitalized, '-', ' '); + LLStringUtil::replaceChar(mNameCapitalized, '_', ' '); + for (U32 i=0; i < mNameCapitalized.size(); i++) + { + if (i == 0 || mNameCapitalized[i-1] == ' ') // don't change ordering of this statement or crash + { + mNameCapitalized[i] = toupper(mNameCapitalized[i]); + } + } } diff --git a/indra/llcommon/lldictionary.h b/indra/llcommon/lldictionary.h index 18664e340e..9c399057ae 100644 --- a/indra/llcommon/lldictionary.h +++ b/indra/llcommon/lldictionary.h @@ -1,25 +1,25 @@ -/** +/** * @file lldictionary.h * @brief Lldictionary class header file * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -34,64 +34,64 @@ struct LL_COMMON_API LLDictionaryEntry { - LLDictionaryEntry(const std::string &name); - virtual ~LLDictionaryEntry() {} - const std::string mName; - std::string mNameCapitalized; + LLDictionaryEntry(const std::string &name); + virtual ~LLDictionaryEntry() {} + const std::string mName; + std::string mNameCapitalized; }; template class LLDictionary : public std::map { public: - typedef std::map map_t; - typedef typename map_t::iterator iterator_t; - typedef typename map_t::const_iterator const_iterator_t; - - LLDictionary() {} - virtual ~LLDictionary() - { - for (iterator_t iter = map_t::begin(); iter != map_t::end(); ++iter) - delete (iter->second); - } + typedef std::map map_t; + typedef typename map_t::iterator iterator_t; + typedef typename map_t::const_iterator const_iterator_t; + + LLDictionary() {} + virtual ~LLDictionary() + { + for (iterator_t iter = map_t::begin(); iter != map_t::end(); ++iter) + delete (iter->second); + } - const Entry *lookup(Index index) const - { - const_iterator_t dictionary_iter = map_t::find(index); - if (dictionary_iter == map_t::end()) return NULL; - return dictionary_iter->second; - } - const Index lookup(const std::string &name) const - { - for (const_iterator_t dictionary_iter = map_t::begin(); - dictionary_iter != map_t::end(); - dictionary_iter++) - { - const Entry *entry = dictionary_iter->second; - if (entry->mName == name) - { - return dictionary_iter->first; - } - } - return notFound(); - } + const Entry *lookup(Index index) const + { + const_iterator_t dictionary_iter = map_t::find(index); + if (dictionary_iter == map_t::end()) return NULL; + return dictionary_iter->second; + } + const Index lookup(const std::string &name) const + { + for (const_iterator_t dictionary_iter = map_t::begin(); + dictionary_iter != map_t::end(); + dictionary_iter++) + { + const Entry *entry = dictionary_iter->second; + if (entry->mName == name) + { + return dictionary_iter->first; + } + } + return notFound(); + } protected: - virtual Index notFound() const - { - // default is to assert - // don't assert -- makes it impossible to work on mesh-development and viewer-development simultaneously - // -- davep 2010.10.29 - //llassert(false); - return Index(-1); - } - void addEntry(Index index, Entry *entry) - { - if (!this->emplace(index, entry).second) - { - LL_ERRS() << "Dictionary entry already added (attempted to add duplicate entry)" << LL_ENDL; - } - } + virtual Index notFound() const + { + // default is to assert + // don't assert -- makes it impossible to work on mesh-development and viewer-development simultaneously + // -- davep 2010.10.29 + //llassert(false); + return Index(-1); + } + void addEntry(Index index, Entry *entry) + { + if (!this->emplace(index, entry).second) + { + LL_ERRS() << "Dictionary entry already added (attempted to add duplicate entry)" << LL_ENDL; + } + } }; #endif // LL_LLDICTIONARY_H diff --git a/indra/llcommon/lldoubledispatch.h b/indra/llcommon/lldoubledispatch.h index ce6731e864..c8c566205a 100644 --- a/indra/llcommon/lldoubledispatch.h +++ b/indra/llcommon/lldoubledispatch.h @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2008-11-11 * @brief function calls virtual on more than one parameter - * + * * $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$ */ @@ -41,7 +41,7 @@ * subset of that problem: function calls which accept two parameters, and * select which particular function to call depending on the dynamic type of * both. - * + * * Scott Meyers, in More Effective C++ (Item 31), talks about some of the perils * and pitfalls lurking down this pathway. He discusses and dismisses the * straightforward approaches of using single-dispatch virtual functions twice, @@ -50,17 +50,17 @@ * look up the actual types of both parameters (he uses the classes' string names, * via typeid(param).name()) to obtain a pointer to a free (non-member) function * that will accept this pair of parameters. - * + * * He does point out that his approach doesn't handle inheritance. If you have a * registry entry for SpaceShip, and you have in hand a MilitaryShip (subclass of * SpaceShip) and an Asteroid, you'd like to call the function appropriate for * SpaceShips and Asteroids -- but alas, his lookup fails because the class name * for your MilitaryShip subclass isn't in the registry. - * + * * This class extends his idea to build a registry whose entries can examine the * dynamic type of the parameter in a more flexible way -- using dynamic_cast<> * -- thereby supporting inheritance relationships. - * + * * Of course we must allow for the ambiguity this permits. We choose to use a * sequence container rather than a map, and require that the client code * specify the order in which dispatch-table entries should be searched. The @@ -69,7 +69,7 @@ * you catch ErrorBaseClass before you catch ErrorSubclass, then any * ErrorSubclass exceptions thrown by the protected code will always match * ErrorBaseClass, and you will never reach your catch(ErrorSubclass) clause. - * + * * So, in a similar way, if you have a specific routine to process * MilitaryShip and Asteroid, you'd better place that in the table @em before * your more general routine that processes SpaceShip and Asteroid, or else @@ -279,7 +279,7 @@ private: /// Look up the first matching entry. EntryPtr lookup(const ParamBaseType& param1, const ParamBaseType& param2) const { - typename DispatchTable::const_iterator found = find(param1, param2); + typename DispatchTable::const_iterator found = find(param1, param2); if (found != mDispatch.end()) { // Dereferencing the list iterator gets us an EntryPtr diff --git a/indra/llcommon/llendianswizzle.h b/indra/llcommon/llendianswizzle.h index 4c08074a9c..d56eb7be2e 100644 --- a/indra/llcommon/llendianswizzle.h +++ b/indra/llcommon/llendianswizzle.h @@ -1,25 +1,25 @@ -/** +/** * @file llendianswizzle.h * @brief Functions for in-place bit swizzling * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -28,63 +28,63 @@ #define LL_LLENDIANSWIZZLE_H /* This function is intended to be used for in-place swizzling, particularly after fread() of - binary values from a file. Such as: - - numRead = fread(scale.mV, sizeof(float), 3, fp); - llendianswizzle(scale.mV, sizeof(float), 3); - - It assumes that the values in the file are LITTLE endian, so it's a no-op on a little endian machine. - - It keys off of typesize to do the correct swizzle, so make sure that typesize is the size of the native type. - - 64-bit types are not yet handled. + binary values from a file. Such as: + + numRead = fread(scale.mV, sizeof(float), 3, fp); + llendianswizzle(scale.mV, sizeof(float), 3); + + It assumes that the values in the file are LITTLE endian, so it's a no-op on a little endian machine. + + It keys off of typesize to do the correct swizzle, so make sure that typesize is the size of the native type. + + 64-bit types are not yet handled. */ #ifdef LL_LITTLE_ENDIAN - // little endian is native for most things. - inline void llendianswizzle(void *,int,int) - { - // Nothing to do - } + // little endian is native for most things. + inline void llendianswizzle(void *,int,int) + { + // Nothing to do + } #endif #ifdef LL_BIG_ENDIAN - // big endian requires a bit of work. - inline void llendianswizzle(void *p,int typesize, int count) - { - int i; - switch(typesize) - { - case 2: - { - U16 temp; - for(i=count ;i!=0 ;i--) - { - temp = ((U16*)p)[0]; - ((U16*)p)[0] = ((temp >> 8) & 0x000000FF) | ((temp << 8) & 0x0000FF00); - p = (void*)(((U16*)p) + 1); - } - } - break; - - case 4: - { - U32 temp; - for(i=count; i!=0; i--) - { - temp = ((U32*)p)[0]; - ((U32*)p)[0] = - ((temp >> 24) & 0x000000FF) | - ((temp >> 8) & 0x0000FF00) | - ((temp << 8) & 0x00FF0000) | - ((temp << 24) & 0xFF000000); - p = (void*)(((U32*)p) + 1); - } - } - break; - } - - } + // big endian requires a bit of work. + inline void llendianswizzle(void *p,int typesize, int count) + { + int i; + switch(typesize) + { + case 2: + { + U16 temp; + for(i=count ;i!=0 ;i--) + { + temp = ((U16*)p)[0]; + ((U16*)p)[0] = ((temp >> 8) & 0x000000FF) | ((temp << 8) & 0x0000FF00); + p = (void*)(((U16*)p) + 1); + } + } + break; + + case 4: + { + U32 temp; + for(i=count; i!=0; i--) + { + temp = ((U32*)p)[0]; + ((U32*)p)[0] = + ((temp >> 24) & 0x000000FF) | + ((temp >> 8) & 0x0000FF00) | + ((temp << 8) & 0x00FF0000) | + ((temp << 24) & 0xFF000000); + p = (void*)(((U32*)p) + 1); + } + } + break; + } + + } #endif // Use this when working with a single integral value you want swizzled diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp index 0f48ce16b2..e4843a88eb 100644 --- a/indra/llcommon/llerror.cpp +++ b/indra/llcommon/llerror.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llerror.cpp * @date December 2006 * @brief error message system @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -65,91 +65,91 @@ namespace { #if LL_WINDOWS - void debugger_print(const std::string& s) - { - // Be careful when calling OutputDebugString as it throws DBG_PRINTEXCEPTION_C - // which works just fine under the windows debugger, but can cause users who - // have enabled SEHOP exception chain validation to crash due to interactions - // between the Win 32-bit exception handling and boost coroutine fiber stacks. BUG-2707 - // - if (IsDebuggerPresent()) - { - // Need UTF16 for Unicode OutputDebugString - // - if (s.size()) - { - OutputDebugString(utf8str_to_utf16str(s).c_str()); - OutputDebugString(TEXT("\n")); - } - } - } + void debugger_print(const std::string& s) + { + // Be careful when calling OutputDebugString as it throws DBG_PRINTEXCEPTION_C + // which works just fine under the windows debugger, but can cause users who + // have enabled SEHOP exception chain validation to crash due to interactions + // between the Win 32-bit exception handling and boost coroutine fiber stacks. BUG-2707 + // + if (IsDebuggerPresent()) + { + // Need UTF16 for Unicode OutputDebugString + // + if (s.size()) + { + OutputDebugString(utf8str_to_utf16str(s).c_str()); + OutputDebugString(TEXT("\n")); + } + } + } #else - class RecordToSyslog : public LLError::Recorder - { - public: - RecordToSyslog(const std::string& identity) - : mIdentity(identity) - { - openlog(mIdentity.c_str(), LOG_CONS|LOG_PID, LOG_LOCAL0); - // we need to set the string from a local copy of the string - // since apparanetly openlog expects the const char* to remain - // valid even after it returns (presumably until closelog) - } - - ~RecordToSyslog() - { - closelog(); - } + class RecordToSyslog : public LLError::Recorder + { + public: + RecordToSyslog(const std::string& identity) + : mIdentity(identity) + { + openlog(mIdentity.c_str(), LOG_CONS|LOG_PID, LOG_LOCAL0); + // we need to set the string from a local copy of the string + // since apparanetly openlog expects the const char* to remain + // valid even after it returns (presumably until closelog) + } + + ~RecordToSyslog() + { + closelog(); + } virtual bool enabled() override { return LLError::getEnabledLogTypesMask() & 0x01; } - - virtual void recordMessage(LLError::ELevel level, - const std::string& message) override - { + + virtual void recordMessage(LLError::ELevel level, + const std::string& message) override + { LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING - int syslogPriority = LOG_CRIT; - switch (level) { - case LLError::LEVEL_DEBUG: syslogPriority = LOG_DEBUG; break; - case LLError::LEVEL_INFO: syslogPriority = LOG_INFO; break; - case LLError::LEVEL_WARN: syslogPriority = LOG_WARNING; break; - case LLError::LEVEL_ERROR: syslogPriority = LOG_CRIT; break; - default: syslogPriority = LOG_CRIT; - } - - syslog(syslogPriority, "%s", message.c_str()); - } - private: - std::string mIdentity; - }; + int syslogPriority = LOG_CRIT; + switch (level) { + case LLError::LEVEL_DEBUG: syslogPriority = LOG_DEBUG; break; + case LLError::LEVEL_INFO: syslogPriority = LOG_INFO; break; + case LLError::LEVEL_WARN: syslogPriority = LOG_WARNING; break; + case LLError::LEVEL_ERROR: syslogPriority = LOG_CRIT; break; + default: syslogPriority = LOG_CRIT; + } + + syslog(syslogPriority, "%s", message.c_str()); + } + private: + std::string mIdentity; + }; #endif - class RecordToFile : public LLError::Recorder - { - public: - RecordToFile(const std::string& filename): - mName(filename) - { - mFile.open(filename.c_str(), std::ios_base::out | std::ios_base::app); - if (!mFile) - { - LL_INFOS() << "Error setting log file to " << filename << LL_ENDL; - } - else - { - if (!LLError::getAlwaysFlush()) - { - mFile.sync_with_stdio(false); - } - } - } - - ~RecordToFile() - { - mFile.close(); - } + class RecordToFile : public LLError::Recorder + { + public: + RecordToFile(const std::string& filename): + mName(filename) + { + mFile.open(filename.c_str(), std::ios_base::out | std::ios_base::app); + if (!mFile) + { + LL_INFOS() << "Error setting log file to " << filename << LL_ENDL; + } + else + { + if (!LLError::getAlwaysFlush()) + { + mFile.sync_with_stdio(false); + } + } + } + + ~RecordToFile() + { + mFile.close(); + } virtual bool enabled() override { @@ -159,7 +159,7 @@ namespace { return LLError::getEnabledLogTypesMask() & 0x02; #endif } - + bool okay() const { return mFile.good(); } std::string getFilename() const { return mName; } @@ -178,25 +178,25 @@ namespace { } } - private: - const std::string mName; - llofstream mFile; - }; - - - class RecordToStderr : public LLError::Recorder - { - public: - RecordToStderr(bool timestamp) : mUseANSI(checkANSI()) - { + private: + const std::string mName; + llofstream mFile; + }; + + + class RecordToStderr : public LLError::Recorder + { + public: + RecordToStderr(bool timestamp) : mUseANSI(checkANSI()) + { this->showMultiline(true); - } - + } + virtual bool enabled() override { return LLError::getEnabledLogTypesMask() & 0x04; } - + LL_FORCE_INLINE std::string createBoldANSI() { std::string ansi_code; @@ -231,12 +231,12 @@ namespace { return ansi_code; } - virtual void recordMessage(LLError::ELevel level, - const std::string& message) override - { + virtual void recordMessage(LLError::ELevel level, + const std::string& message) override + { LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING // The default colors for error, warn and debug are now a bit more pastel - // and easier to read on the default (black) terminal background but you + // and easier to read on the default (black) terminal background but you // now have the option to set the color of each via an environment variables: // LL_ANSI_ERROR_COLOR_CODE (default is red) // LL_ANSI_WARN_COLOR_CODE (default is blue) @@ -256,75 +256,75 @@ namespace { static std::string s_ansi_warn = createANSI(s_ansi_warn_code); // default is blue static std::string s_ansi_debug = createANSI(s_ansi_debug_code); // default is magenta - if (mUseANSI) - { + if (mUseANSI) + { writeANSI((level == LLError::LEVEL_ERROR) ? s_ansi_error : (level == LLError::LEVEL_WARN) ? s_ansi_warn : s_ansi_debug, message); - } + } else { LL_PROFILE_ZONE_NAMED("fprintf"); fprintf(stderr, "%s\n", message.c_str()); } - } - - private: - bool mUseANSI; + } + + private: + bool mUseANSI; LL_FORCE_INLINE void writeANSI(const std::string& ansi_code, const std::string& message) - { + { LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING static std::string s_ansi_bold = createBoldANSI(); // bold text static std::string s_ansi_reset = createResetANSI(); // reset - // ANSI color code escape sequence, message, and reset in one fprintf call + // ANSI color code escape sequence, message, and reset in one fprintf call // Default all message levels to bold so we can distinguish our own messages from those dumped by subprocesses and libraries. - fprintf(stderr, "%s%s\n%s", ansi_code.c_str(), message.c_str(), s_ansi_reset.c_str() ); - } - - static bool checkANSI(void) - { - // Check whether it's okay to use ANSI; if stderr is - // a tty then we assume yes. Can be turned off with - // the LL_NO_ANSI_COLOR env var. - return (0 != isatty(2)) && - (NULL == getenv("LL_NO_ANSI_COLOR")); - } - }; - - class RecordToFixedBuffer : public LLError::Recorder - { - public: - RecordToFixedBuffer(LLLineBuffer* buffer) + fprintf(stderr, "%s%s\n%s", ansi_code.c_str(), message.c_str(), s_ansi_reset.c_str() ); + } + + static bool checkANSI(void) + { + // Check whether it's okay to use ANSI; if stderr is + // a tty then we assume yes. Can be turned off with + // the LL_NO_ANSI_COLOR env var. + return (0 != isatty(2)) && + (NULL == getenv("LL_NO_ANSI_COLOR")); + } + }; + + class RecordToFixedBuffer : public LLError::Recorder + { + public: + RecordToFixedBuffer(LLLineBuffer* buffer) : mBuffer(buffer) { this->showMultiline(true); this->showTags(false); this->showLocation(false); } - + virtual bool enabled() override { return LLError::getEnabledLogTypesMask() & 0x08; } - - virtual void recordMessage(LLError::ELevel level, - const std::string& message) override - { + + virtual void recordMessage(LLError::ELevel level, + const std::string& message) override + { LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING - mBuffer->addLine(message); - } - - private: - LLLineBuffer* mBuffer; - }; + mBuffer->addLine(message); + } + + private: + LLLineBuffer* mBuffer; + }; #if LL_WINDOWS - class RecordToWinDebug: public LLError::Recorder - { - public: - RecordToWinDebug() - { + class RecordToWinDebug: public LLError::Recorder + { + public: + RecordToWinDebug() + { this->showMultiline(true); this->showTags(false); this->showLocation(false); @@ -334,154 +334,154 @@ namespace { { return LLError::getEnabledLogTypesMask() & 0x10; } - - virtual void recordMessage(LLError::ELevel level, - const std::string& message) override - { + + virtual void recordMessage(LLError::ELevel level, + const std::string& message) override + { LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING - debugger_print(message); - } - }; + debugger_print(message); + } + }; #endif } namespace { - std::string className(const std::type_info& type) - { - return LLError::Log::demangle(type.name()); - } + std::string className(const std::type_info& type) + { + return LLError::Log::demangle(type.name()); + } } // anonymous namespace LLError { - std::string Log::demangle(const char* mangled) - { + std::string Log::demangle(const char* mangled) + { #ifdef __GNUC__ - // GCC: type_info::name() returns a mangled class name,st demangle - // passing nullptr, 0 forces allocation of a unique buffer we can free - // fixing MAINT-8724 on OSX 10.14 - int status = -1; - char* name = abi::__cxa_demangle(mangled, nullptr, 0, &status); - std::string result(name ? name : mangled); - free(name); - return result; + // GCC: type_info::name() returns a mangled class name,st demangle + // passing nullptr, 0 forces allocation of a unique buffer we can free + // fixing MAINT-8724 on OSX 10.14 + int status = -1; + char* name = abi::__cxa_demangle(mangled, nullptr, 0, &status); + std::string result(name ? name : mangled); + free(name); + return result; #elif LL_WINDOWS - // Visual Studio: type_info::name() includes the text "class " at the start - std::string name = mangled; - for (const auto& prefix : std::vector{ "class ", "struct " }) - { - if (0 == name.compare(0, prefix.length(), prefix)) - { - return name.substr(prefix.length()); - } - } - // huh, that's odd, we should see one or the other prefix -- but don't - // try to log unless logging is already initialized - // in Python, " or ".join(vector) -- but in C++, a PITB - LL_DEBUGS() << "Did not see 'class' or 'struct' prefix on '" - << name << "'" << LL_ENDL; - return name; + // Visual Studio: type_info::name() includes the text "class " at the start + std::string name = mangled; + for (const auto& prefix : std::vector{ "class ", "struct " }) + { + if (0 == name.compare(0, prefix.length(), prefix)) + { + return name.substr(prefix.length()); + } + } + // huh, that's odd, we should see one or the other prefix -- but don't + // try to log unless logging is already initialized + // in Python, " or ".join(vector) -- but in C++, a PITB + LL_DEBUGS() << "Did not see 'class' or 'struct' prefix on '" + << name << "'" << LL_ENDL; + return name; #else // neither GCC nor Visual Studio - return mangled; + return mangled; #endif - } + } } // LLError namespace { - std::string functionName(const std::string& preprocessor_name) - { + std::string functionName(const std::string& preprocessor_name) + { #if LL_WINDOWS - // DevStudio: the __FUNCTION__ macro string includes - // the type and/or namespace prefixes + // DevStudio: the __FUNCTION__ macro string includes + // the type and/or namespace prefixes - std::string::size_type p = preprocessor_name.rfind(':'); - if (p == std::string::npos) - { - return preprocessor_name; - } - return preprocessor_name.substr(p + 1); + std::string::size_type p = preprocessor_name.rfind(':'); + if (p == std::string::npos) + { + return preprocessor_name; + } + return preprocessor_name.substr(p + 1); #else - return preprocessor_name; + return preprocessor_name; #endif - } - - - class LogControlFile : public LLLiveFile - { - LOG_CLASS(LogControlFile); - - public: - static LogControlFile& fromDirectory(const std::string& user_dir, const std::string& app_dir); - - virtual bool loadFile(); - - private: - LogControlFile(const std::string &filename) - : LLLiveFile(filename) - { } - }; - - LogControlFile& LogControlFile::fromDirectory(const std::string& user_dir, const std::string& app_dir) - { + } + + + class LogControlFile : public LLLiveFile + { + LOG_CLASS(LogControlFile); + + public: + static LogControlFile& fromDirectory(const std::string& user_dir, const std::string& app_dir); + + virtual bool loadFile(); + + private: + LogControlFile(const std::string &filename) + : LLLiveFile(filename) + { } + }; + + LogControlFile& LogControlFile::fromDirectory(const std::string& user_dir, const std::string& app_dir) + { // NB: We have no abstraction in llcommon for the "proper" // delimiter but it turns out that "/" works on all three platforms - - std::string file = user_dir + "/logcontrol-dev.xml"; - - llstat stat_info; - if (LLFile::stat(file, &stat_info)) { - // NB: stat returns non-zero if it can't read the file, for example - // if it doesn't exist. LLFile has no better abstraction for - // testing for file existence. - - file = app_dir + "/logcontrol.xml"; - } - return * new LogControlFile(file); - // NB: This instance is never freed - } - - bool LogControlFile::loadFile() - { - LLSD configuration; - - { - llifstream file(filename().c_str()); - if (!file.is_open()) - { - LL_WARNS() << filename() << " failed to open file; not changing configuration" << LL_ENDL; - return false; - } - - if (LLSDSerialize::fromXML(configuration, file) == LLSDParser::PARSE_FAILURE) - { - LL_WARNS() << filename() << " parcing error; not changing configuration" << LL_ENDL; - return false; - } - - if (! configuration || !configuration.isMap()) - { - LL_WARNS() << filename() << " missing, ill-formed, or simply undefined" - " content; not changing configuration" - << LL_ENDL; - return false; - } - } - - LLError::configure(configuration); - LL_INFOS("LogControlFile") << "logging reconfigured from " << filename() << LL_ENDL; - return true; - } - - - typedef std::map LevelMap; - typedef std::vector Recorders; - typedef std::vector CallSiteVector; + + std::string file = user_dir + "/logcontrol-dev.xml"; + + llstat stat_info; + if (LLFile::stat(file, &stat_info)) { + // NB: stat returns non-zero if it can't read the file, for example + // if it doesn't exist. LLFile has no better abstraction for + // testing for file existence. + + file = app_dir + "/logcontrol.xml"; + } + return * new LogControlFile(file); + // NB: This instance is never freed + } + + bool LogControlFile::loadFile() + { + LLSD configuration; + + { + llifstream file(filename().c_str()); + if (!file.is_open()) + { + LL_WARNS() << filename() << " failed to open file; not changing configuration" << LL_ENDL; + return false; + } + + if (LLSDSerialize::fromXML(configuration, file) == LLSDParser::PARSE_FAILURE) + { + LL_WARNS() << filename() << " parcing error; not changing configuration" << LL_ENDL; + return false; + } + + if (! configuration || !configuration.isMap()) + { + LL_WARNS() << filename() << " missing, ill-formed, or simply undefined" + " content; not changing configuration" + << LL_ENDL; + return false; + } + } + + LLError::configure(configuration); + LL_INFOS("LogControlFile") << "logging reconfigured from " << filename() << LL_ENDL; + return true; + } + + + typedef std::map LevelMap; + typedef std::vector Recorders; + typedef std::vector CallSiteVector; class SettingsConfig : public LLRefCount { @@ -492,9 +492,9 @@ namespace LLError::ELevel mDefaultLevel; - bool mLogAlwaysFlush; + bool mLogAlwaysFlush; - U32 mEnabledLogTypesMask; + U32 mEnabledLogTypesMask; LevelMap mFunctionLevelMap; LevelMap mClassLevelMap; @@ -539,34 +539,34 @@ namespace mRecorders.clear(); } - class Globals - { + class Globals + { public: static Globals* getInstance(); protected: - Globals(); - public: - std::string mFatalMessage; + Globals(); + public: + std::string mFatalMessage; - void addCallSite(LLError::CallSite&); - void invalidateCallSites(); + void addCallSite(LLError::CallSite&); + void invalidateCallSites(); SettingsConfigPtr getSettingsConfig(); void resetSettingsConfig(); LLError::SettingsStoragePtr saveAndResetSettingsConfig(); void restore(LLError::SettingsStoragePtr pSettingsStorage); - private: - CallSiteVector callSites; + private: + CallSiteVector callSites; SettingsConfigPtr mSettingsConfig; - }; + }; - Globals::Globals() - : - callSites(), + Globals::Globals() + : + callSites(), mSettingsConfig(new SettingsConfig()) - { - } + { + } Globals* Globals::getInstance() @@ -579,20 +579,20 @@ namespace return &inst; } - void Globals::addCallSite(LLError::CallSite& site) - { - callSites.push_back(&site); - } - - void Globals::invalidateCallSites() - { - for (LLError::CallSite* site : callSites) - { + void Globals::addCallSite(LLError::CallSite& site) + { + callSites.push_back(&site); + } + + void Globals::invalidateCallSites() + { + for (LLError::CallSite* site : callSites) + { site->invalidate(); - } - - callSites.clear(); - } + } + + callSites.clear(); + } SettingsConfigPtr Globals::getSettingsConfig() { @@ -622,77 +622,77 @@ namespace namespace LLError { - CallSite::CallSite(ELevel level, - const char* file, - int line, - const std::type_info& class_info, - const char* function, - bool printOnce, - const char** tags, - size_t tag_count) - : mLevel(level), - mFile(file), - mLine(line), - mClassInfo(class_info), - mFunction(function), - mCached(false), - mShouldLog(false), - mPrintOnce(printOnce), - mTags(new const char* [tag_count]), - mTagCount(tag_count) - { - switch (mLevel) - { + CallSite::CallSite(ELevel level, + const char* file, + int line, + const std::type_info& class_info, + const char* function, + bool printOnce, + const char** tags, + size_t tag_count) + : mLevel(level), + mFile(file), + mLine(line), + mClassInfo(class_info), + mFunction(function), + mCached(false), + mShouldLog(false), + mPrintOnce(printOnce), + mTags(new const char* [tag_count]), + mTagCount(tag_count) + { + switch (mLevel) + { case LEVEL_DEBUG: mLevelString = "DEBUG"; break; case LEVEL_INFO: mLevelString = "INFO"; break; case LEVEL_WARN: mLevelString = "WARNING"; break; case LEVEL_ERROR: mLevelString = "ERROR"; break; default: mLevelString = "XXX"; break; - }; + }; - mLocationString = llformat("%s(%d)", abbreviateFile(mFile).c_str(), mLine); + mLocationString = llformat("%s(%d)", abbreviateFile(mFile).c_str(), mLine); #if LL_WINDOWS - // DevStudio: __FUNCTION__ already includes the full class name + // DevStudio: __FUNCTION__ already includes the full class name #else #if LL_LINUX - // gross, but typeid comparison seems to always fail here with gcc4.1 - if (0 != strcmp(mClassInfo.name(), typeid(NoClassInfo).name())) + // gross, but typeid comparison seems to always fail here with gcc4.1 + if (0 != strcmp(mClassInfo.name(), typeid(NoClassInfo).name())) #else - if (mClassInfo != typeid(NoClassInfo)) + if (mClassInfo != typeid(NoClassInfo)) #endif // LL_LINUX - { - mFunctionString = className(mClassInfo) + "::"; - } + { + mFunctionString = className(mClassInfo) + "::"; + } #endif - mFunctionString += std::string(mFunction); + mFunctionString += std::string(mFunction); - for (int i = 0; i < tag_count; i++) - { + for (int i = 0; i < tag_count; i++) + { if (strchr(tags[i], ' ')) { LL_ERRS() << "Space is not allowed in a log tag at " << mLocationString << LL_ENDL; } - mTags[i] = tags[i]; - } + mTags[i] = tags[i]; + } mTagString.append("#"); // always construct a tag sequence; will be just a single # if no tag - for (size_t i = 0; i < mTagCount; i++) - { - mTagString.append(mTags[i]); + for (size_t i = 0; i < mTagCount; i++) + { + mTagString.append(mTags[i]); mTagString.append("#"); - } - } - - CallSite::~CallSite() - { - delete []mTags; - } - - void CallSite::invalidate() - { - mCached = false; - } + } + } + + CallSite::~CallSite() + { + delete []mTags; + } + + void CallSite::invalidate() + { + mCached = false; + } } namespace @@ -729,202 +729,202 @@ namespace #endif } - bool stderrLogWantsTime() - { + bool stderrLogWantsTime() + { #if LL_WINDOWS - return false; + return false; #else - return true; + return true; #endif - } - - - void commonInit(const std::string& user_dir, const std::string& app_dir, bool log_to_stderr = true) - { - Globals::getInstance()->resetSettingsConfig(); - - LLError::setDefaultLevel(LLError::LEVEL_INFO); - LLError::setAlwaysFlush(true); - LLError::setEnabledLogTypesMask(0xFFFFFFFF); - LLError::setTimeFunction(LLError::utcTime); - - // log_to_stderr is only false in the unit and integration tests to keep builds quieter - if (log_to_stderr && shouldLogToStderr()) - { - LLError::logToStderr(); - } + } + + + void commonInit(const std::string& user_dir, const std::string& app_dir, bool log_to_stderr = true) + { + Globals::getInstance()->resetSettingsConfig(); + + LLError::setDefaultLevel(LLError::LEVEL_INFO); + LLError::setAlwaysFlush(true); + LLError::setEnabledLogTypesMask(0xFFFFFFFF); + LLError::setTimeFunction(LLError::utcTime); + + // log_to_stderr is only false in the unit and integration tests to keep builds quieter + if (log_to_stderr && shouldLogToStderr()) + { + LLError::logToStderr(); + } #if LL_WINDOWS - LLError::RecorderPtr recordToWinDebug(new RecordToWinDebug()); - LLError::addRecorder(recordToWinDebug); + LLError::RecorderPtr recordToWinDebug(new RecordToWinDebug()); + LLError::addRecorder(recordToWinDebug); #endif - LogControlFile& e = LogControlFile::fromDirectory(user_dir, app_dir); - - // NOTE: We want to explicitly load the file before we add it to the event timer - // that checks for changes to the file. Else, we're not actually loading the file yet, - // and most of the initialization happens without any attention being paid to the - // log control file. Not to mention that when it finally gets checked later, - // all log statements that have been evaluated already become dirty and need to be - // evaluated for printing again. So, make sure to call checkAndReload() - // before addToEventTimer(). - e.checkAndReload(); - e.addToEventTimer(); - } + LogControlFile& e = LogControlFile::fromDirectory(user_dir, app_dir); + + // NOTE: We want to explicitly load the file before we add it to the event timer + // that checks for changes to the file. Else, we're not actually loading the file yet, + // and most of the initialization happens without any attention being paid to the + // log control file. Not to mention that when it finally gets checked later, + // all log statements that have been evaluated already become dirty and need to be + // evaluated for printing again. So, make sure to call checkAndReload() + // before addToEventTimer(). + e.checkAndReload(); + e.addToEventTimer(); + } } namespace LLError { - void initForApplication(const std::string& user_dir, const std::string& app_dir, bool log_to_stderr) - { - commonInit(user_dir, app_dir, log_to_stderr); - } - - void setFatalFunction(const FatalFunction& f) - { - SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); - s->mCrashFunction = f; - } - - FatalFunction getFatalFunction() - { - SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); - return s->mCrashFunction; - } - - std::string getFatalMessage() - { - return Globals::getInstance()->mFatalMessage; - } - - void setTimeFunction(TimeFunction f) - { - SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); - s->mTimeFunction = f; - } - - void setDefaultLevel(ELevel level) - { - Globals *g = Globals::getInstance(); - g->invalidateCallSites(); - SettingsConfigPtr s = g->getSettingsConfig(); - s->mDefaultLevel = level; - } - - ELevel getDefaultLevel() - { - SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); - return s->mDefaultLevel; - } - - void setAlwaysFlush(bool flush) - { - SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); - s->mLogAlwaysFlush = flush; - } - - bool getAlwaysFlush() - { - SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); - return s->mLogAlwaysFlush; - } - - void setEnabledLogTypesMask(U32 mask) - { - SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); - s->mEnabledLogTypesMask = mask; - } - - U32 getEnabledLogTypesMask() - { - SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); - return s->mEnabledLogTypesMask; - } - - void setFunctionLevel(const std::string& function_name, ELevel level) - { - Globals *g = Globals::getInstance(); - g->invalidateCallSites(); - SettingsConfigPtr s = g->getSettingsConfig(); - s->mFunctionLevelMap[function_name] = level; - } - - void setClassLevel(const std::string& class_name, ELevel level) - { - Globals *g = Globals::getInstance(); - g->invalidateCallSites(); - SettingsConfigPtr s = g->getSettingsConfig(); - s->mClassLevelMap[class_name] = level; - } - - void setFileLevel(const std::string& file_name, ELevel level) - { - Globals *g = Globals::getInstance(); - g->invalidateCallSites(); - SettingsConfigPtr s = g->getSettingsConfig(); - s->mFileLevelMap[file_name] = level; - } - - void setTagLevel(const std::string& tag_name, ELevel level) - { - Globals *g = Globals::getInstance(); - g->invalidateCallSites(); - SettingsConfigPtr s = g->getSettingsConfig(); - s->mTagLevelMap[tag_name] = level; - } - - LLError::ELevel decodeLevel(std::string name) - { - static LevelMap level_names; - if (level_names.empty()) - { - level_names["ALL"] = LLError::LEVEL_ALL; - level_names["DEBUG"] = LLError::LEVEL_DEBUG; - level_names["INFO"] = LLError::LEVEL_INFO; - level_names["WARN"] = LLError::LEVEL_WARN; - level_names["ERROR"] = LLError::LEVEL_ERROR; - level_names["NONE"] = LLError::LEVEL_NONE; - } - - std::transform(name.begin(), name.end(), name.begin(), toupper); - - LevelMap::const_iterator i = level_names.find(name); - if (i == level_names.end()) - { - LL_WARNS() << "unrecognized logging level: '" << name << "'" << LL_ENDL; - return LLError::LEVEL_INFO; - } - - return i->second; - } + void initForApplication(const std::string& user_dir, const std::string& app_dir, bool log_to_stderr) + { + commonInit(user_dir, app_dir, log_to_stderr); + } + + void setFatalFunction(const FatalFunction& f) + { + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); + s->mCrashFunction = f; + } + + FatalFunction getFatalFunction() + { + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); + return s->mCrashFunction; + } + + std::string getFatalMessage() + { + return Globals::getInstance()->mFatalMessage; + } + + void setTimeFunction(TimeFunction f) + { + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); + s->mTimeFunction = f; + } + + void setDefaultLevel(ELevel level) + { + Globals *g = Globals::getInstance(); + g->invalidateCallSites(); + SettingsConfigPtr s = g->getSettingsConfig(); + s->mDefaultLevel = level; + } + + ELevel getDefaultLevel() + { + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); + return s->mDefaultLevel; + } + + void setAlwaysFlush(bool flush) + { + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); + s->mLogAlwaysFlush = flush; + } + + bool getAlwaysFlush() + { + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); + return s->mLogAlwaysFlush; + } + + void setEnabledLogTypesMask(U32 mask) + { + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); + s->mEnabledLogTypesMask = mask; + } + + U32 getEnabledLogTypesMask() + { + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); + return s->mEnabledLogTypesMask; + } + + void setFunctionLevel(const std::string& function_name, ELevel level) + { + Globals *g = Globals::getInstance(); + g->invalidateCallSites(); + SettingsConfigPtr s = g->getSettingsConfig(); + s->mFunctionLevelMap[function_name] = level; + } + + void setClassLevel(const std::string& class_name, ELevel level) + { + Globals *g = Globals::getInstance(); + g->invalidateCallSites(); + SettingsConfigPtr s = g->getSettingsConfig(); + s->mClassLevelMap[class_name] = level; + } + + void setFileLevel(const std::string& file_name, ELevel level) + { + Globals *g = Globals::getInstance(); + g->invalidateCallSites(); + SettingsConfigPtr s = g->getSettingsConfig(); + s->mFileLevelMap[file_name] = level; + } + + void setTagLevel(const std::string& tag_name, ELevel level) + { + Globals *g = Globals::getInstance(); + g->invalidateCallSites(); + SettingsConfigPtr s = g->getSettingsConfig(); + s->mTagLevelMap[tag_name] = level; + } + + LLError::ELevel decodeLevel(std::string name) + { + static LevelMap level_names; + if (level_names.empty()) + { + level_names["ALL"] = LLError::LEVEL_ALL; + level_names["DEBUG"] = LLError::LEVEL_DEBUG; + level_names["INFO"] = LLError::LEVEL_INFO; + level_names["WARN"] = LLError::LEVEL_WARN; + level_names["ERROR"] = LLError::LEVEL_ERROR; + level_names["NONE"] = LLError::LEVEL_NONE; + } + + std::transform(name.begin(), name.end(), name.begin(), toupper); + + LevelMap::const_iterator i = level_names.find(name); + if (i == level_names.end()) + { + LL_WARNS() << "unrecognized logging level: '" << name << "'" << LL_ENDL; + return LLError::LEVEL_INFO; + } + + return i->second; + } } namespace { - void setLevels(LevelMap& map, const LLSD& list, LLError::ELevel level) - { - LLSD::array_const_iterator i, end; - for (i = list.beginArray(), end = list.endArray(); i != end; ++i) - { - map[*i] = level; - } - } + void setLevels(LevelMap& map, const LLSD& list, LLError::ELevel level) + { + LLSD::array_const_iterator i, end; + for (i = list.beginArray(), end = list.endArray(); i != end; ++i) + { + map[*i] = level; + } + } } namespace LLError { - void configure(const LLSD& config) - { - Globals *g = Globals::getInstance(); - g->invalidateCallSites(); - SettingsConfigPtr s = g->getSettingsConfig(); - - s->mFunctionLevelMap.clear(); - s->mClassLevelMap.clear(); - s->mFileLevelMap.clear(); - s->mTagLevelMap.clear(); - s->mUniqueLogMessages.clear(); - - setDefaultLevel(decodeLevel(config["default-level"])); + void configure(const LLSD& config) + { + Globals *g = Globals::getInstance(); + g->invalidateCallSites(); + SettingsConfigPtr s = g->getSettingsConfig(); + + s->mFunctionLevelMap.clear(); + s->mClassLevelMap.clear(); + s->mFileLevelMap.clear(); + s->mTagLevelMap.clear(); + s->mUniqueLogMessages.clear(); + + setDefaultLevel(decodeLevel(config["default-level"])); if (config.has("log-always-flush")) { setAlwaysFlush(config["log-always-flush"]); @@ -933,7 +933,7 @@ namespace LLError { setEnabledLogTypesMask(config["enabled-log-types-mask"].asInteger()); } - + if (config.has("settings") && config["settings"].isArray()) { LLSD sets = config["settings"]; @@ -952,66 +952,66 @@ namespace LLError } } } - } + } } namespace LLError { - Recorder::Recorder() - : mWantsTime(true) + Recorder::Recorder() + : mWantsTime(true) , mWantsTags(true) , mWantsLevel(true) , mWantsLocation(true) , mWantsFunctionName(true) , mWantsMultiline(false) - { - } - - Recorder::~Recorder() - { - } - - bool Recorder::wantsTime() - { - return mWantsTime; - } - - // virtual - bool Recorder::wantsTags() - { - return mWantsTags; - } - - // virtual - bool Recorder::wantsLevel() - { - return mWantsLevel; - } - - // virtual - bool Recorder::wantsLocation() - { - return mWantsLocation; - } - - // virtual - bool Recorder::wantsFunctionName() - { - return mWantsFunctionName; - } - - // virtual - bool Recorder::wantsMultiline() - { - return mWantsMultiline; - } + { + } + + Recorder::~Recorder() + { + } + + bool Recorder::wantsTime() + { + return mWantsTime; + } + + // virtual + bool Recorder::wantsTags() + { + return mWantsTags; + } + + // virtual + bool Recorder::wantsLevel() + { + return mWantsLevel; + } + + // virtual + bool Recorder::wantsLocation() + { + return mWantsLocation; + } + + // virtual + bool Recorder::wantsFunctionName() + { + return mWantsFunctionName; + } + + // virtual + bool Recorder::wantsMultiline() + { + return mWantsMultiline; + } void Recorder::showTime(bool show) { mWantsTime = show; } - + void Recorder::showTags(bool show) { mWantsTags = show; @@ -1037,28 +1037,28 @@ namespace LLError mWantsMultiline = show; } - void addRecorder(RecorderPtr recorder) - { - if (!recorder) - { - return; - } - SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); - LLMutexLock lock(&s->mRecorderMutex); - s->mRecorders.push_back(recorder); - } - - void removeRecorder(RecorderPtr recorder) - { - if (!recorder) - { - return; - } - SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); - LLMutexLock lock(&s->mRecorderMutex); - s->mRecorders.erase(std::remove(s->mRecorders.begin(), s->mRecorders.end(), recorder), - s->mRecorders.end()); - } + void addRecorder(RecorderPtr recorder) + { + if (!recorder) + { + return; + } + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); + LLMutexLock lock(&s->mRecorderMutex); + s->mRecorders.push_back(recorder); + } + + void removeRecorder(RecorderPtr recorder) + { + if (!recorder) + { + return; + } + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); + LLMutexLock lock(&s->mRecorderMutex); + s->mRecorders.erase(std::remove(s->mRecorders.begin(), s->mRecorders.end(), recorder), + s->mRecorders.end()); + } // Find an entry in SettingsConfig::mRecorders whose RecorderPtr points to // a Recorder subclass of type RECORDER. Return, not a RecorderPtr (which @@ -1127,26 +1127,26 @@ namespace LLError namespace LLError { - void logToFile(const std::string& file_name) - { - // remove any previous Recorder filling this role - removeRecorder(); - - if (!file_name.empty()) - { - std::shared_ptr recordToFile(new RecordToFile(file_name)); - if (recordToFile->okay()) - { - addRecorder(recordToFile); - } - } - } - - std::string logFileName() - { - auto found = findRecorder(); - return found? found->getFilename() : std::string(); - } + void logToFile(const std::string& file_name) + { + // remove any previous Recorder filling this role + removeRecorder(); + + if (!file_name.empty()) + { + std::shared_ptr recordToFile(new RecordToFile(file_name)); + if (recordToFile->okay()) + { + addRecorder(recordToFile); + } + } + } + + std::string logFileName() + { + auto found = findRecorder(); + return found? found->getFilename() : std::string(); + } void logToStderr() { @@ -1157,17 +1157,17 @@ namespace LLError } } - void logToFixedBuffer(LLLineBuffer* fixedBuffer) - { - // remove any previous Recorder filling this role - removeRecorder(); + void logToFixedBuffer(LLLineBuffer* fixedBuffer) + { + // remove any previous Recorder filling this role + removeRecorder(); - if (fixedBuffer) - { - RecorderPtr recordToFixedBuffer(new RecordToFixedBuffer(fixedBuffer)); - addRecorder(recordToFixedBuffer); - } - } + if (fixedBuffer) + { + RecorderPtr recordToFixedBuffer(new RecordToFixedBuffer(fixedBuffer)); + addRecorder(recordToFixedBuffer); + } + } } namespace @@ -1213,40 +1213,40 @@ namespace return out.str(); } - void writeToRecorders(const LLError::CallSite& site, const std::string& message) - { + void writeToRecorders(const LLError::CallSite& site, const std::string& message) + { LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING - LLError::ELevel level = site.mLevel; - SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); + LLError::ELevel level = site.mLevel; + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); std::string escaped_message; LLMutexLock lock(&s->mRecorderMutex); - for (LLError::RecorderPtr& r : s->mRecorders) - { + for (LLError::RecorderPtr& r : s->mRecorders) + { if (!r->enabled()) { continue; } - - std::ostringstream message_stream; - if (r->wantsTime() && s->mTimeFunction != NULL) - { - message_stream << s->mTimeFunction(); - } + std::ostringstream message_stream; + + if (r->wantsTime() && s->mTimeFunction != NULL) + { + message_stream << s->mTimeFunction(); + } message_stream << " "; - - if (r->wantsLevel()) + + if (r->wantsLevel()) { - message_stream << site.mLevelString; + message_stream << site.mLevelString; } message_stream << " "; - - if (r->wantsTags()) - { - message_stream << site.mTagString; - } + + if (r->wantsTags()) + { + message_stream << site.mTagString; + } message_stream << " "; if (r->wantsLocation() || level == LLError::LEVEL_ERROR) @@ -1255,10 +1255,10 @@ namespace } message_stream << " "; - if (r->wantsFunctionName()) - { - message_stream << site.mFunctionString; - } + if (r->wantsFunctionName()) + { + message_stream << site.mFunctionString; + } message_stream << " : "; if (r->wantsMultiline()) @@ -1274,250 +1274,250 @@ namespace message_stream << escaped_message; } - r->recordMessage(level, message_stream.str()); - } - } + r->recordMessage(level, message_stream.str()); + } + } } namespace { - // We need a couple different mutexes, but we want to use the same mechanism - // for both. Make getMutex() a template function with different instances - // for different MutexDiscriminator values. - enum MutexDiscriminator - { - LOG_MUTEX, - STACKS_MUTEX - }; - // Some logging calls happen very early in processing -- so early that our - // module-static variables aren't yet initialized. getMutex() wraps a - // function-static LLMutex so that early calls can still have a valid - // LLMutex instance. - template - LLMutex* getMutex() - { - // guaranteed to be initialized the first time control reaches here - static LLMutex sMutex; - return &sMutex; - } - - bool checkLevelMap(const LevelMap& map, const std::string& key, - LLError::ELevel& level) - { - bool stop_checking; - LevelMap::const_iterator i = map.find(key); - if (i == map.end()) - { - return stop_checking = false; - } - - level = i->second; - return stop_checking = true; - } - - bool checkLevelMap( const LevelMap& map, - const char *const * keys, - size_t count, - LLError::ELevel& level) - { - bool found_level = false; - - LLError::ELevel tag_level = LLError::LEVEL_NONE; - - for (size_t i = 0; i < count; i++) - { - LevelMap::const_iterator it = map.find(keys[i]); - if (it != map.end()) - { - found_level = true; - tag_level = llmin(tag_level, it->second); - } - } - - if (found_level) - { - level = tag_level; - } - return found_level; - } + // We need a couple different mutexes, but we want to use the same mechanism + // for both. Make getMutex() a template function with different instances + // for different MutexDiscriminator values. + enum MutexDiscriminator + { + LOG_MUTEX, + STACKS_MUTEX + }; + // Some logging calls happen very early in processing -- so early that our + // module-static variables aren't yet initialized. getMutex() wraps a + // function-static LLMutex so that early calls can still have a valid + // LLMutex instance. + template + LLMutex* getMutex() + { + // guaranteed to be initialized the first time control reaches here + static LLMutex sMutex; + return &sMutex; + } + + bool checkLevelMap(const LevelMap& map, const std::string& key, + LLError::ELevel& level) + { + bool stop_checking; + LevelMap::const_iterator i = map.find(key); + if (i == map.end()) + { + return stop_checking = false; + } + + level = i->second; + return stop_checking = true; + } + + bool checkLevelMap( const LevelMap& map, + const char *const * keys, + size_t count, + LLError::ELevel& level) + { + bool found_level = false; + + LLError::ELevel tag_level = LLError::LEVEL_NONE; + + for (size_t i = 0; i < count; i++) + { + LevelMap::const_iterator it = map.find(keys[i]); + if (it != map.end()) + { + found_level = true; + tag_level = llmin(tag_level, it->second); + } + } + + if (found_level) + { + level = tag_level; + } + return found_level; + } } namespace LLError { - bool Log::shouldLog(CallSite& site) - { + bool Log::shouldLog(CallSite& site) + { LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING - LLMutexTrylock lock(getMutex(), 5); - if (!lock.isLocked()) - { - return false; - } - - Globals *g = Globals::getInstance(); - SettingsConfigPtr s = g->getSettingsConfig(); - - s->mShouldLogCallCounter++; - - const std::string& class_name = className(site.mClassInfo); - std::string function_name = functionName(site.mFunction); + LLMutexTrylock lock(getMutex(), 5); + if (!lock.isLocked()) + { + return false; + } + + Globals *g = Globals::getInstance(); + SettingsConfigPtr s = g->getSettingsConfig(); + + s->mShouldLogCallCounter++; + + const std::string& class_name = className(site.mClassInfo); + std::string function_name = functionName(site.mFunction); #if LL_LINUX - // gross, but typeid comparison seems to always fail here with gcc4.1 - if (0 != strcmp(site.mClassInfo.name(), typeid(NoClassInfo).name())) + // gross, but typeid comparison seems to always fail here with gcc4.1 + if (0 != strcmp(site.mClassInfo.name(), typeid(NoClassInfo).name())) #else - if (site.mClassInfo != typeid(NoClassInfo)) + if (site.mClassInfo != typeid(NoClassInfo)) #endif // LL_LINUX - { - function_name = class_name + "::" + function_name; - } - - ELevel compareLevel = s->mDefaultLevel; - - // The most specific match found will be used as the log level, - // since the computation short circuits. - // So, in increasing order of importance: - // Default < Tags < File < Class < Function - checkLevelMap(s->mFunctionLevelMap, function_name, compareLevel) - || checkLevelMap(s->mClassLevelMap, class_name, compareLevel) - || checkLevelMap(s->mFileLevelMap, abbreviateFile(site.mFile), compareLevel) - || (site.mTagCount > 0 - ? checkLevelMap(s->mTagLevelMap, site.mTags, site.mTagCount, compareLevel) - : false); - - site.mCached = true; - g->addCallSite(site); - return site.mShouldLog = site.mLevel >= compareLevel; - } - - - void Log::flush(const std::ostringstream& out, const CallSite& site) - { + { + function_name = class_name + "::" + function_name; + } + + ELevel compareLevel = s->mDefaultLevel; + + // The most specific match found will be used as the log level, + // since the computation short circuits. + // So, in increasing order of importance: + // Default < Tags < File < Class < Function + checkLevelMap(s->mFunctionLevelMap, function_name, compareLevel) + || checkLevelMap(s->mClassLevelMap, class_name, compareLevel) + || checkLevelMap(s->mFileLevelMap, abbreviateFile(site.mFile), compareLevel) + || (site.mTagCount > 0 + ? checkLevelMap(s->mTagLevelMap, site.mTags, site.mTagCount, compareLevel) + : false); + + site.mCached = true; + g->addCallSite(site); + return site.mShouldLog = site.mLevel >= compareLevel; + } + + + void Log::flush(const std::ostringstream& out, const CallSite& site) + { LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING - LLMutexTrylock lock(getMutex(),5); - if (!lock.isLocked()) - { - return; - } - - Globals* g = Globals::getInstance(); - SettingsConfigPtr s = g->getSettingsConfig(); - - std::string message = out.str(); - - if (site.mPrintOnce) - { - std::ostringstream message_stream; - - std::map::iterator messageIter = s->mUniqueLogMessages.find(message); - if (messageIter != s->mUniqueLogMessages.end()) - { - messageIter->second++; - unsigned int num_messages = messageIter->second; - if (num_messages == 10 || num_messages == 50 || (num_messages % 100) == 0) - { - message_stream << "ONCE (" << num_messages << "th time seen): "; - } - else - { - return; - } - } - else - { - message_stream << "ONCE: "; - s->mUniqueLogMessages[message] = 1; - } - message_stream << message; - message = message_stream.str(); - } - - writeToRecorders(site, message); - - if (site.mLevel == LEVEL_ERROR) - { - g->mFatalMessage = message; + LLMutexTrylock lock(getMutex(),5); + if (!lock.isLocked()) + { + return; + } + + Globals* g = Globals::getInstance(); + SettingsConfigPtr s = g->getSettingsConfig(); + + std::string message = out.str(); + + if (site.mPrintOnce) + { + std::ostringstream message_stream; + + std::map::iterator messageIter = s->mUniqueLogMessages.find(message); + if (messageIter != s->mUniqueLogMessages.end()) + { + messageIter->second++; + unsigned int num_messages = messageIter->second; + if (num_messages == 10 || num_messages == 50 || (num_messages % 100) == 0) + { + message_stream << "ONCE (" << num_messages << "th time seen): "; + } + else + { + return; + } + } + else + { + message_stream << "ONCE: "; + s->mUniqueLogMessages[message] = 1; + } + message_stream << message; + message = message_stream.str(); + } + + writeToRecorders(site, message); + + if (site.mLevel == LEVEL_ERROR) + { + g->mFatalMessage = message; if (s->mCrashFunction) { s->mCrashFunction(message); } - } - } + } + } } namespace LLError { - SettingsStoragePtr saveAndResetSettings() - { - return Globals::getInstance()->saveAndResetSettingsConfig(); - } - - void restoreSettings(SettingsStoragePtr pSettingsStorage) - { - return Globals::getInstance()->restore(pSettingsStorage); - } - - std::string removePrefix(std::string& s, const std::string& p) - { - std::string::size_type where = s.find(p); - if (where == std::string::npos) - { - return s; - } - - return std::string(s, where + p.size()); - } - - void replaceChar(std::string& s, char old, char replacement) - { - std::string::size_type i = 0; - std::string::size_type len = s.length(); - for ( ; i < len; i++ ) - { - if (s[i] == old) - { - s[i] = replacement; - } - } - } - - std::string abbreviateFile(const std::string& filePath) - { - std::string f = filePath; + SettingsStoragePtr saveAndResetSettings() + { + return Globals::getInstance()->saveAndResetSettingsConfig(); + } + + void restoreSettings(SettingsStoragePtr pSettingsStorage) + { + return Globals::getInstance()->restore(pSettingsStorage); + } + + std::string removePrefix(std::string& s, const std::string& p) + { + std::string::size_type where = s.find(p); + if (where == std::string::npos) + { + return s; + } + + return std::string(s, where + p.size()); + } + + void replaceChar(std::string& s, char old, char replacement) + { + std::string::size_type i = 0; + std::string::size_type len = s.length(); + for ( ; i < len; i++ ) + { + if (s[i] == old) + { + s[i] = replacement; + } + } + } + + std::string abbreviateFile(const std::string& filePath) + { + std::string f = filePath; #if LL_WINDOWS - replaceChar(f, '\\', '/'); + replaceChar(f, '\\', '/'); #endif - static std::string indra_prefix = "indra/"; - f = removePrefix(f, indra_prefix); + static std::string indra_prefix = "indra/"; + f = removePrefix(f, indra_prefix); #if LL_DARWIN - static std::string newview_prefix = "newview/../"; - f = removePrefix(f, newview_prefix); + static std::string newview_prefix = "newview/../"; + f = removePrefix(f, newview_prefix); #endif - return f; - } - - int shouldLogCallCount() - { - SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); - return s->mShouldLogCallCounter; - } - - std::string utcTime() - { - time_t now = time(NULL); - const size_t BUF_SIZE = 64; - char time_str[BUF_SIZE]; /* Flawfinder: ignore */ - - auto chars = strftime(time_str, BUF_SIZE, - "%Y-%m-%dT%H:%M:%SZ", - gmtime(&now)); - - return chars ? time_str : "time error"; - } + return f; + } + + int shouldLogCallCount() + { + SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); + return s->mShouldLogCallCounter; + } + + std::string utcTime() + { + time_t now = time(NULL); + const size_t BUF_SIZE = 64; + char time_str[BUF_SIZE]; /* Flawfinder: ignore */ + + auto chars = strftime(time_str, BUF_SIZE, + "%Y-%m-%dT%H:%M:%SZ", + gmtime(&now)); + + return chars ? time_str : "time error"; + } } namespace LLError -{ +{ LLCallStacks::StringVector LLCallStacks::sBuffer ; //static @@ -1576,7 +1576,7 @@ namespace LLError LL_INFOS() << " ************* PRINT OUT LL CALL STACKS ************* " << LL_ENDL; for (StringVector::const_reverse_iterator ri(sBuffer.rbegin()), re(sBuffer.rend()); ri != re; ++ri) - { + { LL_INFOS() << (*ri) << LL_ENDL; } LL_INFOS() << " *************** END OF LL CALL STACKS *************** " << LL_ENDL; diff --git a/indra/llcommon/llerror.h b/indra/llcommon/llerror.h index 6f6b349cf5..6176ce0d1d 100644 --- a/indra/llcommon/llerror.h +++ b/indra/llcommon/llerror.h @@ -1,4 +1,4 @@ -/** +/** * @file llerror.h * @date December 2006 * @brief error message system @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -79,16 +79,16 @@ const int LL_ERR_NOERR = 0; #define llassert_always_msg(func, msg) if (LL_UNLIKELY(!(func))) LL_ERRS() << "ASSERT (" << msg << ")" << LL_ENDL -#define llassert_always(func) llassert_always_msg(func, #func) +#define llassert_always(func) llassert_always_msg(func, #func) #ifdef SHOW_ASSERT -#define llassert(func) llassert_always_msg(func, #func) -#define llassert_msg(func, msg) llassert_always_msg(func, msg) -#define llverify(func) llassert_always_msg(func, #func) +#define llassert(func) llassert_always_msg(func, #func) +#define llassert_msg(func, msg) llassert_always_msg(func, msg) +#define llverify(func) llassert_always_msg(func, #func) #else #define llassert(func) #define llassert_msg(func, msg) -#define llverify(func) do {if (func) {}} while(0) +#define llverify(func) do {if (func) {}} while(0) #endif #ifdef LL_WINDOWS @@ -102,59 +102,59 @@ const int LL_ERR_NOERR = 0; /** Error Logging Facility - Information for most users: - - Code can log messages with constructions like this: - - LL_INFOS("StringTag") << "request to fizzbip agent " << agent_id - << " denied due to timeout" << LL_ENDL; - - Messages can be logged to one of four increasing levels of concern, - using one of four "streams": - - LL_DEBUGS("StringTag") - debug messages that are normally suppressed - LL_INFOS("StringTag") - informational messages that are normal shown - LL_WARNS("StringTag") - warning messages that signal a problem - LL_ERRS("StringTag") - error messages that are major, unrecoverable failures - - The later (LL_ERRS("StringTag")) automatically crashes the process after the message - is logged. - - Note that these "streams" are actually #define magic. Rules for use: - * they cannot be used as normal streams, only to start a message - * messages written to them MUST be terminated with LL_ENDL - * between the opening and closing, the << operator is indeed - writing onto a std::ostream, so all conversions and stream - formating are available - - These messages are automatically logged with function name, and (if enabled) - file and line of the message. (Note: Existing messages that already include - the function name don't get name printed twice.) - - If you have a class, adding LOG_CLASS line to the declaration will cause - all messages emitted from member functions (normal and static) to be tagged - with the proper class name as well as the function name: - - class LLFoo - { - LOG_CLASS(LLFoo); - public: - ... - }; - - void LLFoo::doSomething(int i) - { - if (i > 100) - { - LL_WARNS("FooBarTag") << "called with a big value for i: " << i << LL_ENDL; - } - ... - } - - will result in messages like: - - WARN #FooBarTag# llcommon/llfoo(100) LLFoo::doSomething : called with a big value for i: 283 - + Information for most users: + + Code can log messages with constructions like this: + + LL_INFOS("StringTag") << "request to fizzbip agent " << agent_id + << " denied due to timeout" << LL_ENDL; + + Messages can be logged to one of four increasing levels of concern, + using one of four "streams": + + LL_DEBUGS("StringTag") - debug messages that are normally suppressed + LL_INFOS("StringTag") - informational messages that are normal shown + LL_WARNS("StringTag") - warning messages that signal a problem + LL_ERRS("StringTag") - error messages that are major, unrecoverable failures + + The later (LL_ERRS("StringTag")) automatically crashes the process after the message + is logged. + + Note that these "streams" are actually #define magic. Rules for use: + * they cannot be used as normal streams, only to start a message + * messages written to them MUST be terminated with LL_ENDL + * between the opening and closing, the << operator is indeed + writing onto a std::ostream, so all conversions and stream + formating are available + + These messages are automatically logged with function name, and (if enabled) + file and line of the message. (Note: Existing messages that already include + the function name don't get name printed twice.) + + If you have a class, adding LOG_CLASS line to the declaration will cause + all messages emitted from member functions (normal and static) to be tagged + with the proper class name as well as the function name: + + class LLFoo + { + LOG_CLASS(LLFoo); + public: + ... + }; + + void LLFoo::doSomething(int i) + { + if (i > 100) + { + LL_WARNS("FooBarTag") << "called with a big value for i: " << i << LL_ENDL; + } + ... + } + + will result in messages like: + + WARN #FooBarTag# llcommon/llfoo(100) LLFoo::doSomething : called with a big value for i: 283 + the syntax is: SPACE SPACE SPACE SPACE SPACE COLON SPACE @@ -164,121 +164,121 @@ const int LL_ERR_NOERR = 0; The tags must be a single word (may not contain a space); if more than one tag is specified, they are all surrounded by '#' ( #FooTag#BarTag# ). - Which messages are logged and which are suppressed can be controlled at run - time from the configuration file. The default configuration is in newview/app_settings/logcontrol.xml + Which messages are logged and which are suppressed can be controlled at run + time from the configuration file. The default configuration is in newview/app_settings/logcontrol.xml A copy of that file named logcontrol-dev.xml can be made in the users personal settings directory; that will override the installed default file. See the logcontrol.xml file or http://wiki.secondlife.com/wiki/Logging_System_Overview for configuration details. - - Lastly, logging is now very efficient in both compiled code and execution - when skipped. There is no need to wrap messages, even debugging ones, in - #ifdef _DEBUG constructs. LL_DEBUGS("StringTag") messages are compiled into all builds, - even release. Which means you can use them to help debug even when deployed - to a real grid. + + Lastly, logging is now very efficient in both compiled code and execution + when skipped. There is no need to wrap messages, even debugging ones, in + #ifdef _DEBUG constructs. LL_DEBUGS("StringTag") messages are compiled into all builds, + even release. Which means you can use them to help debug even when deployed + to a real grid. */ namespace LLError { - enum ELevel - { - LEVEL_ALL = 0, - // used to indicate that all messages should be logged - - LEVEL_DEBUG = 0, - LEVEL_INFO = 1, - LEVEL_WARN = 2, - LEVEL_ERROR = 3, // used to be called FATAL - - LEVEL_NONE = 4 - // not really a level - // used to indicate that no messages should be logged - }; - // If you change ELevel, please update llvlog() macro below. - - /* Macro support - The classes CallSite and Log are used by the logging macros below. - They are not intended for general use. - */ - - struct CallSite; - - class LL_COMMON_API Log - { - public: - static bool shouldLog(CallSite&); - static void flush(const std::ostringstream&, const CallSite&); - static std::string demangle(const char* mangled); - /// classname() - template - static std::string classname() { return demangle(typeid(T).name()); } - /// classname(some_pointer) - template - static std::string classname(T* const ptr) { return ptr? demangle(typeid(*ptr).name()) : "nullptr"; } - /// classname(some_reference) - template - static std::string classname(const T& obj) { return demangle(typeid(obj).name()); } - }; - - struct LL_COMMON_API CallSite - { - // Represents a specific place in the code where a message is logged - // This is public because it is used by the macros below. It is not - // intended for public use. - CallSite(ELevel level, - const char* file, - int line, - const std::type_info& class_info, - const char* function, - bool print_once, - const char** tags, - size_t tag_count); - - ~CallSite(); + enum ELevel + { + LEVEL_ALL = 0, + // used to indicate that all messages should be logged + + LEVEL_DEBUG = 0, + LEVEL_INFO = 1, + LEVEL_WARN = 2, + LEVEL_ERROR = 3, // used to be called FATAL + + LEVEL_NONE = 4 + // not really a level + // used to indicate that no messages should be logged + }; + // If you change ELevel, please update llvlog() macro below. + + /* Macro support + The classes CallSite and Log are used by the logging macros below. + They are not intended for general use. + */ + + struct CallSite; + + class LL_COMMON_API Log + { + public: + static bool shouldLog(CallSite&); + static void flush(const std::ostringstream&, const CallSite&); + static std::string demangle(const char* mangled); + /// classname() + template + static std::string classname() { return demangle(typeid(T).name()); } + /// classname(some_pointer) + template + static std::string classname(T* const ptr) { return ptr? demangle(typeid(*ptr).name()) : "nullptr"; } + /// classname(some_reference) + template + static std::string classname(const T& obj) { return demangle(typeid(obj).name()); } + }; + + struct LL_COMMON_API CallSite + { + // Represents a specific place in the code where a message is logged + // This is public because it is used by the macros below. It is not + // intended for public use. + CallSite(ELevel level, + const char* file, + int line, + const std::type_info& class_info, + const char* function, + bool print_once, + const char** tags, + size_t tag_count); + + ~CallSite(); #ifdef LL_LIBRARY_INCLUDE - bool shouldLog(); + bool shouldLog(); #else // LL_LIBRARY_INCLUDE - bool shouldLog() - { - return mCached - ? mShouldLog - : Log::shouldLog(*this); - } - // this member function needs to be in-line for efficiency + bool shouldLog() + { + return mCached + ? mShouldLog + : Log::shouldLog(*this); + } + // this member function needs to be in-line for efficiency #endif // LL_LIBRARY_INCLUDE - - void invalidate(); - - // these describe the call site and never change - const ELevel mLevel; - const char* const mFile; - const int mLine; - const std::type_info& mClassInfo; - const char* const mFunction; - const char** mTags; - size_t mTagCount; - const bool mPrintOnce; - const char* mLevelString; - std::string mLocationString, - mFunctionString, - mTagString; - bool mCached, - mShouldLog; - - friend class Log; - }; - - - class End { }; - inline std::ostream& operator<<(std::ostream& s, const End&) - { return s; } - // used to indicate the end of a message - - class LL_COMMON_API NoClassInfo { }; - // used to indicate no class info known for logging + + void invalidate(); + + // these describe the call site and never change + const ELevel mLevel; + const char* const mFile; + const int mLine; + const std::type_info& mClassInfo; + const char* const mFunction; + const char** mTags; + size_t mTagCount; + const bool mPrintOnce; + const char* mLevelString; + std::string mLocationString, + mFunctionString, + mTagString; + bool mCached, + mShouldLog; + + friend class Log; + }; + + + class End { }; + inline std::ostream& operator<<(std::ostream& s, const End&) + { return s; } + // used to indicate the end of a message + + class LL_COMMON_API NoClassInfo { }; + // used to indicate no class info known for logging //LLCallStacks keeps track of call stacks and output the call stacks to log file // - //Note: to be simple, efficient and necessary to keep track of correct call stacks, + //Note: to be simple, efficient and necessary to keep track of correct call stacks, //LLCallStacks is designed not to be thread-safe. //so try not to use it in multiple parallel threads at same time. //Used in a single thread at a time is fine. @@ -287,8 +287,8 @@ namespace LLError private: typedef std::vector StringVector; static StringVector sBuffer ; - - public: + + public: static void push(const char* function, const int line) ; static void insert(std::ostream& out, const char* function, const int line) ; static void print() ; @@ -326,34 +326,34 @@ namespace LLError }; } -//this is cheaper than llcallstacks if no need to output other variables to call stacks. +//this is cheaper than llcallstacks if no need to output other variables to call stacks. #define LL_PUSH_CALLSTACKS() LLError::LLCallStacks::push(__FUNCTION__, __LINE__) #define llcallstacks \ - { \ - std::ostringstream _out; \ - LLError::LLCallStacks::insert(_out, __FUNCTION__, __LINE__) ; \ - _out + { \ + std::ostringstream _out; \ + LLError::LLCallStacks::insert(_out, __FUNCTION__, __LINE__) ; \ + _out #define llcallstacksendl \ - LLError::End(); \ - LLError::LLCallStacks::end(_out) ; \ - } + LLError::End(); \ + LLError::LLCallStacks::end(_out) ; \ + } #define LL_CLEAR_CALLSTACKS() LLError::LLCallStacks::clear() -#define LL_PRINT_CALLSTACKS() LLError::LLCallStacks::print() +#define LL_PRINT_CALLSTACKS() LLError::LLCallStacks::print() /* - Class type information for logging + Class type information for logging */ -#define LOG_CLASS(s) typedef s _LL_CLASS_TO_LOG - // Declares class to tag logged messages with. - // See top of file for example of how to use this - +#define LOG_CLASS(s) typedef s _LL_CLASS_TO_LOG + // Declares class to tag logged messages with. + // See top of file for example of how to use this + typedef LLError::NoClassInfo _LL_CLASS_TO_LOG; - // Outside a class declaration, or in class without LOG_CLASS(), this - // typedef causes the messages to not be associated with any class. + // Outside a class declaration, or in class without LOG_CLASS(), this + // typedef causes the messages to not be associated with any class. ///////////////////////////////// // Error Logging Macros @@ -376,34 +376,34 @@ typedef LLError::NoClassInfo _LL_CLASS_TO_LOG; #define lllog(level, once, ...) \ do { \ LL_PROFILE_ZONE_NAMED("lllog"); \ - const char* tags[] = {"", ##__VA_ARGS__}; \ - static LLError::CallSite _site(lllog_site_args_(level, once, tags)); \ - lllog_test_() + const char* tags[] = {"", ##__VA_ARGS__}; \ + static LLError::CallSite _site(lllog_site_args_(level, once, tags)); \ + lllog_test_() #define lllog_test_() \ - if (LL_UNLIKELY(_site.shouldLog())) \ - { \ - std::ostringstream _out; \ - _out + if (LL_UNLIKELY(_site.shouldLog())) \ + { \ + std::ostringstream _out; \ + _out #define lllog_site_args_(level, once, tags) \ - level, __FILE__, __LINE__, typeid(_LL_CLASS_TO_LOG), \ - __FUNCTION__, once, &tags[1], LL_ARRAY_SIZE(tags)-1 + level, __FILE__, __LINE__, typeid(_LL_CLASS_TO_LOG), \ + __FUNCTION__, once, &tags[1], LL_ARRAY_SIZE(tags)-1 //Use this construct if you need to do computation in the middle of a //message: -// -// LL_INFOS("AgentGesture") << "the agent " << agend_id; -// switch (f) -// { -// case FOP_SHRUGS: LL_CONT << "shrugs"; break; -// case FOP_TAPS: LL_CONT << "points at " << who; break; -// case FOP_SAYS: LL_CONT << "says " << message; break; -// } -// LL_CONT << " for " << t << " seconds" << LL_ENDL; -// +// +// LL_INFOS("AgentGesture") << "the agent " << agend_id; +// switch (f) +// { +// case FOP_SHRUGS: LL_CONT << "shrugs"; break; +// case FOP_TAPS: LL_CONT << "points at " << who; break; +// case FOP_SAYS: LL_CONT << "says " << message; break; +// } +// LL_CONT << " for " << t << " seconds" << LL_ENDL; +// //Such computation is done iff the message will be logged. -#define LL_CONT _out +#define LL_CONT _out #define LL_NEWLINE '\n' @@ -426,24 +426,24 @@ typedef LLError::NoClassInfo _LL_CLASS_TO_LOG; // NEW Macros for debugging, allow the passing of a string tag // Pass comma separated list of tags (currently only supports up to 0, 1, or 2) -#define LL_DEBUGS(...) lllog(LLError::LEVEL_DEBUG, false, ##__VA_ARGS__) -#define LL_INFOS(...) lllog(LLError::LEVEL_INFO, false, ##__VA_ARGS__) -#define LL_WARNS(...) lllog(LLError::LEVEL_WARN, false, ##__VA_ARGS__) -#define LL_ERRS(...) lllog(LLError::LEVEL_ERROR, false, ##__VA_ARGS__) +#define LL_DEBUGS(...) lllog(LLError::LEVEL_DEBUG, false, ##__VA_ARGS__) +#define LL_INFOS(...) lllog(LLError::LEVEL_INFO, false, ##__VA_ARGS__) +#define LL_WARNS(...) lllog(LLError::LEVEL_WARN, false, ##__VA_ARGS__) +#define LL_ERRS(...) lllog(LLError::LEVEL_ERROR, false, ##__VA_ARGS__) // alternative to llassert_always that prints explanatory message // note ## token paste operator hack used above will only work in gcc following // a comma and is completely unnecessary in VS since the comma is automatically // suppressed // https://gcc.gnu.org/onlinedocs/cpp/Variadic-Macros.html // https://docs.microsoft.com/en-us/cpp/preprocessor/variadic-macros?view=vs-2015 -#define LL_WARNS_IF(exp, ...) if (exp) LL_WARNS(__VA_ARGS__) << "(" #exp ")" -#define LL_ERRS_IF(exp, ...) if (exp) LL_ERRS(__VA_ARGS__) << "(" #exp ")" +#define LL_WARNS_IF(exp, ...) if (exp) LL_WARNS(__VA_ARGS__) << "(" #exp ")" +#define LL_ERRS_IF(exp, ...) if (exp) LL_ERRS(__VA_ARGS__) << "(" #exp ")" // Only print the log message once (good for warnings or infos that would otherwise // spam the log file over and over, such as tighter loops). -#define LL_DEBUGS_ONCE(...) lllog(LLError::LEVEL_DEBUG, true, ##__VA_ARGS__) -#define LL_INFOS_ONCE(...) lllog(LLError::LEVEL_INFO, true, ##__VA_ARGS__) -#define LL_WARNS_ONCE(...) lllog(LLError::LEVEL_WARN, true, ##__VA_ARGS__) +#define LL_DEBUGS_ONCE(...) lllog(LLError::LEVEL_DEBUG, true, ##__VA_ARGS__) +#define LL_INFOS_ONCE(...) lllog(LLError::LEVEL_INFO, true, ##__VA_ARGS__) +#define LL_WARNS_ONCE(...) lllog(LLError::LEVEL_WARN, true, ##__VA_ARGS__) // Use this if you need to pass LLError::ELevel as a variable. #define LL_VLOGS(level, ...) llvlog(level, false, ##__VA_ARGS__) @@ -459,33 +459,33 @@ typedef LLError::NoClassInfo _LL_CLASS_TO_LOG; // instance for the passed level value. // Compare implementation to lllog() above. #define llvlog(level, once, ...) \ - do { \ - const char* tags[] = {"", ##__VA_ARGS__}; \ - /* Need a static CallSite instance per expected ELevel value. */ \ - /* Since we intend to index this array with the ELevel, */ \ - /* _sites[0] should be ELevel(0), and so on -- avoid using */ \ - /* ELevel symbolic names when initializing -- except for */ \ - /* the last entry, which handles anything beyond the end. */ \ - /* (Commented ELevel value names are from 2016-09-01.) */ \ - /* Passing an ELevel past the end of this array is itself */ \ - /* a fatal error, so ensure the last is LEVEL_ERROR. */ \ - static LLError::CallSite _sites[] = \ - { \ - /* LEVEL_DEBUG */ \ - LLError::CallSite(lllog_site_args_(LLError::ELevel(0), once, tags)), \ - /* LEVEL_INFO */ \ - LLError::CallSite(lllog_site_args_(LLError::ELevel(1), once, tags)), \ - /* LEVEL_WARN */ \ - LLError::CallSite(lllog_site_args_(LLError::ELevel(2), once, tags)), \ - /* LEVEL_ERROR */ \ - LLError::CallSite(lllog_site_args_(LLError::LEVEL_ERROR, once, tags)) \ - }; \ - /* Clamp the passed 'level' to at most last entry */ \ - std::size_t which((std::size_t(level) >= LL_ARRAY_SIZE(_sites)) ? \ - (LL_ARRAY_SIZE(_sites) - 1) : std::size_t(level)); \ - /* selected CallSite *must* be named _site for LL_ENDL */ \ - LLError::CallSite& _site(_sites[which]); \ - lllog_test_() + do { \ + const char* tags[] = {"", ##__VA_ARGS__}; \ + /* Need a static CallSite instance per expected ELevel value. */ \ + /* Since we intend to index this array with the ELevel, */ \ + /* _sites[0] should be ELevel(0), and so on -- avoid using */ \ + /* ELevel symbolic names when initializing -- except for */ \ + /* the last entry, which handles anything beyond the end. */ \ + /* (Commented ELevel value names are from 2016-09-01.) */ \ + /* Passing an ELevel past the end of this array is itself */ \ + /* a fatal error, so ensure the last is LEVEL_ERROR. */ \ + static LLError::CallSite _sites[] = \ + { \ + /* LEVEL_DEBUG */ \ + LLError::CallSite(lllog_site_args_(LLError::ELevel(0), once, tags)), \ + /* LEVEL_INFO */ \ + LLError::CallSite(lllog_site_args_(LLError::ELevel(1), once, tags)), \ + /* LEVEL_WARN */ \ + LLError::CallSite(lllog_site_args_(LLError::ELevel(2), once, tags)), \ + /* LEVEL_ERROR */ \ + LLError::CallSite(lllog_site_args_(LLError::LEVEL_ERROR, once, tags)) \ + }; \ + /* Clamp the passed 'level' to at most last entry */ \ + std::size_t which((std::size_t(level) >= LL_ARRAY_SIZE(_sites)) ? \ + (LL_ARRAY_SIZE(_sites) - 1) : std::size_t(level)); \ + /* selected CallSite *must* be named _site for LL_ENDL */ \ + LLError::CallSite& _site(_sites[which]); \ + lllog_test_() /* // Check at run-time whether logging is enabled, without generating output. @@ -510,7 +510,7 @@ LL_ENDL; LL_DEBUGS("SomeTag") performs the locking and map-searching ONCE, then caches the result in a static variable. -*/ +*/ // used by LLERROR_CRASH void crashdriver(void (*)(int*)); diff --git a/indra/llcommon/llerrorcontrol.h b/indra/llcommon/llerrorcontrol.h index 77b187a80f..bf5a6df556 100644 --- a/indra/llcommon/llerrorcontrol.h +++ b/indra/llcommon/llerrorcontrol.h @@ -38,143 +38,143 @@ class LLSD; /* - This is the part of the LLError namespace that manages the messages - produced by the logging. The logging support is defined in llerror.h. - Most files do not need to include this. + This is the part of the LLError namespace that manages the messages + produced by the logging. The logging support is defined in llerror.h. + Most files do not need to include this. - These implementations are in llerror.cpp. + These implementations are in llerror.cpp. */ // Line buffer interface class LLLineBuffer { public: - LLLineBuffer() {}; - virtual ~LLLineBuffer() {}; + LLLineBuffer() {}; + virtual ~LLLineBuffer() {}; - virtual void clear() = 0; // Clear the buffer, and reset it. + virtual void clear() = 0; // Clear the buffer, and reset it. - virtual void addLine(const std::string& utf8line) = 0; + virtual void addLine(const std::string& utf8line) = 0; }; namespace LLError { - LL_COMMON_API void initForApplication(const std::string& user_dir, const std::string& app_dir, bool log_to_stderr = true); - // resets all logging settings to defaults needed by applicaitons - // logs to stderr and windows debug log - // sets up log configuration from the file logcontrol.xml in dir + LL_COMMON_API void initForApplication(const std::string& user_dir, const std::string& app_dir, bool log_to_stderr = true); + // resets all logging settings to defaults needed by applicaitons + // logs to stderr and windows debug log + // sets up log configuration from the file logcontrol.xml in dir - /* - Settings that control what is logged. - Setting a level means log messages at that level or above. - */ + /* + Settings that control what is logged. + Setting a level means log messages at that level or above. + */ - LL_COMMON_API void setPrintLocation(bool); - LL_COMMON_API void setDefaultLevel(LLError::ELevel); - LL_COMMON_API ELevel getDefaultLevel(); - LL_COMMON_API void setAlwaysFlush(bool flush); + LL_COMMON_API void setPrintLocation(bool); + LL_COMMON_API void setDefaultLevel(LLError::ELevel); + LL_COMMON_API ELevel getDefaultLevel(); + LL_COMMON_API void setAlwaysFlush(bool flush); LL_COMMON_API bool getAlwaysFlush(); - LL_COMMON_API void setEnabledLogTypesMask(U32 mask); - LL_COMMON_API U32 getEnabledLogTypesMask(); - LL_COMMON_API void setFunctionLevel(const std::string& function_name, LLError::ELevel); - LL_COMMON_API void setClassLevel(const std::string& class_name, LLError::ELevel); - LL_COMMON_API void setFileLevel(const std::string& file_name, LLError::ELevel); - LL_COMMON_API void setTagLevel(const std::string& file_name, LLError::ELevel); - - LL_COMMON_API LLError::ELevel decodeLevel(std::string name); - LL_COMMON_API void configure(const LLSD&); - // the LLSD can configure all of the settings - // usually read automatically from the live errorlog.xml file - - - /* - Control functions. - */ - - typedef boost::function FatalFunction; - - LL_COMMON_API void setFatalFunction(const FatalFunction&); - // The fatal function will be called after an message of LEVEL_ERROR - // is logged. Note: supressing a LEVEL_ERROR message from being logged - // (by, for example, setting a class level to LEVEL_NONE), will keep - // that message from causing the fatal function to be invoked. - // The passed FatalFunction will be the LAST log function called - // before LL_ERRS crashes its caller. A FatalFunction can throw an - // exception, or call exit(), to bypass the crash. It MUST disrupt the - // flow of control because no caller expects LL_ERRS to return. - - LL_COMMON_API FatalFunction getFatalFunction(); - // Retrieve the previously-set FatalFunction - - LL_COMMON_API std::string getFatalMessage(); - // Retrieve the message last passed to FatalFunction, if any - - /// temporarily override the FatalFunction for the duration of a - /// particular scope, e.g. for unit tests - class LL_COMMON_API OverrideFatalFunction - { - public: - OverrideFatalFunction(const FatalFunction& func): - mPrev(getFatalFunction()) - { - setFatalFunction(func); - } - ~OverrideFatalFunction() - { - setFatalFunction(mPrev); - } - - private: - FatalFunction mPrev; - }; - - typedef std::string (*TimeFunction)(); - LL_COMMON_API std::string utcTime(); - - LL_COMMON_API void setTimeFunction(TimeFunction); - // The function is use to return the current time, formatted for - // display by those error recorders that want the time included. - - - - class LL_COMMON_API Recorder - { - // An object that handles the actual output or error messages. - public: - Recorder(); - virtual ~Recorder(); - - virtual void recordMessage(LLError::ELevel, const std::string& message) = 0; - // use the level for better display, not for filtering - - virtual bool enabled() { return true; } - - bool wantsTime(); - bool wantsTags(); - bool wantsLevel(); - bool wantsLocation(); - bool wantsFunctionName(); - bool wantsMultiline(); - - void showTime(bool show); - void showTags(bool show); - void showLevel(bool show); - void showLocation(bool show); - void showFunctionName(bool show); - void showMultiline(bool show); - - protected: - bool mWantsTime; - bool mWantsTags; - bool mWantsLevel; - bool mWantsLocation; - bool mWantsFunctionName; - bool mWantsMultiline; - }; - - typedef std::shared_ptr RecorderPtr; + LL_COMMON_API void setEnabledLogTypesMask(U32 mask); + LL_COMMON_API U32 getEnabledLogTypesMask(); + LL_COMMON_API void setFunctionLevel(const std::string& function_name, LLError::ELevel); + LL_COMMON_API void setClassLevel(const std::string& class_name, LLError::ELevel); + LL_COMMON_API void setFileLevel(const std::string& file_name, LLError::ELevel); + LL_COMMON_API void setTagLevel(const std::string& file_name, LLError::ELevel); + + LL_COMMON_API LLError::ELevel decodeLevel(std::string name); + LL_COMMON_API void configure(const LLSD&); + // the LLSD can configure all of the settings + // usually read automatically from the live errorlog.xml file + + + /* + Control functions. + */ + + typedef boost::function FatalFunction; + + LL_COMMON_API void setFatalFunction(const FatalFunction&); + // The fatal function will be called after an message of LEVEL_ERROR + // is logged. Note: supressing a LEVEL_ERROR message from being logged + // (by, for example, setting a class level to LEVEL_NONE), will keep + // that message from causing the fatal function to be invoked. + // The passed FatalFunction will be the LAST log function called + // before LL_ERRS crashes its caller. A FatalFunction can throw an + // exception, or call exit(), to bypass the crash. It MUST disrupt the + // flow of control because no caller expects LL_ERRS to return. + + LL_COMMON_API FatalFunction getFatalFunction(); + // Retrieve the previously-set FatalFunction + + LL_COMMON_API std::string getFatalMessage(); + // Retrieve the message last passed to FatalFunction, if any + + /// temporarily override the FatalFunction for the duration of a + /// particular scope, e.g. for unit tests + class LL_COMMON_API OverrideFatalFunction + { + public: + OverrideFatalFunction(const FatalFunction& func): + mPrev(getFatalFunction()) + { + setFatalFunction(func); + } + ~OverrideFatalFunction() + { + setFatalFunction(mPrev); + } + + private: + FatalFunction mPrev; + }; + + typedef std::string (*TimeFunction)(); + LL_COMMON_API std::string utcTime(); + + LL_COMMON_API void setTimeFunction(TimeFunction); + // The function is use to return the current time, formatted for + // display by those error recorders that want the time included. + + + + class LL_COMMON_API Recorder + { + // An object that handles the actual output or error messages. + public: + Recorder(); + virtual ~Recorder(); + + virtual void recordMessage(LLError::ELevel, const std::string& message) = 0; + // use the level for better display, not for filtering + + virtual bool enabled() { return true; } + + bool wantsTime(); + bool wantsTags(); + bool wantsLevel(); + bool wantsLocation(); + bool wantsFunctionName(); + bool wantsMultiline(); + + void showTime(bool show); + void showTags(bool show); + void showLevel(bool show); + void showLocation(bool show); + void showFunctionName(bool show); + void showMultiline(bool show); + + protected: + bool mWantsTime; + bool mWantsTags; + bool mWantsLevel; + bool mWantsLocation; + bool mWantsFunctionName; + bool mWantsMultiline; + }; + + typedef std::shared_ptr RecorderPtr; /** * Instantiate GenericRecorder with a callable(level, message) to get @@ -197,48 +197,48 @@ namespace LLError CALLABLE mCallable; }; - /** - * @NOTE: addRecorder() and removeRecorder() uses the boost::shared_ptr to allow for shared ownership - * while still ensuring that the allocated memory is eventually freed - */ - LL_COMMON_API void addRecorder(RecorderPtr); - LL_COMMON_API void removeRecorder(RecorderPtr); - // each error message is passed to each recorder via recordMessage() - /** - * Call addGenericRecorder() with a callable(level, message) to get - * control on every log message without having to code an explicit - * Recorder subclass. Save the returned RecorderPtr if you later want to - * call removeRecorder(). - */ - template - RecorderPtr addGenericRecorder(const CALLABLE& callable) - { - RecorderPtr ptr{ new GenericRecorder(callable) }; - addRecorder(ptr); - return ptr; - } - - LL_COMMON_API void logToFile(const std::string& filename); - LL_COMMON_API void logToStderr(); - LL_COMMON_API void logToFixedBuffer(LLLineBuffer*); - // Utilities to add recorders for logging to a file or a fixed buffer - // A second call to the same function will remove the logger added - // with the first. - // Passing the empty string or NULL to just removes any prior. - LL_COMMON_API std::string logFileName(); - // returns name of current logging file, empty string if none - - - /* - Utilities for use by the unit tests of LLError itself. - */ - - typedef LLPointer SettingsStoragePtr; - LL_COMMON_API SettingsStoragePtr saveAndResetSettings(); - LL_COMMON_API void restoreSettings(SettingsStoragePtr pSettingsStorage); - - LL_COMMON_API std::string abbreviateFile(const std::string& filePath); - LL_COMMON_API int shouldLogCallCount(); + /** + * @NOTE: addRecorder() and removeRecorder() uses the boost::shared_ptr to allow for shared ownership + * while still ensuring that the allocated memory is eventually freed + */ + LL_COMMON_API void addRecorder(RecorderPtr); + LL_COMMON_API void removeRecorder(RecorderPtr); + // each error message is passed to each recorder via recordMessage() + /** + * Call addGenericRecorder() with a callable(level, message) to get + * control on every log message without having to code an explicit + * Recorder subclass. Save the returned RecorderPtr if you later want to + * call removeRecorder(). + */ + template + RecorderPtr addGenericRecorder(const CALLABLE& callable) + { + RecorderPtr ptr{ new GenericRecorder(callable) }; + addRecorder(ptr); + return ptr; + } + + LL_COMMON_API void logToFile(const std::string& filename); + LL_COMMON_API void logToStderr(); + LL_COMMON_API void logToFixedBuffer(LLLineBuffer*); + // Utilities to add recorders for logging to a file or a fixed buffer + // A second call to the same function will remove the logger added + // with the first. + // Passing the empty string or NULL to just removes any prior. + LL_COMMON_API std::string logFileName(); + // returns name of current logging file, empty string if none + + + /* + Utilities for use by the unit tests of LLError itself. + */ + + typedef LLPointer SettingsStoragePtr; + LL_COMMON_API SettingsStoragePtr saveAndResetSettings(); + LL_COMMON_API void restoreSettings(SettingsStoragePtr pSettingsStorage); + + LL_COMMON_API std::string abbreviateFile(const std::string& filePath); + LL_COMMON_API int shouldLogCallCount(); }; #endif // LL_LLERRORCONTROL_H diff --git a/indra/llcommon/llerrorlegacy.h b/indra/llcommon/llerrorlegacy.h index 31dd207008..693e1501d5 100644 --- a/indra/llcommon/llerrorlegacy.h +++ b/indra/llcommon/llerrorlegacy.h @@ -1,4 +1,4 @@ -/** +/** * @file llerrorlegacy.h * @date January 2007 * @brief old things from the older error system @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcommon/llevent.cpp b/indra/llcommon/llevent.cpp index 501d06e3cd..305ab8144a 100644 --- a/indra/llcommon/llevent.cpp +++ b/indra/llcommon/llevent.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llevent.cpp * @brief LLEvent and LLEventListener base classes. * * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -42,13 +42,13 @@ LLEvent::~LLEvent() // virtual bool LLEvent::accept(LLEventListener* listener) { - return true; + return true; } // virtual const std::string& LLEvent::desc() { - return mDesc; + return mDesc; } /************************************************ @@ -56,50 +56,50 @@ const std::string& LLEvent::desc() ************************************************/ LLObservable::LLObservable() - : mDispatcher(new LLEventDispatcher()) + : mDispatcher(new LLEventDispatcher()) { } // virtual LLObservable::~LLObservable() { - if (mDispatcher.notNull()) - { - mDispatcher->disengage(this); - mDispatcher = NULL; - } + if (mDispatcher.notNull()) + { + mDispatcher->disengage(this); + mDispatcher = NULL; + } } // virtual bool LLObservable::setDispatcher(LLPointer dispatcher) { - if (mDispatcher.notNull()) - { - mDispatcher->disengage(this); - mDispatcher = NULL; - } - if (dispatcher.notNull() || dispatcher->engage(this)) - { - mDispatcher = dispatcher; - return true; - } - return false; + if (mDispatcher.notNull()) + { + mDispatcher->disengage(this); + mDispatcher = NULL; + } + if (dispatcher.notNull() || dispatcher->engage(this)) + { + mDispatcher = dispatcher; + return true; + } + return false; } // Returns the current dispatcher pointer. // virtual LLEventDispatcher* LLObservable::getDispatcher() { - return mDispatcher; + return mDispatcher; } // Notifies the dispatcher of an event being fired. void LLObservable::fireEvent(LLPointer event, LLSD filter) { - if (mDispatcher.notNull()) - { - mDispatcher->fireEvent(event, filter); - } + if (mDispatcher.notNull()) + { + mDispatcher->fireEvent(event, filter); + } } /************************************************ @@ -109,134 +109,134 @@ void LLObservable::fireEvent(LLPointer event, LLSD filter) class LLEventDispatcher::Impl { public: - virtual ~Impl() { } - virtual bool engage(LLObservable* observable) { return true; } - virtual void disengage(LLObservable* observable) { } - - virtual void addListener(LLEventListener *listener, LLSD filter, const LLSD& userdata) = 0; - virtual void removeListener(LLEventListener *listener) = 0; - virtual std::vector getListeners() const = 0; - virtual bool fireEvent(LLPointer event, LLSD filter) = 0; + virtual ~Impl() { } + virtual bool engage(LLObservable* observable) { return true; } + virtual void disengage(LLObservable* observable) { } + + virtual void addListener(LLEventListener *listener, LLSD filter, const LLSD& userdata) = 0; + virtual void removeListener(LLEventListener *listener) = 0; + virtual std::vector getListeners() const = 0; + virtual bool fireEvent(LLPointer event, LLSD filter) = 0; }; bool LLEventDispatcher::engage(LLObservable* observable) { - return impl->engage(observable); + return impl->engage(observable); } void LLEventDispatcher::disengage(LLObservable* observable) { - impl->disengage(observable); + impl->disengage(observable); } void LLEventDispatcher::addListener(LLEventListener *listener, LLSD filter, const LLSD& userdata) { - impl->addListener(listener, filter, userdata); + impl->addListener(listener, filter, userdata); } void LLEventDispatcher::removeListener(LLEventListener *listener) { - impl->removeListener(listener); + impl->removeListener(listener); } std::vector LLEventDispatcher::getListeners() const { - return impl->getListeners(); + return impl->getListeners(); } bool LLEventDispatcher::fireEvent(LLPointer event, LLSD filter) { - return impl->fireEvent(event, filter); + return impl->fireEvent(event, filter); } class LLSimpleDispatcher : public LLEventDispatcher::Impl { public: - LLSimpleDispatcher(LLEventDispatcher *parent) : mParent(parent) { } - virtual ~LLSimpleDispatcher(); - virtual void addListener(LLEventListener* listener, LLSD filter, const LLSD& userdata); - virtual void removeListener(LLEventListener* listener); - virtual std::vector getListeners() const; - virtual bool fireEvent(LLPointer event, LLSD filter); + LLSimpleDispatcher(LLEventDispatcher *parent) : mParent(parent) { } + virtual ~LLSimpleDispatcher(); + virtual void addListener(LLEventListener* listener, LLSD filter, const LLSD& userdata); + virtual void removeListener(LLEventListener* listener); + virtual std::vector getListeners() const; + virtual bool fireEvent(LLPointer event, LLSD filter); protected: - std::vector mListeners; - LLEventDispatcher *mParent; + std::vector mListeners; + LLEventDispatcher *mParent; }; LLSimpleDispatcher::~LLSimpleDispatcher() { - while (mListeners.size() > 0) - { - removeListener(mListeners.begin()->listener); - } + while (mListeners.size() > 0) + { + removeListener(mListeners.begin()->listener); + } } void LLSimpleDispatcher::addListener(LLEventListener* listener, LLSD filter, const LLSD& userdata) { - if (listener == NULL) return; - removeListener(listener); - LLListenerEntry new_entry; - new_entry.listener = listener; - new_entry.filter = filter; - new_entry.userdata = userdata; - mListeners.push_back(new_entry); - listener->handleAttach(mParent); + if (listener == NULL) return; + removeListener(listener); + LLListenerEntry new_entry; + new_entry.listener = listener; + new_entry.filter = filter; + new_entry.userdata = userdata; + mListeners.push_back(new_entry); + listener->handleAttach(mParent); } void LLSimpleDispatcher::removeListener(LLEventListener* listener) { - std::vector::iterator itor = mListeners.begin(); - std::vector::iterator end = mListeners.end(); - for (; itor != end; ++itor) - { - if ((*itor).listener == listener) - { - mListeners.erase(itor); - break; - } - } - listener->handleDetach(mParent); + std::vector::iterator itor = mListeners.begin(); + std::vector::iterator end = mListeners.end(); + for (; itor != end; ++itor) + { + if ((*itor).listener == listener) + { + mListeners.erase(itor); + break; + } + } + listener->handleDetach(mParent); } std::vector LLSimpleDispatcher::getListeners() const { - std::vector ret; - for (const LLListenerEntry& entry : mListeners) - { - ret.push_back(entry); - } - - return ret; + std::vector ret; + for (const LLListenerEntry& entry : mListeners) + { + ret.push_back(entry); + } + + return ret; } // virtual bool LLSimpleDispatcher::fireEvent(LLPointer event, LLSD filter) { - std::string filter_string = filter.asString(); - for (LLListenerEntry& entry : mListeners) - { - if (filter_string == "" || entry.filter.asString() == filter_string) - { - (entry.listener)->handleEvent(event, entry.userdata); - } - } - return true; + std::string filter_string = filter.asString(); + for (LLListenerEntry& entry : mListeners) + { + if (filter_string == "" || entry.filter.asString() == filter_string) + { + (entry.listener)->handleEvent(event, entry.userdata); + } + } + return true; } LLEventDispatcher::LLEventDispatcher() { - impl = new LLSimpleDispatcher(this); + impl = new LLSimpleDispatcher(this); } LLEventDispatcher::~LLEventDispatcher() { - if (impl) - { - delete impl; - impl = NULL; - } + if (impl) + { + delete impl; + impl = NULL; + } } /************************************************ @@ -249,52 +249,52 @@ LLEventListener::~LLEventListener() LLSimpleListener::~LLSimpleListener() { - clearDispatchers(); + clearDispatchers(); } void LLSimpleListener::clearDispatchers() { - // Remove myself from all listening dispatchers - std::vector::iterator itor; - while (mDispatchers.size() > 0) - { - itor = mDispatchers.begin(); - LLEventDispatcher *dispatcher = *itor; - dispatcher->removeListener(this); - itor = mDispatchers.begin(); - if (itor != mDispatchers.end() && (*itor) == dispatcher) - { - // Somehow, the dispatcher was not removed. Remove it forcibly - mDispatchers.erase(itor); - } - } + // Remove myself from all listening dispatchers + std::vector::iterator itor; + while (mDispatchers.size() > 0) + { + itor = mDispatchers.begin(); + LLEventDispatcher *dispatcher = *itor; + dispatcher->removeListener(this); + itor = mDispatchers.begin(); + if (itor != mDispatchers.end() && (*itor) == dispatcher) + { + // Somehow, the dispatcher was not removed. Remove it forcibly + mDispatchers.erase(itor); + } + } } bool LLSimpleListener::handleAttach(LLEventDispatcher *dispatcher) { - // Add dispatcher if it doesn't already exist - for (LLEventDispatcher* disp : mDispatchers) - { - if (disp == dispatcher) return true; - } - mDispatchers.push_back(dispatcher); - return true; + // Add dispatcher if it doesn't already exist + for (LLEventDispatcher* disp : mDispatchers) + { + if (disp == dispatcher) return true; + } + mDispatchers.push_back(dispatcher); + return true; } bool LLSimpleListener::handleDetach(LLEventDispatcher *dispatcher) { - // Remove dispatcher from list - std::vector::iterator itor; - for (itor = mDispatchers.begin(); itor != mDispatchers.end(); ) - { - if ((*itor) == dispatcher) - { - itor = mDispatchers.erase(itor); - } - else - { - ++itor; - } - } - return true; + // Remove dispatcher from list + std::vector::iterator itor; + for (itor = mDispatchers.begin(); itor != mDispatchers.end(); ) + { + if ((*itor) == dispatcher) + { + itor = mDispatchers.erase(itor); + } + else + { + ++itor; + } + } + return true; } diff --git a/indra/llcommon/llevent.h b/indra/llcommon/llevent.h index 28ce7de102..4933f8d607 100644 --- a/indra/llcommon/llevent.h +++ b/indra/llcommon/llevent.h @@ -1,4 +1,4 @@ -/** +/** * @file llevent.h * @author Tom Yedwab * @brief LLEvent and LLEventListener base classes. @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -44,58 +44,58 @@ class LLObservable; class LL_COMMON_API LLEvent : public LLThreadSafeRefCount { protected: - virtual ~LLEvent(); - + virtual ~LLEvent(); + public: - LLEvent(LLObservable* source, const std::string& desc = "") : mSource(source), mDesc(desc) { } - - LLObservable* getSource() { return mSource; } - virtual LLSD getValue() { return LLSD(); } - // Determines whether this particular listener - // should be notified of this event. - // If this function returns true, handleEvent is - // called on the listener with this event as the - // argument. - // Defaults to handling all events. Override this - // if associated with an Observable with many different listeners - virtual bool accept(LLEventListener* listener); - - // return a string describing the event - virtual const std::string& desc(); + LLEvent(LLObservable* source, const std::string& desc = "") : mSource(source), mDesc(desc) { } + + LLObservable* getSource() { return mSource; } + virtual LLSD getValue() { return LLSD(); } + // Determines whether this particular listener + // should be notified of this event. + // If this function returns true, handleEvent is + // called on the listener with this event as the + // argument. + // Defaults to handling all events. Override this + // if associated with an Observable with many different listeners + virtual bool accept(LLEventListener* listener); + + // return a string describing the event + virtual const std::string& desc(); private: - LLObservable* mSource; - std::string mDesc; + LLObservable* mSource; + std::string mDesc; }; // Abstract listener. All listeners derive from LLEventListener class LL_COMMON_API LLEventListener : public LLThreadSafeRefCount { protected: - virtual ~LLEventListener(); - + virtual ~LLEventListener(); + public: - // Processes the event. - // TODO: Make the return value less ambiguous? - virtual bool handleEvent(LLPointer event, const LLSD& userdata) = 0; + // Processes the event. + // TODO: Make the return value less ambiguous? + virtual bool handleEvent(LLPointer event, const LLSD& userdata) = 0; - // Called when an dispatcher starts/stops listening - virtual bool handleAttach(LLEventDispatcher *dispatcher) = 0; - virtual bool handleDetach(LLEventDispatcher *dispatcher) = 0; + // Called when an dispatcher starts/stops listening + virtual bool handleAttach(LLEventDispatcher *dispatcher) = 0; + virtual bool handleDetach(LLEventDispatcher *dispatcher) = 0; }; // A listener which tracks references to it and cleans up when it's deallocated class LL_COMMON_API LLSimpleListener : public LLEventListener { public: - void clearDispatchers(); - virtual bool handleAttach(LLEventDispatcher *dispatcher); - virtual bool handleDetach(LLEventDispatcher *dispatcher); + void clearDispatchers(); + virtual bool handleAttach(LLEventDispatcher *dispatcher); + virtual bool handleDetach(LLEventDispatcher *dispatcher); protected: - ~LLSimpleListener(); - std::vector mDispatchers; + ~LLSimpleListener(); + std::vector mDispatchers; }; class LLObservable; // defined below @@ -103,9 +103,9 @@ class LLObservable; // defined below // A structure which stores a Listener and its metadata struct LLListenerEntry { - LLEventListener* listener; - LLSD filter; - LLSD userdata; + LLEventListener* listener; + LLSD filter; + LLSD userdata; }; // Base class for a dispatcher - an object which listens @@ -114,40 +114,40 @@ struct LLListenerEntry class LL_COMMON_API LLEventDispatcher : public LLThreadSafeRefCount { protected: - virtual ~LLEventDispatcher(); - + virtual ~LLEventDispatcher(); + public: - // The default constructor creates a default simple dispatcher implementation. - // The simple implementation has an array of listeners and fires every event to - // all of them. - LLEventDispatcher(); - - // This dispatcher is being attached to an observable object. - // If we return false, the attach fails. - bool engage(LLObservable* observable); + // The default constructor creates a default simple dispatcher implementation. + // The simple implementation has an array of listeners and fires every event to + // all of them. + LLEventDispatcher(); + + // This dispatcher is being attached to an observable object. + // If we return false, the attach fails. + bool engage(LLObservable* observable); - // This dispatcher is being detached from an observable object. - void disengage(LLObservable* observable); + // This dispatcher is being detached from an observable object. + void disengage(LLObservable* observable); - // Adds a listener to this dispatcher, with a given user data - // that will be passed to the listener when an event is fired. - // Duplicate pointers are removed on addtion. - void addListener(LLEventListener *listener, LLSD filter, const LLSD& userdata); + // Adds a listener to this dispatcher, with a given user data + // that will be passed to the listener when an event is fired. + // Duplicate pointers are removed on addtion. + void addListener(LLEventListener *listener, LLSD filter, const LLSD& userdata); - // Removes a listener from this dispatcher - void removeListener(LLEventListener *listener); + // Removes a listener from this dispatcher + void removeListener(LLEventListener *listener); - // Gets a list of interested listeners - std::vector getListeners() const; + // Gets a list of interested listeners + std::vector getListeners() const; - // Handle an event that has just been fired by communicating it - // to listeners, passing it across a network, etc. - bool fireEvent(LLPointer event, LLSD filter); + // Handle an event that has just been fired by communicating it + // to listeners, passing it across a network, etc. + bool fireEvent(LLPointer event, LLSD filter); public: - class Impl; + class Impl; private: - Impl* impl; + Impl* impl; }; // Interface for observable data (data that fires events) @@ -157,38 +157,38 @@ private: class LL_COMMON_API LLObservable { public: - // Initialize with the default Dispatcher - LLObservable(); - virtual ~LLObservable(); - - // Replaces the existing dispatcher pointer to the new one, - // informing the dispatcher of the change. - virtual bool setDispatcher(LLPointer dispatcher); - - // Returns the current dispatcher pointer. - virtual LLEventDispatcher* getDispatcher(); - - void addListener(LLEventListener *listener, LLSD filter = "", const LLSD& userdata = "") - { - if (mDispatcher.notNull()) mDispatcher->addListener(listener, filter, userdata); - } - void removeListener(LLEventListener *listener) - { - if (mDispatcher.notNull()) mDispatcher->removeListener(listener); - } - // Notifies the dispatcher of an event being fired. - void fireEvent(LLPointer event, LLSD filter = LLSD()); + // Initialize with the default Dispatcher + LLObservable(); + virtual ~LLObservable(); + + // Replaces the existing dispatcher pointer to the new one, + // informing the dispatcher of the change. + virtual bool setDispatcher(LLPointer dispatcher); + + // Returns the current dispatcher pointer. + virtual LLEventDispatcher* getDispatcher(); + + void addListener(LLEventListener *listener, LLSD filter = "", const LLSD& userdata = "") + { + if (mDispatcher.notNull()) mDispatcher->addListener(listener, filter, userdata); + } + void removeListener(LLEventListener *listener) + { + if (mDispatcher.notNull()) mDispatcher->removeListener(listener); + } + // Notifies the dispatcher of an event being fired. + void fireEvent(LLPointer event, LLSD filter = LLSD()); protected: - LLPointer mDispatcher; + LLPointer mDispatcher; }; class LLValueChangedEvent : public LLEvent { public: - LLValueChangedEvent(LLObservable* source, LLSD value) : LLEvent(source, "value_changed"), mValue(value) { } - LLSD getValue() { return mValue; } - LLSD mValue; + LLValueChangedEvent(LLObservable* source, LLSD value) : LLEvent(source, "value_changed"), mValue(value) { } + LLSD getValue() { return mValue; } + LLSD mValue; }; } // LLOldEvents diff --git a/indra/llcommon/lleventapi.cpp b/indra/llcommon/lleventapi.cpp index 3d46ef1034..8b724256b8 100644 --- a/indra/llcommon/lleventapi.cpp +++ b/indra/llcommon/lleventapi.cpp @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2009-11-10 * @brief Implementation for lleventapi. - * + * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcommon/lleventapi.h b/indra/llcommon/lleventapi.h index 25f6becd8b..3ae820db51 100644 --- a/indra/llcommon/lleventapi.h +++ b/indra/llcommon/lleventapi.h @@ -5,25 +5,25 @@ * @brief LLEventAPI is the base class for every class that wraps a C++ API * in an event API * (see https://wiki.lindenlab.com/wiki/Incremental_Viewer_Automation/Event_API). - * + * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcommon/lleventcoro.cpp b/indra/llcommon/lleventcoro.cpp index 067b5e6fbc..e1fc4764f6 100644 --- a/indra/llcommon/lleventcoro.cpp +++ b/indra/llcommon/lleventcoro.cpp @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2009-04-29 * @brief Implementation for lleventcoro. - * + * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcommon/lleventcoro.h b/indra/llcommon/lleventcoro.h index c0fe8b094f..492563bb98 100644 --- a/indra/llcommon/lleventcoro.h +++ b/indra/llcommon/lleventcoro.h @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2009-04-29 * @brief Utilities to interface between coroutines and events. - * + * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -152,7 +152,7 @@ LLSD postAndSuspendWithTimeout(const LLSD& event, F32 timeout, const LLSD& timeoutResult); /// Suspend the coroutine until an event is fired on the identified pump -/// or the timeout duration has elapsed. If the timeout duration +/// or the timeout duration has elapsed. If the timeout duration /// elapses the specified LLSD is returned. inline LLSD suspendUntilEventOnWithTimeout(const LLEventPumpOrPumpName& suspendPumpOrName, diff --git a/indra/llcommon/lleventdispatcher.cpp b/indra/llcommon/lleventdispatcher.cpp index da96de18f7..9dd6864cff 100644 --- a/indra/llcommon/lleventdispatcher.cpp +++ b/indra/llcommon/lleventdispatcher.cpp @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2009-06-18 * @brief Implementation for lleventdispatcher. - * + * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -755,7 +755,7 @@ std::string LLEventDispatcher::getState() const bool LLEventDispatcher::setState(SetState&, const std::string& state) const { - // If SetState is instantiated at multiple levels of function call, ignore + // If SetState is instantiated at multiple levels of function call, ignore // the lower-level call because the outer call presumably provides more // context. if (mState.get()) diff --git a/indra/llcommon/lleventdispatcher.h b/indra/llcommon/lleventdispatcher.h index a82bc7a69b..4c3c0f3414 100644 --- a/indra/llcommon/lleventdispatcher.h +++ b/indra/llcommon/lleventdispatcher.h @@ -6,25 +6,25 @@ * useful when you have a single LLEventPump listener on which you can * request different operations, vs. instantiating a different * LLEventPump for each such operation. - * + * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -201,7 +201,7 @@ public: template ::type, LLSD>::value - >::type> + >::type> void add(const std::string& name, const std::string& desc, R (CLASS::*method)(ARG)) @@ -213,7 +213,7 @@ public: template ::type, LLSD>::value - >::type> + >::type> void add(const std::string& name, const std::string& desc, R (CLASS::*method)(ARG) const) @@ -226,7 +226,7 @@ public: template ::type, LLSD>::value - >::type> + >::type> void add(const std::string& name, const std::string& desc, void (CLASS::*method)(ARG)) @@ -238,7 +238,7 @@ public: template ::type, LLSD>::value - >::type> + >::type> void add(const std::string& name, const std::string& desc, void (CLASS::*method)(ARG) const) @@ -247,7 +247,7 @@ public: } // non-const binary (or more) method - template + template void add(const std::string& name, const std::string& desc, R (CLASS::*method)(ARG0, ARG1, ARGS...)) @@ -256,7 +256,7 @@ public: } // const binary (or more) method - template + template void add(const std::string& name, const std::string& desc, R (CLASS::*method)(ARG0, ARG1, ARGS...) const) @@ -265,7 +265,7 @@ public: } // non-const binary (or more) method returning void - template + template void add(const std::string& name, const std::string& desc, void (CLASS::*method)(ARG0, ARG1, ARGS...)) @@ -274,7 +274,7 @@ public: } // const binary (or more) method returning void - template + template void add(const std::string& name, const std::string& desc, void (CLASS::*method)(ARG0, ARG1, ARGS...) const) @@ -371,7 +371,7 @@ public: const InstanceGetter& getter, const LLSD& params, const LLSD& defaults=LLSD()); - //@} + //@} /// Unregister a callable bool remove(const std::string& name); diff --git a/indra/llcommon/lleventemitter.h b/indra/llcommon/lleventemitter.h index cd82fc56f9..14160e1e76 100644 --- a/indra/llcommon/lleventemitter.h +++ b/indra/llcommon/lleventemitter.h @@ -1,25 +1,25 @@ -/** +/** * @file lleventemitter.h * @brief General event emitter class * * $LicenseInfo:firstyear=2005&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -38,65 +38,65 @@ #include "stdtypes.h" /////////////////////////////////////////////////////////////////////////////// -// templatized emitter class +// templatized emitter class template < class T > class eventEmitter { - public: - typedef typename T::EventType EventType; - typedef std::list< T* > ObserverContainer; - typedef void ( T::*observerMethod )( const EventType& ); + public: + typedef typename T::EventType EventType; + typedef std::list< T* > ObserverContainer; + typedef void ( T::*observerMethod )( const EventType& ); - protected: - ObserverContainer observers; + protected: + ObserverContainer observers; - public: - eventEmitter () { }; + public: + eventEmitter () { }; - ~eventEmitter () { }; + ~eventEmitter () { }; - /////////////////////////////////////////////////////////////////////////////// - // - BOOL addObserver ( T* observerIn ) - { - if ( ! observerIn ) - return FALSE; + /////////////////////////////////////////////////////////////////////////////// + // + BOOL addObserver ( T* observerIn ) + { + if ( ! observerIn ) + return FALSE; - // check if observer already exists - if ( std::find ( observers.begin (), observers.end (), observerIn ) != observers.end () ) - return FALSE; + // check if observer already exists + if ( std::find ( observers.begin (), observers.end (), observerIn ) != observers.end () ) + return FALSE; - // save it - observers.push_back ( observerIn ); + // save it + observers.push_back ( observerIn ); - return true; - }; + return true; + }; - /////////////////////////////////////////////////////////////////////////////// - // - BOOL remObserver ( T* observerIn ) - { - if ( ! observerIn ) - return FALSE; + /////////////////////////////////////////////////////////////////////////////// + // + BOOL remObserver ( T* observerIn ) + { + if ( ! observerIn ) + return FALSE; - observers.remove ( observerIn ); + observers.remove ( observerIn ); - return TRUE; - }; + return TRUE; + }; - /////////////////////////////////////////////////////////////////////////////// - // - void update ( observerMethod method, const EventType& msgIn ) - { - typename std::list< T* >::iterator iter = observers.begin (); + /////////////////////////////////////////////////////////////////////////////// + // + void update ( observerMethod method, const EventType& msgIn ) + { + typename std::list< T* >::iterator iter = observers.begin (); - while ( iter != observers.end () ) - { - ( ( *iter )->*method ) ( msgIn ); + while ( iter != observers.end () ) + { + ( ( *iter )->*method ) ( msgIn ); - ++iter; - }; - }; + ++iter; + }; + }; }; #endif // lleventemitter_h diff --git a/indra/llcommon/lleventfilter.cpp b/indra/llcommon/lleventfilter.cpp index 4cded7f88e..604ee8a42d 100644 --- a/indra/llcommon/lleventfilter.cpp +++ b/indra/llcommon/lleventfilter.cpp @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2009-03-05 * @brief Implementation for lleventfilter. - * + * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcommon/lleventfilter.h b/indra/llcommon/lleventfilter.h index 1fb41e0297..5c45144fad 100644 --- a/indra/llcommon/lleventfilter.h +++ b/indra/llcommon/lleventfilter.h @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2009-03-05 * @brief Define LLEventFilter: LLEventStream subclass with conditions - * + * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -149,11 +149,11 @@ public: /** * Like actionAfter(), but where the desired Action is a particular event * for all listeners. Pass the timeout time and the desired @a event data. - * + * * Suppose the timeout should only be satisfied by a particular event, but * the ultimate listener must see all other incoming events as well, plus * the timeout @a event if any: - * + * * @code * some LLEventMatching LLEventMatching * event ---> for particular ---> LLEventTimeout ---> for timeout @@ -161,7 +161,7 @@ public: * \ \ ultimate * `-----------------------------------------------------> listener * @endcode - * + * * Since a given listener can listen on more than one LLEventPump, we can * set things up so it sees the set union of events from LLEventTimeout * and the original event source. However, as LLEventTimeout passes @@ -197,8 +197,8 @@ private: /** * Production implementation of LLEventTimoutBase. - * - * @NOTE: Caution should be taken when using the LLEventTimeout(LLEventPump &) + * + * @NOTE: Caution should be taken when using the LLEventTimeout(LLEventPump &) * constructor to ensure that the upstream event pump is not an LLEventMaildrop * or any other kind of store and forward pump which may have events outstanding. * Using this constructor will cause the upstream event pump to fire any pending @@ -207,7 +207,7 @@ private: * from the event pump and attached using the listen method. * See llcoro::suspendUntilEventOnWithTimeout() for an example. */ - + class LL_COMMON_API LLEventTimeout: public LLEventTimeoutBase { public: diff --git a/indra/llcommon/llevents.cpp b/indra/llcommon/llevents.cpp index 70931f3a65..5b4e69659d 100644 --- a/indra/llcommon/llevents.cpp +++ b/indra/llcommon/llevents.cpp @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2008-09-12 * @brief Implementation for llevents. - * + * * $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$ */ @@ -423,8 +423,8 @@ LLBoundListener LLEventPump::listen_impl(const std::string& name, const LLEventL float nodePosition = 1.0; - // if the supplied name is empty we are not interested in the ordering mechanism - // and can bypass attempting to find the optimal location to insert the new + // if the supplied name is empty we are not interested in the ordering mechanism + // and can bypass attempting to find the optimal location to insert the new // listener. We'll just tack it on to the end. if (!name.empty()) // should be the same as testing against ANONYMOUS { @@ -569,12 +569,12 @@ LLBoundListener LLEventPump::listen_impl(const std::string& name, const LLEventL // Now that newNode has a value that places it appropriately in mSignal, // connect it. LLBoundListener bound = mSignal->connect(nodePosition, listener); - + if (!name.empty()) { // note that we are not tracking anonymous listeners here either. - // This means that it is the caller's responsibility to either assign - // to a TempBoundListerer (scoped_connection) or manually disconnect - // when done. + // This means that it is the caller's responsibility to either assign + // to a TempBoundListerer (scoped_connection) or manually disconnect + // when done. mConnections[name] = bound; } return bound; @@ -641,9 +641,9 @@ bool LLEventMailDrop::post(const LLSD& event) { // forward the call to our base class bool posted = LLEventStream::post(event); - + if (!posted) - { // if the event was not handled we will save it for later so that it can + { // if the event was not handled we will save it for later so that it can // be posted to any future listeners when they attach. mEventHistory.push_back(event); } diff --git a/indra/llcommon/llevents.h b/indra/llcommon/llevents.h index bebcfacdcb..9a0a6863f0 100644 --- a/indra/llcommon/llevents.h +++ b/indra/llcommon/llevents.h @@ -6,25 +6,25 @@ * https://wiki.lindenlab.com/wiki/Viewer:Messaging/Event_System, * originally introduced in llnotifications.h. It has nothing * whatsoever to do with the older system in llevent.h. - * + * * $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$ */ @@ -39,13 +39,13 @@ #include #include #if LL_WINDOWS - #pragma warning (push) - #pragma warning (disable : 4263) // boost::signals2::expired_slot::what() has const mismatch - #pragma warning (disable : 4264) + #pragma warning (push) + #pragma warning (disable : 4263) // boost::signals2::expired_slot::what() has const mismatch + #pragma warning (disable : 4264) #endif #include #if LL_WINDOWS - #pragma warning (pop) + #pragma warning (pop) #endif #include @@ -310,9 +310,9 @@ public: /** * Find the named LLEventPump instance. If it exists post the message to it. * If the pump does not exist, do nothing. - * + * * returns the result of the LLEventPump::post. If no pump exists returns false. - * + * * This is syntactically similar to LLEventPumps::instance().post(name, message), * however if the pump does not already exist it will not be created. */ @@ -541,10 +541,10 @@ public: * instantiate your listener, then passing the same name on each listen() * call, allows us to optimize away the second and subsequent dependency * sorts. - * - * If name is set to LLEventPump::ANONYMOUS listen will bypass the entire - * dependency and ordering calculation. In this case, it is critical that - * the result be assigned to a LLTempBoundListener or the listener is + * + * If name is set to LLEventPump::ANONYMOUS listen will bypass the entire + * dependency and ordering calculation. In this case, it is critical that + * the result be assigned to a LLTempBoundListener or the listener is * manually disconnected when no longer needed since there will be no * way to later find and disconnect this listener manually. */ @@ -607,7 +607,7 @@ protected: virtual LLBoundListener listen_impl(const std::string& name, const LLEventListener&, const NameList& after, const NameList& before); - + /// implement the dispatching std::shared_ptr mSignal; @@ -660,21 +660,21 @@ public: * by all listeners, until some listener consumes it. The caveat is that each * event *must* eventually reach a listener that will consume it, else the * queue will grow to arbitrary length. - * + * * @NOTE: When using an LLEventMailDrop with an LLEventTimeout or * LLEventFilter attaching the filter downstream, using Timeout's constructor will - * cause the MailDrop to discharge any of its stored events. The timeout should - * instead be connected upstream using its listen() method. + * cause the MailDrop to discharge any of its stored events. The timeout should + * instead be connected upstream using its listen() method. */ class LL_COMMON_API LLEventMailDrop : public LLEventStream { public: LLEventMailDrop(const std::string& name, bool tweak = false) : LLEventStream(name, tweak) {} virtual ~LLEventMailDrop() {} - + /// Post an event to all listeners virtual bool post(const LLSD& event) override; - + /// Remove any history stored in the mail drop. void discard(); diff --git a/indra/llcommon/lleventtimer.cpp b/indra/llcommon/lleventtimer.cpp index f575a7b6bf..33fafffefd 100644 --- a/indra/llcommon/lleventtimer.cpp +++ b/indra/llcommon/lleventtimer.cpp @@ -1,25 +1,25 @@ -/** +/** * @file lleventtimer.cpp - * @brief Cross-platform objects for doing timing + * @brief Cross-platform objects for doing timing * * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -33,20 +33,20 @@ ////////////////////////////////////////////////////////////////////////////// // -// LLEventTimer Implementation +// LLEventTimer Implementation // ////////////////////////////////////////////////////////////////////////////// LLEventTimer::LLEventTimer(F32 period) : mEventTimer() { - mPeriod = period; + mPeriod = period; } LLEventTimer::LLEventTimer(const LLDate& time) : mEventTimer() { - mPeriod = (F32)(time.secondsSinceEpoch() - LLDate::now().secondsSinceEpoch()); + mPeriod = (F32)(time.secondsSinceEpoch() - LLDate::now().secondsSinceEpoch()); } @@ -55,19 +55,19 @@ LLEventTimer::~LLEventTimer() } //static -void LLEventTimer::updateClass() +void LLEventTimer::updateClass() { - for (auto& timer : instance_snapshot()) - { - F32 et = timer.mEventTimer.getElapsedTimeF32(); - if (timer.mEventTimer.getStarted() && et > timer.mPeriod) { - timer.mEventTimer.reset(); - if ( timer.tick() ) - { - delete &timer; - } - } - } + for (auto& timer : instance_snapshot()) + { + F32 et = timer.mEventTimer.getElapsedTimeF32(); + if (timer.mEventTimer.getStarted() && et > timer.mPeriod) { + timer.mEventTimer.reset(); + if ( timer.tick() ) + { + delete &timer; + } + } + } } diff --git a/indra/llcommon/lleventtimer.h b/indra/llcommon/lleventtimer.h index dbbfe0c6e6..ed6f10d5e1 100644 --- a/indra/llcommon/lleventtimer.h +++ b/indra/llcommon/lleventtimer.h @@ -1,30 +1,30 @@ -/** +/** * @file lleventtimer.h - * @brief Cross-platform objects for doing timing + * @brief Cross-platform objects for doing timing * * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ -#ifndef LL_EVENTTIMER_H +#ifndef LL_EVENTTIMER_H #define LL_EVENTTIMER_H #include "stdtypes.h" @@ -37,42 +37,42 @@ class LL_COMMON_API LLEventTimer : public LLInstanceTracker { public: - LLEventTimer(F32 period); // period is the amount of time between each call to tick() in seconds - LLEventTimer(const LLDate& time); - virtual ~LLEventTimer(); + LLEventTimer(F32 period); // period is the amount of time between each call to tick() in seconds + LLEventTimer(const LLDate& time); + virtual ~LLEventTimer(); - //function to be called at the supplied frequency - // Normally return FALSE; TRUE will delete the timer after the function returns. - virtual BOOL tick() = 0; + //function to be called at the supplied frequency + // Normally return FALSE; TRUE will delete the timer after the function returns. + virtual BOOL tick() = 0; - static void updateClass(); + static void updateClass(); - /// Schedule recurring calls to generic callable every period seconds. - /// Returns a pointer; if you delete it, cancels the recurring calls. - template - static LLEventTimer* run_every(F32 period, const CALLABLE& callable); + /// Schedule recurring calls to generic callable every period seconds. + /// Returns a pointer; if you delete it, cancels the recurring calls. + template + static LLEventTimer* run_every(F32 period, const CALLABLE& callable); - /// Schedule a future call to generic callable. Returns a pointer. - /// CAUTION: The object referenced by that pointer WILL BE DELETED once - /// the callback has been called! LLEventTimer::getInstance(pointer) (NOT - /// pointer->getInstance(pointer)!) can be used to test whether the - /// pointer is still valid. If it is, deleting it will cancel the - /// callback. - template - static LLEventTimer* run_at(const LLDate& time, const CALLABLE& callable); + /// Schedule a future call to generic callable. Returns a pointer. + /// CAUTION: The object referenced by that pointer WILL BE DELETED once + /// the callback has been called! LLEventTimer::getInstance(pointer) (NOT + /// pointer->getInstance(pointer)!) can be used to test whether the + /// pointer is still valid. If it is, deleting it will cancel the + /// callback. + template + static LLEventTimer* run_at(const LLDate& time, const CALLABLE& callable); - /// Like run_at(), but after a time delta rather than at a timestamp. - /// Same CAUTION. - template - static LLEventTimer* run_after(F32 interval, const CALLABLE& callable); + /// Like run_at(), but after a time delta rather than at a timestamp. + /// Same CAUTION. + template + static LLEventTimer* run_after(F32 interval, const CALLABLE& callable); protected: - LLTimer mEventTimer; - F32 mPeriod; + LLTimer mEventTimer; + F32 mPeriod; private: - template - class Generic; + template + class Generic; }; template diff --git a/indra/llcommon/llexception.cpp b/indra/llcommon/llexception.cpp index 0787bde57f..c0154a569f 100644 --- a/indra/llcommon/llexception.cpp +++ b/indra/llcommon/llexception.cpp @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2016-08-12 * @brief Implementation for llexception. - * + * * $LicenseInfo:firstyear=2016&license=viewerlgpl$ * Copyright (c) 2016, Linden Research, Inc. * $/LicenseInfo$ @@ -99,8 +99,8 @@ static const U32 STATUS_MSC_EXCEPTION = 0xE06D7363; // compiler specific U32 msc_exception_filter(U32 code, struct _EXCEPTION_POINTERS *exception_infop) { const auto stack = to_string(boost::stacktrace::stacktrace()); - LL_WARNS() << "SEH Exception handled (that probably shouldn't be): Code " << code - << "\n Stack trace: \n" + LL_WARNS() << "SEH Exception handled (that probably shouldn't be): Code " << code + << "\n Stack trace: \n" << stack << LL_ENDL; if (code == STATUS_MSC_EXCEPTION) diff --git a/indra/llcommon/llexception.h b/indra/llcommon/llexception.h index 375bea4a57..68e609444e 100644 --- a/indra/llcommon/llexception.h +++ b/indra/llcommon/llexception.h @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2016-06-29 * @brief Types needed for generic exception handling - * + * * $LicenseInfo:firstyear=2016&license=viewerlgpl$ * Copyright (c) 2016, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/llfasttimer.cpp b/indra/llcommon/llfasttimer.cpp index 2612d0f07c..722743f453 100644 --- a/indra/llcommon/llfasttimer.cpp +++ b/indra/llcommon/llfasttimer.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llfasttimer.cpp * @brief Implementation of the fast timer. * * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -49,8 +49,8 @@ #include "lltimer.h" #elif LL_DARWIN #include -#include "lltimer.h" // get_clock_count() -#else +#include "lltimer.h" // get_clock_count() +#else #error "architecture not supported" #endif @@ -60,7 +60,7 @@ namespace LLTrace ////////////////////////////////////////////////////////////////////////////// // statics -bool BlockTimer::sLog = false; +bool BlockTimer::sLog = false; std::string BlockTimer::sLogName = ""; bool BlockTimer::sMetricLog = false; @@ -70,83 +70,83 @@ U64 BlockTimer::sClockResolution = 1000000000; // Nanosecond resolution U64 BlockTimer::sClockResolution = 1000000; // Microsecond resolution #endif -static LLMutex* sLogLock = NULL; +static LLMutex* sLogLock = NULL; static std::queue sLogQueue; -block_timer_tree_df_iterator_t begin_block_timer_tree_df(BlockTimerStatHandle& id) -{ - return block_timer_tree_df_iterator_t(&id, - boost::bind(boost::mem_fn(&BlockTimerStatHandle::beginChildren), _1), - boost::bind(boost::mem_fn(&BlockTimerStatHandle::endChildren), _1)); +block_timer_tree_df_iterator_t begin_block_timer_tree_df(BlockTimerStatHandle& id) +{ + return block_timer_tree_df_iterator_t(&id, + boost::bind(boost::mem_fn(&BlockTimerStatHandle::beginChildren), _1), + boost::bind(boost::mem_fn(&BlockTimerStatHandle::endChildren), _1)); } -block_timer_tree_df_iterator_t end_block_timer_tree_df() -{ - return block_timer_tree_df_iterator_t(); +block_timer_tree_df_iterator_t end_block_timer_tree_df() +{ + return block_timer_tree_df_iterator_t(); } -block_timer_tree_df_post_iterator_t begin_block_timer_tree_df_post(BlockTimerStatHandle& id) -{ - return block_timer_tree_df_post_iterator_t(&id, - boost::bind(boost::mem_fn(&BlockTimerStatHandle::beginChildren), _1), - boost::bind(boost::mem_fn(&BlockTimerStatHandle::endChildren), _1)); +block_timer_tree_df_post_iterator_t begin_block_timer_tree_df_post(BlockTimerStatHandle& id) +{ + return block_timer_tree_df_post_iterator_t(&id, + boost::bind(boost::mem_fn(&BlockTimerStatHandle::beginChildren), _1), + boost::bind(boost::mem_fn(&BlockTimerStatHandle::endChildren), _1)); } -block_timer_tree_df_post_iterator_t end_block_timer_tree_df_post() -{ - return block_timer_tree_df_post_iterator_t(); +block_timer_tree_df_post_iterator_t end_block_timer_tree_df_post() +{ + return block_timer_tree_df_post_iterator_t(); } block_timer_tree_bf_iterator_t begin_block_timer_tree_bf(BlockTimerStatHandle& id) -{ - return block_timer_tree_bf_iterator_t(&id, - boost::bind(boost::mem_fn(&BlockTimerStatHandle::beginChildren), _1), - boost::bind(boost::mem_fn(&BlockTimerStatHandle::endChildren), _1)); +{ + return block_timer_tree_bf_iterator_t(&id, + boost::bind(boost::mem_fn(&BlockTimerStatHandle::beginChildren), _1), + boost::bind(boost::mem_fn(&BlockTimerStatHandle::endChildren), _1)); } block_timer_tree_bf_iterator_t end_block_timer_tree_bf() - { - return block_timer_tree_bf_iterator_t(); - } - -block_timer_tree_df_iterator_t begin_timer_tree(BlockTimerStatHandle& id) - { - return block_timer_tree_df_iterator_t(&id, - boost::bind(boost::mem_fn(&BlockTimerStatHandle::beginChildren), _1), - boost::bind(boost::mem_fn(&BlockTimerStatHandle::endChildren), _1)); - } - -block_timer_tree_df_iterator_t end_timer_tree() - { - return block_timer_tree_df_iterator_t(); + { + return block_timer_tree_bf_iterator_t(); + } + +block_timer_tree_df_iterator_t begin_timer_tree(BlockTimerStatHandle& id) + { + return block_timer_tree_df_iterator_t(&id, + boost::bind(boost::mem_fn(&BlockTimerStatHandle::beginChildren), _1), + boost::bind(boost::mem_fn(&BlockTimerStatHandle::endChildren), _1)); + } + +block_timer_tree_df_iterator_t end_timer_tree() + { + return block_timer_tree_df_iterator_t(); } // sort child timers by name struct SortTimerByName - { - bool operator()(const BlockTimerStatHandle* i1, const BlockTimerStatHandle* i2) - { - return i1->getName() < i2->getName(); - } + { + bool operator()(const BlockTimerStatHandle* i1, const BlockTimerStatHandle* i2) + { + return i1->getName() < i2->getName(); + } }; static BlockTimerStatHandle sRootTimer("root", NULL); BlockTimerStatHandle& BlockTimer::getRootTimeBlock() { - return sRootTimer; - } + return sRootTimer; + } void BlockTimer::pushLog(LLSD log) { - LLMutexLock lock(sLogLock); + LLMutexLock lock(sLogLock); - sLogQueue.push(log); + sLogQueue.push(log); } void BlockTimer::setLogLock(LLMutex* lock) { - sLogLock = lock; + sLogLock = lock; } @@ -154,40 +154,40 @@ void BlockTimer::setLogLock(LLMutex* lock) #if (LL_DARWIN || LL_LINUX) && !(defined(__i386__) || defined(__amd64__)) U64 BlockTimer::countsPerSecond() { - return sClockResolution; + return sClockResolution; } #else // windows or x86-mac or x86-linux U64 BlockTimer::countsPerSecond() { #if LL_FASTTIMER_USE_RDTSC || !LL_WINDOWS - //getCPUFrequency returns MHz and sCPUClockFrequency wants to be in Hz - static LLUnit sCPUClockFrequency = LLProcessorInfo().getCPUFrequency(); - return sCPUClockFrequency.value(); + //getCPUFrequency returns MHz and sCPUClockFrequency wants to be in Hz + static LLUnit sCPUClockFrequency = LLProcessorInfo().getCPUFrequency(); + return sCPUClockFrequency.value(); #else - // If we're not using RDTSC, each fasttimer tick is just a performance counter tick. - // Not redefining the clock frequency itself (in llprocessor.cpp/calculate_cpu_frequency()) - // since that would change displayed MHz stats for CPUs - static bool firstcall = true; - static U64 sCPUClockFrequency; - if (firstcall) - { - QueryPerformanceFrequency((LARGE_INTEGER*)&sCPUClockFrequency); - firstcall = false; - } - return sCPUClockFrequency.value(); + // If we're not using RDTSC, each fasttimer tick is just a performance counter tick. + // Not redefining the clock frequency itself (in llprocessor.cpp/calculate_cpu_frequency()) + // since that would change displayed MHz stats for CPUs + static bool firstcall = true; + static U64 sCPUClockFrequency; + if (firstcall) + { + QueryPerformanceFrequency((LARGE_INTEGER*)&sCPUClockFrequency); + firstcall = false; + } + return sCPUClockFrequency.value(); #endif } #endif BlockTimerStatHandle::BlockTimerStatHandle(const char* name, const char* description) -: StatType(name, description) +: StatType(name, description) {} TimeBlockTreeNode& BlockTimerStatHandle::getTreeNode() const { - TimeBlockTreeNode* nodep = LLTrace::get_thread_recorder()->getTimeBlockTreeNode(getIndex()); - llassert(nodep); - return *nodep; + TimeBlockTreeNode* nodep = LLTrace::get_thread_recorder()->getTimeBlockTreeNode(getIndex()); + llassert(nodep); + return *nodep; } @@ -223,71 +223,71 @@ void BlockTimer::bootstrapTimerTree() void BlockTimer::incrementalUpdateTimerTree() { LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - for(block_timer_tree_df_post_iterator_t it = begin_block_timer_tree_df_post(BlockTimer::getRootTimeBlock()); - it != end_block_timer_tree_df_post(); - ++it) - { - BlockTimerStatHandle* timerp = *it; - - // sort timers by time last called, so call graph makes sense - TimeBlockTreeNode& tree_node = timerp->getTreeNode(); - if (tree_node.mNeedsSorting) + for(block_timer_tree_df_post_iterator_t it = begin_block_timer_tree_df_post(BlockTimer::getRootTimeBlock()); + it != end_block_timer_tree_df_post(); + ++it) + { + BlockTimerStatHandle* timerp = *it; + + // sort timers by time last called, so call graph makes sense + TimeBlockTreeNode& tree_node = timerp->getTreeNode(); + if (tree_node.mNeedsSorting) { - std::sort(tree_node.mChildren.begin(), tree_node.mChildren.end(), SortTimerByName()); + std::sort(tree_node.mChildren.begin(), tree_node.mChildren.end(), SortTimerByName()); } - // skip root timer - if (timerp != &BlockTimer::getRootTimeBlock()) + // skip root timer + if (timerp != &BlockTimer::getRootTimeBlock()) { - TimeBlockAccumulator& accumulator = timerp->getCurrentAccumulator(); + TimeBlockAccumulator& accumulator = timerp->getCurrentAccumulator(); - if (accumulator.mMoveUpTree) + if (accumulator.mMoveUpTree) { - // since ancestors have already been visited, re-parenting won't affect tree traversal - //step up tree, bringing our descendants with us - LL_DEBUGS("FastTimers") << "Moving " << timerp->getName() << " from child of " << timerp->getParent()->getName() << - " to child of " << timerp->getParent()->getParent()->getName() << LL_ENDL; - timerp->setParent(timerp->getParent()->getParent()); - accumulator.mParent = timerp->getParent(); - accumulator.mMoveUpTree = false; - - // don't bubble up any ancestors until descendants are done bubbling up - // as ancestors may call this timer only on certain paths, so we want to resolve - // child-most block locations before their parents - it.skipAncestors(); - } - } - } + // since ancestors have already been visited, re-parenting won't affect tree traversal + //step up tree, bringing our descendants with us + LL_DEBUGS("FastTimers") << "Moving " << timerp->getName() << " from child of " << timerp->getParent()->getName() << + " to child of " << timerp->getParent()->getParent()->getName() << LL_ENDL; + timerp->setParent(timerp->getParent()->getParent()); + accumulator.mParent = timerp->getParent(); + accumulator.mMoveUpTree = false; + + // don't bubble up any ancestors until descendants are done bubbling up + // as ancestors may call this timer only on certain paths, so we want to resolve + // child-most block locations before their parents + it.skipAncestors(); + } + } + } } void BlockTimer::updateTimes() { LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - // walk up stack of active timers and accumulate current time while leaving timing structures active - BlockTimerStackRecord* stack_record = LLThreadLocalSingletonPointer::getInstance(); - if (!stack_record) return; - - U64 cur_time = getCPUClockCount64(); - BlockTimer* cur_timer = stack_record->mActiveTimer; - TimeBlockAccumulator* accumulator = &stack_record->mTimeBlock->getCurrentAccumulator(); - - while(cur_timer - && cur_timer->mParentTimerData.mActiveTimer != cur_timer) // root defined by parent pointing to self - { - U64 cumulative_time_delta = cur_time - cur_timer->mStartTime; - cur_timer->mStartTime = cur_time; - - accumulator->mTotalTimeCounter += cumulative_time_delta; - accumulator->mSelfTimeCounter += cumulative_time_delta - stack_record->mChildTime; - stack_record->mChildTime = 0; - - stack_record = &cur_timer->mParentTimerData; - accumulator = &stack_record->mTimeBlock->getCurrentAccumulator(); - cur_timer = stack_record->mActiveTimer; - - stack_record->mChildTime += cumulative_time_delta; - } + // walk up stack of active timers and accumulate current time while leaving timing structures active + BlockTimerStackRecord* stack_record = LLThreadLocalSingletonPointer::getInstance(); + if (!stack_record) return; + + U64 cur_time = getCPUClockCount64(); + BlockTimer* cur_timer = stack_record->mActiveTimer; + TimeBlockAccumulator* accumulator = &stack_record->mTimeBlock->getCurrentAccumulator(); + + while(cur_timer + && cur_timer->mParentTimerData.mActiveTimer != cur_timer) // root defined by parent pointing to self + { + U64 cumulative_time_delta = cur_time - cur_timer->mStartTime; + cur_timer->mStartTime = cur_time; + + accumulator->mTotalTimeCounter += cumulative_time_delta; + accumulator->mSelfTimeCounter += cumulative_time_delta - stack_record->mChildTime; + stack_record->mChildTime = 0; + + stack_record = &cur_timer->mParentTimerData; + accumulator = &stack_record->mTimeBlock->getCurrentAccumulator(); + cur_timer = stack_record->mActiveTimer; + + stack_record->mChildTime += cumulative_time_delta; + } } static LLTrace::BlockTimerStatHandle FTM_PROCESS_TIMES("Process FastTimer Times"); @@ -297,192 +297,192 @@ static LLTrace::BlockTimerStatHandle FTM_PROCESS_TIMES("Process FastTimer Times" void BlockTimer::processTimes() { #if LL_TRACE_ENABLED - LL_RECORD_BLOCK_TIME(FTM_PROCESS_TIMES); - get_clock_count(); // good place to calculate clock frequency + LL_RECORD_BLOCK_TIME(FTM_PROCESS_TIMES); + get_clock_count(); // good place to calculate clock frequency - // set up initial tree - bootstrapTimerTree(); + // set up initial tree + bootstrapTimerTree(); - incrementalUpdateTimerTree(); + incrementalUpdateTimerTree(); - updateTimes(); + updateTimes(); - // reset for next frame - for (auto& base : BlockTimerStatHandle::instance_snapshot()) - { - // because of indirect derivation from LLInstanceTracker, have to downcast - BlockTimerStatHandle& timer = static_cast(base); - TimeBlockAccumulator& accumulator = timer.getCurrentAccumulator(); + // reset for next frame + for (auto& base : BlockTimerStatHandle::instance_snapshot()) + { + // because of indirect derivation from LLInstanceTracker, have to downcast + BlockTimerStatHandle& timer = static_cast(base); + TimeBlockAccumulator& accumulator = timer.getCurrentAccumulator(); - accumulator.mLastCaller = NULL; - accumulator.mMoveUpTree = false; - } + accumulator.mLastCaller = NULL; + accumulator.mMoveUpTree = false; + } #endif } std::vector::iterator BlockTimerStatHandle::beginChildren() - { - return getTreeNode().mChildren.begin(); - } + { + return getTreeNode().mChildren.begin(); + } std::vector::iterator BlockTimerStatHandle::endChildren() - { - return getTreeNode().mChildren.end(); + { + return getTreeNode().mChildren.end(); } std::vector& BlockTimerStatHandle::getChildren() { - return getTreeNode().mChildren; - } + return getTreeNode().mChildren; + } bool BlockTimerStatHandle::hasChildren() { - return ! getTreeNode().mChildren.empty(); + return ! getTreeNode().mChildren.empty(); } // static void BlockTimer::logStats() { - // get ready for next frame - if (sLog) - { //output current frame counts to performance log - - static S32 call_count = 0; - if (call_count % 100 == 0) - { - LL_DEBUGS("FastTimers") << "countsPerSecond: " << countsPerSecond() << LL_ENDL; - LL_DEBUGS("FastTimers") << "LLProcessorInfo().getCPUFrequency() " << LLProcessorInfo().getCPUFrequency() << LL_ENDL; - LL_DEBUGS("FastTimers") << "getCPUClockCount32() " << getCPUClockCount32() << LL_ENDL; - LL_DEBUGS("FastTimers") << "getCPUClockCount64() " << getCPUClockCount64() << LL_ENDL; - LL_DEBUGS("FastTimers") << "elapsed sec " << ((F64)getCPUClockCount64() / (F64HertzImplicit)LLProcessorInfo().getCPUFrequency()) << LL_ENDL; - } - call_count++; - - F64Seconds total_time(0); - LLSD sd; - - { - for (auto& base : BlockTimerStatHandle::instance_snapshot()) - { - // because of indirect derivation from LLInstanceTracker, have to downcast - BlockTimerStatHandle& timer = static_cast(base); - LLTrace::PeriodicRecording& frame_recording = LLTrace::get_frame_recording(); - sd[timer.getName()]["Time"] = (LLSD::Real) (frame_recording.getLastRecording().getSum(timer).value()); - sd[timer.getName()]["Calls"] = (LLSD::Integer) (frame_recording.getLastRecording().getSum(timer.callCount())); - - // computing total time here because getting the root timer's getCountHistory - // doesn't work correctly on the first frame - total_time += frame_recording.getLastRecording().getSum(timer); - } - } - - sd["Total"]["Time"] = (LLSD::Real) total_time.value(); - sd["Total"]["Calls"] = (LLSD::Integer) 1; - - { - LLMutexLock lock(sLogLock); - sLogQueue.push(sd); - } - } + // get ready for next frame + if (sLog) + { //output current frame counts to performance log + + static S32 call_count = 0; + if (call_count % 100 == 0) + { + LL_DEBUGS("FastTimers") << "countsPerSecond: " << countsPerSecond() << LL_ENDL; + LL_DEBUGS("FastTimers") << "LLProcessorInfo().getCPUFrequency() " << LLProcessorInfo().getCPUFrequency() << LL_ENDL; + LL_DEBUGS("FastTimers") << "getCPUClockCount32() " << getCPUClockCount32() << LL_ENDL; + LL_DEBUGS("FastTimers") << "getCPUClockCount64() " << getCPUClockCount64() << LL_ENDL; + LL_DEBUGS("FastTimers") << "elapsed sec " << ((F64)getCPUClockCount64() / (F64HertzImplicit)LLProcessorInfo().getCPUFrequency()) << LL_ENDL; + } + call_count++; + + F64Seconds total_time(0); + LLSD sd; + + { + for (auto& base : BlockTimerStatHandle::instance_snapshot()) + { + // because of indirect derivation from LLInstanceTracker, have to downcast + BlockTimerStatHandle& timer = static_cast(base); + LLTrace::PeriodicRecording& frame_recording = LLTrace::get_frame_recording(); + sd[timer.getName()]["Time"] = (LLSD::Real) (frame_recording.getLastRecording().getSum(timer).value()); + sd[timer.getName()]["Calls"] = (LLSD::Integer) (frame_recording.getLastRecording().getSum(timer.callCount())); + + // computing total time here because getting the root timer's getCountHistory + // doesn't work correctly on the first frame + total_time += frame_recording.getLastRecording().getSum(timer); + } + } + + sd["Total"]["Time"] = (LLSD::Real) total_time.value(); + sd["Total"]["Calls"] = (LLSD::Integer) 1; + + { + LLMutexLock lock(sLogLock); + sLogQueue.push(sd); + } + } } //static void BlockTimer::dumpCurTimes() { - LLTrace::PeriodicRecording& frame_recording = LLTrace::get_frame_recording(); - LLTrace::Recording& last_frame_recording = frame_recording.getLastRecording(); - - // walk over timers in depth order and output timings - for(block_timer_tree_df_iterator_t it = begin_timer_tree(BlockTimer::getRootTimeBlock()); - it != end_timer_tree(); - ++it) - { - BlockTimerStatHandle* timerp = (*it); - F64Seconds total_time = last_frame_recording.getSum(*timerp); - U32 num_calls = last_frame_recording.getSum(timerp->callCount()); - - // Don't bother with really brief times, keep output concise - if (total_time < F32Milliseconds(0.1f)) continue; - - std::ostringstream out_str; - BlockTimerStatHandle* parent_timerp = timerp; - while(parent_timerp && parent_timerp != parent_timerp->getParent()) - { - out_str << "\t"; - parent_timerp = parent_timerp->getParent(); - } - - out_str << timerp->getName() << " " - << std::setprecision(3) << total_time.valueInUnits() << " ms, " - << num_calls << " calls"; - - LL_INFOS() << out_str.str() << LL_ENDL; + LLTrace::PeriodicRecording& frame_recording = LLTrace::get_frame_recording(); + LLTrace::Recording& last_frame_recording = frame_recording.getLastRecording(); + + // walk over timers in depth order and output timings + for(block_timer_tree_df_iterator_t it = begin_timer_tree(BlockTimer::getRootTimeBlock()); + it != end_timer_tree(); + ++it) + { + BlockTimerStatHandle* timerp = (*it); + F64Seconds total_time = last_frame_recording.getSum(*timerp); + U32 num_calls = last_frame_recording.getSum(timerp->callCount()); + + // Don't bother with really brief times, keep output concise + if (total_time < F32Milliseconds(0.1f)) continue; + + std::ostringstream out_str; + BlockTimerStatHandle* parent_timerp = timerp; + while(parent_timerp && parent_timerp != parent_timerp->getParent()) + { + out_str << "\t"; + parent_timerp = parent_timerp->getParent(); + } + + out_str << timerp->getName() << " " + << std::setprecision(3) << total_time.valueInUnits() << " ms, " + << num_calls << " calls"; + + LL_INFOS() << out_str.str() << LL_ENDL; } } //static void BlockTimer::writeLog(std::ostream& os) { - while (!sLogQueue.empty()) - { - LLSD& sd = sLogQueue.front(); - LLSDSerialize::toXML(sd, os); - LLMutexLock lock(sLogLock); - sLogQueue.pop(); - } + while (!sLogQueue.empty()) + { + LLSD& sd = sLogQueue.front(); + LLSDSerialize::toXML(sd, os); + LLMutexLock lock(sLogLock); + sLogQueue.pop(); + } } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // TimeBlockAccumulator ////////////////////////////////////////////////////////////////////////////////////////////////////////////////// -TimeBlockAccumulator::TimeBlockAccumulator() -: mTotalTimeCounter(0), - mSelfTimeCounter(0), - mCalls(0), - mLastCaller(NULL), - mActiveCount(0), - mMoveUpTree(false), - mParent(NULL) +TimeBlockAccumulator::TimeBlockAccumulator() +: mTotalTimeCounter(0), + mSelfTimeCounter(0), + mCalls(0), + mLastCaller(NULL), + mActiveCount(0), + mMoveUpTree(false), + mParent(NULL) {} void TimeBlockAccumulator::addSamples( const TimeBlockAccumulator& other, EBufferAppendType append_type ) { #if LL_TRACE_ENABLED - // we can't merge two unrelated time block samples, as that will screw with the nested timings - // due to the call hierarchy of each thread - llassert(append_type == SEQUENTIAL); - mTotalTimeCounter += other.mTotalTimeCounter; - mSelfTimeCounter += other.mSelfTimeCounter; - mCalls += other.mCalls; - mLastCaller = other.mLastCaller; - mActiveCount = other.mActiveCount; - mMoveUpTree = other.mMoveUpTree; - mParent = other.mParent; + // we can't merge two unrelated time block samples, as that will screw with the nested timings + // due to the call hierarchy of each thread + llassert(append_type == SEQUENTIAL); + mTotalTimeCounter += other.mTotalTimeCounter; + mSelfTimeCounter += other.mSelfTimeCounter; + mCalls += other.mCalls; + mLastCaller = other.mLastCaller; + mActiveCount = other.mActiveCount; + mMoveUpTree = other.mMoveUpTree; + mParent = other.mParent; #endif } void TimeBlockAccumulator::reset( const TimeBlockAccumulator* other ) { - mCalls = 0; - mSelfTimeCounter = 0; - mTotalTimeCounter = 0; + mCalls = 0; + mSelfTimeCounter = 0; + mTotalTimeCounter = 0; - if (other) + if (other) { - mLastCaller = other->mLastCaller; - mActiveCount = other->mActiveCount; - mMoveUpTree = other->mMoveUpTree; - mParent = other->mParent; - } + mLastCaller = other->mLastCaller; + mActiveCount = other->mActiveCount; + mMoveUpTree = other->mMoveUpTree; + mParent = other->mParent; + } } F64Seconds BlockTimer::getElapsedTime() { - U64 total_time = getCPUClockCount64() - mStartTime; + U64 total_time = getCPUClockCount64() - mStartTime; - return F64Seconds((F64)total_time / (F64)BlockTimer::countsPerSecond()); + return F64Seconds((F64)total_time / (F64)BlockTimer::countsPerSecond()); } diff --git a/indra/llcommon/llfasttimer.h b/indra/llcommon/llfasttimer.h index 9bd93d7240..17ad37b031 100644 --- a/indra/llcommon/llfasttimer.h +++ b/indra/llcommon/llfasttimer.h @@ -5,21 +5,21 @@ * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -51,77 +51,77 @@ class BlockTimer timeThisBlock(class BlockTimerStatHandle& timer); class BlockTimer { public: - typedef BlockTimer self_t; - typedef class BlockTimerStatHandle DeclareTimer; + typedef BlockTimer self_t; + typedef class BlockTimerStatHandle DeclareTimer; - ~BlockTimer(); + ~BlockTimer(); - F64Seconds getElapsedTime(); + F64Seconds getElapsedTime(); - ////////////////////////////////////////////////////////////////////////////// - // - // Important note: These implementations must be FAST! - // + ////////////////////////////////////////////////////////////////////////////// + // + // Important note: These implementations must be FAST! + // #if LL_WINDOWS - // - // Windows implementation of CPU clock - // - - // - // NOTE: put back in when we aren't using platform sdk anymore - // - // because MS has different signatures for these functions in winnt.h - // need to rename them to avoid conflicts - //#define _interlockedbittestandset _renamed_interlockedbittestandset - //#define _interlockedbittestandreset _renamed_interlockedbittestandreset - //#include - //#undef _interlockedbittestandset - //#undef _interlockedbittestandreset - - //inline U32 getCPUClockCount32() - //{ - // U64 time_stamp = __rdtsc(); - // return (U32)(time_stamp >> 8); - //} - // - //// return full timer value, *not* shifted by 8 bits - //inline U64 getCPUClockCount64() - //{ - // return __rdtsc(); - //} - - - - // shift off lower 8 bits for lower resolution but longer term timing - // on 1Ghz machine, a 32-bit word will hold ~1000 seconds of timing + // + // Windows implementation of CPU clock + // + + // + // NOTE: put back in when we aren't using platform sdk anymore + // + // because MS has different signatures for these functions in winnt.h + // need to rename them to avoid conflicts + //#define _interlockedbittestandset _renamed_interlockedbittestandset + //#define _interlockedbittestandreset _renamed_interlockedbittestandreset + //#include + //#undef _interlockedbittestandset + //#undef _interlockedbittestandreset + + //inline U32 getCPUClockCount32() + //{ + // U64 time_stamp = __rdtsc(); + // return (U32)(time_stamp >> 8); + //} + // + //// return full timer value, *not* shifted by 8 bits + //inline U64 getCPUClockCount64() + //{ + // return __rdtsc(); + //} + + + + // shift off lower 8 bits for lower resolution but longer term timing + // on 1Ghz machine, a 32-bit word will hold ~1000 seconds of timing #if LL_FASTTIMER_USE_RDTSC - static U32 getCPUClockCount32() - { - unsigned __int64 val = __rdtsc(); - val = val >> 8; - return static_cast(val); - } - - // return full timer value, *not* shifted by 8 bits - static U64 getCPUClockCount64() - { - return static_cast( __rdtsc() ); - } + static U32 getCPUClockCount32() + { + unsigned __int64 val = __rdtsc(); + val = val >> 8; + return static_cast(val); + } + + // return full timer value, *not* shifted by 8 bits + static U64 getCPUClockCount64() + { + return static_cast( __rdtsc() ); + } #else - //U64 get_clock_count(); // in lltimer.cpp - // These use QueryPerformanceCounter, which is arguably fine and also works on AMD architectures. - static U32 getCPUClockCount32() - { - return (U32)(get_clock_count()>>8); - } - - static U64 getCPUClockCount64() - { - return get_clock_count(); - } + //U64 get_clock_count(); // in lltimer.cpp + // These use QueryPerformanceCounter, which is arguably fine and also works on AMD architectures. + static U32 getCPUClockCount32() + { + return (U32)(get_clock_count()>>8); + } + + static U64 getCPUClockCount64() + { + return get_clock_count(); + } #endif @@ -129,142 +129,142 @@ public: #if (LL_LINUX) && !(defined(__i386__) || defined(__amd64__)) - // - // Linux implementation of CPU clock - non-x86. - // This is accurate but SLOW! Only use out of desperation. - // - // Try to use the MONOTONIC clock if available, this is a constant time counter - // with nanosecond resolution (but not necessarily accuracy) and attempts are - // made to synchronize this value between cores at kernel start. It should not - // be affected by CPU frequency. If not available use the REALTIME clock, but - // this may be affected by NTP adjustments or other user activity affecting - // the system time. - static U64 getCPUClockCount64() - { - struct timespec tp; + // + // Linux implementation of CPU clock - non-x86. + // This is accurate but SLOW! Only use out of desperation. + // + // Try to use the MONOTONIC clock if available, this is a constant time counter + // with nanosecond resolution (but not necessarily accuracy) and attempts are + // made to synchronize this value between cores at kernel start. It should not + // be affected by CPU frequency. If not available use the REALTIME clock, but + // this may be affected by NTP adjustments or other user activity affecting + // the system time. + static U64 getCPUClockCount64() + { + struct timespec tp; #ifdef CLOCK_MONOTONIC // MONOTONIC supported at build-time? - if (-1 == clock_gettime(CLOCK_MONOTONIC,&tp)) // if MONOTONIC isn't supported at runtime then ouch, try REALTIME + if (-1 == clock_gettime(CLOCK_MONOTONIC,&tp)) // if MONOTONIC isn't supported at runtime then ouch, try REALTIME #endif - clock_gettime(CLOCK_REALTIME,&tp); + clock_gettime(CLOCK_REALTIME,&tp); - return (tp.tv_sec*sClockResolution)+tp.tv_nsec; - } + return (tp.tv_sec*sClockResolution)+tp.tv_nsec; + } - static U32 getCPUClockCount32() - { - return (U32)(getCPUClockCount64() >> 8); - } + static U32 getCPUClockCount32() + { + return (U32)(getCPUClockCount64() >> 8); + } #endif // (LL_LINUX) && !(defined(__i386__) || defined(__amd64__)) #if (LL_LINUX || LL_DARWIN) && (defined(__i386__) || defined(__amd64__)) - // - // Mac+Linux FAST x86 implementation of CPU clock - static U32 getCPUClockCount32() - { - U32 low(0),high(0); - __asm__ volatile (".byte 0x0f, 0x31": "=a"(low), "=d"(high) ); - return (low>>8) | (high<<24); - } - - static U64 getCPUClockCount64() - { - U32 low(0),high(0); - __asm__ volatile (".byte 0x0f, 0x31": "=a"(low), "=d"(high) ); - return (U64)low | ( ((U64)high) << 32); - } + // + // Mac+Linux FAST x86 implementation of CPU clock + static U32 getCPUClockCount32() + { + U32 low(0),high(0); + __asm__ volatile (".byte 0x0f, 0x31": "=a"(low), "=d"(high) ); + return (low>>8) | (high<<24); + } + + static U64 getCPUClockCount64() + { + U32 low(0),high(0); + __asm__ volatile (".byte 0x0f, 0x31": "=a"(low), "=d"(high) ); + return (U64)low | ( ((U64)high) << 32); + } #endif - static BlockTimerStatHandle& getRootTimeBlock(); - static void pushLog(LLSD sd); - static void setLogLock(class LLMutex* mutex); - static void writeLog(std::ostream& os); - static void updateTimes(); - - static U64 countsPerSecond(); + static BlockTimerStatHandle& getRootTimeBlock(); + static void pushLog(LLSD sd); + static void setLogLock(class LLMutex* mutex); + static void writeLog(std::ostream& os); + static void updateTimes(); + + static U64 countsPerSecond(); - // updates cumulative times and hierarchy, - // can be called multiple times in a frame, at any point - static void processTimes(); + // updates cumulative times and hierarchy, + // can be called multiple times in a frame, at any point + static void processTimes(); - static void bootstrapTimerTree(); - static void incrementalUpdateTimerTree(); + static void bootstrapTimerTree(); + static void incrementalUpdateTimerTree(); - // call this once a frame to periodically log timers - static void logStats(); + // call this once a frame to periodically log timers + static void logStats(); - // dumps current cumulative frame stats to log - // call nextFrame() to reset timers - static void dumpCurTimes(); + // dumps current cumulative frame stats to log + // call nextFrame() to reset timers + static void dumpCurTimes(); private: - friend class BlockTimerStatHandle; - // FIXME: this friendship exists so that each thread can instantiate a root timer, - // which could be a derived class with a public constructor instead, possibly - friend class ThreadRecorder; - friend BlockTimer timeThisBlock(BlockTimerStatHandle&); + friend class BlockTimerStatHandle; + // FIXME: this friendship exists so that each thread can instantiate a root timer, + // which could be a derived class with a public constructor instead, possibly + friend class ThreadRecorder; + friend BlockTimer timeThisBlock(BlockTimerStatHandle&); - BlockTimer(BlockTimerStatHandle& timer); + BlockTimer(BlockTimerStatHandle& timer); - // no-copy - BlockTimer(const BlockTimer& other); - BlockTimer& operator=(const BlockTimer& other); + // no-copy + BlockTimer(const BlockTimer& other); + BlockTimer& operator=(const BlockTimer& other); private: - U64 mStartTime; - BlockTimerStackRecord mParentTimerData; + U64 mStartTime; + BlockTimerStackRecord mParentTimerData; public: - // statics - static std::string sLogName; - static bool sMetricLog, - sLog; - static U64 sClockResolution; + // statics + static std::string sLogName; + static bool sMetricLog, + sLog; + static U64 sClockResolution; }; // this dummy function assists in allocating a block timer with stack-based lifetime. -// this is done by capturing the return value in a stack-allocated const reference variable. +// this is done by capturing the return value in a stack-allocated const reference variable. // (This is most easily done using the macro LL_RECORD_BLOCK_TIME) -// Otherwise, it would be possible to store a BlockTimer on the heap, resulting in non-nested lifetimes, +// Otherwise, it would be possible to store a BlockTimer on the heap, resulting in non-nested lifetimes, // which would break the invariants of the timing hierarchy logic LL_FORCE_INLINE class BlockTimer timeThisBlock(class BlockTimerStatHandle& timer) { - return BlockTimer(timer); + return BlockTimer(timer); } // stores a "named" timer instance to be reused via multiple BlockTimer stack instances -class BlockTimerStatHandle -: public StatType +class BlockTimerStatHandle +: public StatType { public: - BlockTimerStatHandle(const char* name, const char* description = ""); - - TimeBlockTreeNode& getTreeNode() const; - BlockTimerStatHandle* getParent() const { return getTreeNode().getParent(); } - void setParent(BlockTimerStatHandle* parent) { getTreeNode().setParent(parent); } - - typedef std::vector::iterator child_iter; - typedef std::vector::const_iterator child_const_iter; - child_iter beginChildren(); - child_iter endChildren(); - bool hasChildren(); - std::vector& getChildren(); - - StatType& callCount() - { - return static_cast&>(*(StatType*)this); - } - - StatType& selfTime() - { - return static_cast&>(*(StatType*)this); - } - - bool mCollapsed; // don't show children + BlockTimerStatHandle(const char* name, const char* description = ""); + + TimeBlockTreeNode& getTreeNode() const; + BlockTimerStatHandle* getParent() const { return getTreeNode().getParent(); } + void setParent(BlockTimerStatHandle* parent) { getTreeNode().setParent(parent); } + + typedef std::vector::iterator child_iter; + typedef std::vector::const_iterator child_const_iter; + child_iter beginChildren(); + child_iter endChildren(); + bool hasChildren(); + std::vector& getChildren(); + + StatType& callCount() + { + return static_cast&>(*(StatType*)this); + } + + StatType& selfTime() + { + return static_cast&>(*(StatType*)this); + } + + bool mCollapsed; // don't show children }; // iterators and helper functions for walking the call hierarchy of block timers in different ways @@ -282,61 +282,61 @@ block_timer_tree_bf_iterator_t end_block_timer_tree_bf(); LL_FORCE_INLINE BlockTimer::BlockTimer(BlockTimerStatHandle& timer) { #if LL_FAST_TIMER_ON - BlockTimerStackRecord* cur_timer_data = LLThreadLocalSingletonPointer::getInstance(); - if (!cur_timer_data) - { - // How likely is it that - // LLThreadLocalSingletonPointer::getInstance() will return NULL? - // Even without researching, what we can say is that if we exit - // without setting mStartTime at all, gcc 4.7 produces (fatal) - // warnings about a possibly-uninitialized data member. - mStartTime = 0; - return; - } - TimeBlockAccumulator& accumulator = timer.getCurrentAccumulator(); - accumulator.mActiveCount++; - // keep current parent as long as it is active when we are - accumulator.mMoveUpTree |= (accumulator.mParent->getCurrentAccumulator().mActiveCount == 0); - - // store top of stack - mParentTimerData = *cur_timer_data; - // push new information - cur_timer_data->mActiveTimer = this; - cur_timer_data->mTimeBlock = &timer; - cur_timer_data->mChildTime = 0; - - mStartTime = getCPUClockCount64(); + BlockTimerStackRecord* cur_timer_data = LLThreadLocalSingletonPointer::getInstance(); + if (!cur_timer_data) + { + // How likely is it that + // LLThreadLocalSingletonPointer::getInstance() will return NULL? + // Even without researching, what we can say is that if we exit + // without setting mStartTime at all, gcc 4.7 produces (fatal) + // warnings about a possibly-uninitialized data member. + mStartTime = 0; + return; + } + TimeBlockAccumulator& accumulator = timer.getCurrentAccumulator(); + accumulator.mActiveCount++; + // keep current parent as long as it is active when we are + accumulator.mMoveUpTree |= (accumulator.mParent->getCurrentAccumulator().mActiveCount == 0); + + // store top of stack + mParentTimerData = *cur_timer_data; + // push new information + cur_timer_data->mActiveTimer = this; + cur_timer_data->mTimeBlock = &timer; + cur_timer_data->mChildTime = 0; + + mStartTime = getCPUClockCount64(); #endif } LL_FORCE_INLINE BlockTimer::~BlockTimer() { #if LL_FAST_TIMER_ON - U64 total_time = getCPUClockCount64() - mStartTime; - BlockTimerStackRecord* cur_timer_data = LLThreadLocalSingletonPointer::getInstance(); - if (!cur_timer_data) return; + U64 total_time = getCPUClockCount64() - mStartTime; + BlockTimerStackRecord* cur_timer_data = LLThreadLocalSingletonPointer::getInstance(); + if (!cur_timer_data) return; - TimeBlockAccumulator& accumulator = cur_timer_data->mTimeBlock->getCurrentAccumulator(); + TimeBlockAccumulator& accumulator = cur_timer_data->mTimeBlock->getCurrentAccumulator(); - accumulator.mCalls++; - accumulator.mTotalTimeCounter += total_time; - accumulator.mSelfTimeCounter += total_time - cur_timer_data->mChildTime; - accumulator.mActiveCount--; + accumulator.mCalls++; + accumulator.mTotalTimeCounter += total_time; + accumulator.mSelfTimeCounter += total_time - cur_timer_data->mChildTime; + accumulator.mActiveCount--; - // store last caller to bootstrap tree creation - // do this in the destructor in case of recursion to get topmost caller - accumulator.mLastCaller = mParentTimerData.mTimeBlock; + // store last caller to bootstrap tree creation + // do this in the destructor in case of recursion to get topmost caller + accumulator.mLastCaller = mParentTimerData.mTimeBlock; - // we are only tracking self time, so subtract our total time delta from parents - mParentTimerData.mChildTime += total_time; + // we are only tracking self time, so subtract our total time delta from parents + mParentTimerData.mChildTime += total_time; - //pop stack - *cur_timer_data = mParentTimerData; + //pop stack + *cur_timer_data = mParentTimerData; #endif } } -typedef LLTrace::BlockTimer LLFastTimer; +typedef LLTrace::BlockTimer LLFastTimer; #endif // LL_LLFASTTIMER_H diff --git a/indra/llcommon/llfile.cpp b/indra/llcommon/llfile.cpp index 8355b1e797..1877dd54ed 100644 --- a/indra/llcommon/llfile.cpp +++ b/indra/llcommon/llfile.cpp @@ -52,9 +52,9 @@ static std::string empty; // On Windows, use strerror_s(). std::string strerr(int errn) { - char buffer[256]; - strerror_s(buffer, errn); // infers sizeof(buffer) -- love it! - return buffer; + char buffer[256]; + strerror_s(buffer, errn); // infers sizeof(buffer) -- love it! + return buffer; } typedef std::basic_ios > _Myios; @@ -69,295 +69,295 @@ typedef std::basic_ios > _Myios; // strerror_r() returns char* std::string message_from(int /*orig_errno*/, const char* /*buffer*/, size_t /*bufflen*/, - const char* strerror_ret) + const char* strerror_ret) { - return strerror_ret; + return strerror_ret; } // strerror_r() returns int std::string message_from(int orig_errno, const char* buffer, size_t bufflen, - int strerror_ret) + int strerror_ret) { - if (strerror_ret == 0) - { - return buffer; - } - // Here strerror_r() has set errno. Since strerror_r() has already failed, - // seems like a poor bet to call it again to diagnose its own error... - int stre_errno = errno; - if (stre_errno == ERANGE) - { - return STRINGIZE("strerror_r() can't explain errno " << orig_errno - << " (" << bufflen << "-byte buffer too small)"); - } - if (stre_errno == EINVAL) - { - return STRINGIZE("unknown errno " << orig_errno); - } - // Here we don't even understand the errno from strerror_r()! - return STRINGIZE("strerror_r() can't explain errno " << orig_errno - << " (error " << stre_errno << ')'); + if (strerror_ret == 0) + { + return buffer; + } + // Here strerror_r() has set errno. Since strerror_r() has already failed, + // seems like a poor bet to call it again to diagnose its own error... + int stre_errno = errno; + if (stre_errno == ERANGE) + { + return STRINGIZE("strerror_r() can't explain errno " << orig_errno + << " (" << bufflen << "-byte buffer too small)"); + } + if (stre_errno == EINVAL) + { + return STRINGIZE("unknown errno " << orig_errno); + } + // Here we don't even understand the errno from strerror_r()! + return STRINGIZE("strerror_r() can't explain errno " << orig_errno + << " (error " << stre_errno << ')'); } std::string strerr(int errn) { - char buffer[256]; - // Select message_from() function matching the strerror_r() we have on hand. - return message_from(errn, buffer, sizeof(buffer), - strerror_r(errn, buffer, sizeof(buffer))); + char buffer[256]; + // Select message_from() function matching the strerror_r() we have on hand. + return message_from(errn, buffer, sizeof(buffer), + strerror_r(errn, buffer, sizeof(buffer))); } -#endif // ! LL_WINDOWS +#endif // ! LL_WINDOWS // On either system, shorthand call just infers global 'errno'. std::string strerr() { - return strerr(errno); + return strerr(errno); } int warnif(const std::string& desc, const std::string& filename, int rc, int accept=0) { - if (rc < 0) - { - // Capture errno before we start emitting output - int errn = errno; - // For certain operations, a particular errno value might be - // acceptable -- e.g. stat() could permit ENOENT, mkdir() could permit - // EEXIST. Don't warn if caller explicitly says this errno is okay. - if (errn != accept) - { - LL_WARNS("LLFile") << "Couldn't " << desc << " '" << filename - << "' (errno " << errn << "): " << strerr(errn) << LL_ENDL; - } + if (rc < 0) + { + // Capture errno before we start emitting output + int errn = errno; + // For certain operations, a particular errno value might be + // acceptable -- e.g. stat() could permit ENOENT, mkdir() could permit + // EEXIST. Don't warn if caller explicitly says this errno is okay. + if (errn != accept) + { + LL_WARNS("LLFile") << "Couldn't " << desc << " '" << filename + << "' (errno " << errn << "): " << strerr(errn) << LL_ENDL; + } #if 0 && LL_WINDOWS // turn on to debug file-locking problems - // If the problem is "Permission denied," maybe it's because another - // process has the file open. Try to find out. - if (errn == EACCES) // *not* EPERM - { - // Only do any of this stuff (before LL_ENDL) if it will be logged. - LL_DEBUGS("LLFile") << empty; - // would be nice to use LLDir for this, but dependency goes the - // wrong way - const char* TEMP = LLFile::tmpdir(); - if (! (TEMP && *TEMP)) - { - LL_CONT << "No $TEMP, not running 'handle'"; - } - else - { - std::string tf(TEMP); - tf += "\\handle.tmp"; - // http://technet.microsoft.com/en-us/sysinternals/bb896655 - std::string cmd(STRINGIZE("handle \"" << filename - // "openfiles /query /v | fgrep -i \"" << filename - << "\" > \"" << tf << '"')); - LL_CONT << cmd; - if (system(cmd.c_str()) != 0) - { - LL_CONT << "\nDownload 'handle.exe' from http://technet.microsoft.com/en-us/sysinternals/bb896655"; - } - else - { - std::ifstream inf(tf); - std::string line; - while (std::getline(inf, line)) - { - LL_CONT << '\n' << line; - } - } - LLFile::remove(tf); - } - LL_CONT << LL_ENDL; - } + // If the problem is "Permission denied," maybe it's because another + // process has the file open. Try to find out. + if (errn == EACCES) // *not* EPERM + { + // Only do any of this stuff (before LL_ENDL) if it will be logged. + LL_DEBUGS("LLFile") << empty; + // would be nice to use LLDir for this, but dependency goes the + // wrong way + const char* TEMP = LLFile::tmpdir(); + if (! (TEMP && *TEMP)) + { + LL_CONT << "No $TEMP, not running 'handle'"; + } + else + { + std::string tf(TEMP); + tf += "\\handle.tmp"; + // http://technet.microsoft.com/en-us/sysinternals/bb896655 + std::string cmd(STRINGIZE("handle \"" << filename + // "openfiles /query /v | fgrep -i \"" << filename + << "\" > \"" << tf << '"')); + LL_CONT << cmd; + if (system(cmd.c_str()) != 0) + { + LL_CONT << "\nDownload 'handle.exe' from http://technet.microsoft.com/en-us/sysinternals/bb896655"; + } + else + { + std::ifstream inf(tf); + std::string line; + while (std::getline(inf, line)) + { + LL_CONT << '\n' << line; + } + } + LLFile::remove(tf); + } + LL_CONT << LL_ENDL; + } #endif // LL_WINDOWS hack to identify processes holding file open - } - return rc; + } + return rc; } // static -int LLFile::mkdir(const std::string& dirname, int perms) +int LLFile::mkdir(const std::string& dirname, int perms) { #if LL_WINDOWS - // permissions are ignored on Windows - std::string utf8dirname = dirname; - llutf16string utf16dirname = utf8str_to_utf16str(utf8dirname); - int rc = _wmkdir(utf16dirname.c_str()); + // permissions are ignored on Windows + std::string utf8dirname = dirname; + llutf16string utf16dirname = utf8str_to_utf16str(utf8dirname); + int rc = _wmkdir(utf16dirname.c_str()); #else - int rc = ::mkdir(dirname.c_str(), (mode_t)perms); + int rc = ::mkdir(dirname.c_str(), (mode_t)perms); #endif - // We often use mkdir() to ensure the existence of a directory that might - // already exist. There is no known case in which we want to call out as - // an error the requested directory already existing. - if (rc < 0 && errno == EEXIST) - { - // this is not the error you want, move along - return 0; - } - // anything else might be a problem - return warnif("mkdir", dirname, rc, EEXIST); + // We often use mkdir() to ensure the existence of a directory that might + // already exist. There is no known case in which we want to call out as + // an error the requested directory already existing. + if (rc < 0 && errno == EEXIST) + { + // this is not the error you want, move along + return 0; + } + // anything else might be a problem + return warnif("mkdir", dirname, rc, EEXIST); } // static -int LLFile::rmdir(const std::string& dirname) +int LLFile::rmdir(const std::string& dirname) { #if LL_WINDOWS - // permissions are ignored on Windows - std::string utf8dirname = dirname; - llutf16string utf16dirname = utf8str_to_utf16str(utf8dirname); - int rc = _wrmdir(utf16dirname.c_str()); + // permissions are ignored on Windows + std::string utf8dirname = dirname; + llutf16string utf16dirname = utf8str_to_utf16str(utf8dirname); + int rc = _wrmdir(utf16dirname.c_str()); #else - int rc = ::rmdir(dirname.c_str()); + int rc = ::rmdir(dirname.c_str()); #endif - return warnif("rmdir", dirname, rc); + return warnif("rmdir", dirname, rc); } // static -LLFILE* LLFile::fopen(const std::string& filename, const char* mode) /* Flawfinder: ignore */ +LLFILE* LLFile::fopen(const std::string& filename, const char* mode) /* Flawfinder: ignore */ { -#if LL_WINDOWS - std::string utf8filename = filename; - std::string utf8mode = std::string(mode); - llutf16string utf16filename = utf8str_to_utf16str(utf8filename); - llutf16string utf16mode = utf8str_to_utf16str(utf8mode); - return _wfopen(utf16filename.c_str(),utf16mode.c_str()); +#if LL_WINDOWS + std::string utf8filename = filename; + std::string utf8mode = std::string(mode); + llutf16string utf16filename = utf8str_to_utf16str(utf8filename); + llutf16string utf16mode = utf8str_to_utf16str(utf8mode); + return _wfopen(utf16filename.c_str(),utf16mode.c_str()); #else - return ::fopen(filename.c_str(),mode); /* Flawfinder: ignore */ + return ::fopen(filename.c_str(),mode); /* Flawfinder: ignore */ #endif } -LLFILE* LLFile::_fsopen(const std::string& filename, const char* mode, int sharingFlag) +LLFILE* LLFile::_fsopen(const std::string& filename, const char* mode, int sharingFlag) { -#if LL_WINDOWS - std::string utf8filename = filename; - std::string utf8mode = std::string(mode); - llutf16string utf16filename = utf8str_to_utf16str(utf8filename); - llutf16string utf16mode = utf8str_to_utf16str(utf8mode); - return _wfsopen(utf16filename.c_str(),utf16mode.c_str(),sharingFlag); +#if LL_WINDOWS + std::string utf8filename = filename; + std::string utf8mode = std::string(mode); + llutf16string utf16filename = utf8str_to_utf16str(utf8filename); + llutf16string utf16mode = utf8str_to_utf16str(utf8mode); + return _wfsopen(utf16filename.c_str(),utf16mode.c_str(),sharingFlag); #else - llassert(0);//No corresponding function on non-windows - return NULL; + llassert(0);//No corresponding function on non-windows + return NULL; #endif } -int LLFile::close(LLFILE * file) +int LLFile::close(LLFILE * file) { - int ret_value = 0; - if (file) - { - ret_value = fclose(file); - } - return ret_value; + int ret_value = 0; + if (file) + { + ret_value = fclose(file); + } + return ret_value; } -int LLFile::remove(const std::string& filename, int supress_error) +int LLFile::remove(const std::string& filename, int supress_error) { -#if LL_WINDOWS - std::string utf8filename = filename; - llutf16string utf16filename = utf8str_to_utf16str(utf8filename); - int rc = _wremove(utf16filename.c_str()); +#if LL_WINDOWS + std::string utf8filename = filename; + llutf16string utf16filename = utf8str_to_utf16str(utf8filename); + int rc = _wremove(utf16filename.c_str()); #else - int rc = ::remove(filename.c_str()); + int rc = ::remove(filename.c_str()); #endif - return warnif("remove", filename, rc, supress_error); + return warnif("remove", filename, rc, supress_error); } -int LLFile::rename(const std::string& filename, const std::string& newname, int supress_error) +int LLFile::rename(const std::string& filename, const std::string& newname, int supress_error) { -#if LL_WINDOWS - std::string utf8filename = filename; - std::string utf8newname = newname; - llutf16string utf16filename = utf8str_to_utf16str(utf8filename); - llutf16string utf16newname = utf8str_to_utf16str(utf8newname); - int rc = _wrename(utf16filename.c_str(),utf16newname.c_str()); +#if LL_WINDOWS + std::string utf8filename = filename; + std::string utf8newname = newname; + llutf16string utf16filename = utf8str_to_utf16str(utf8filename); + llutf16string utf16newname = utf8str_to_utf16str(utf8newname); + int rc = _wrename(utf16filename.c_str(),utf16newname.c_str()); #else - int rc = ::rename(filename.c_str(),newname.c_str()); + int rc = ::rename(filename.c_str(),newname.c_str()); #endif - return warnif(STRINGIZE("rename to '" << newname << "' from"), filename, rc, supress_error); + return warnif(STRINGIZE("rename to '" << newname << "' from"), filename, rc, supress_error); } bool LLFile::copy(const std::string from, const std::string to) { - bool copied = false; - LLFILE* in = LLFile::fopen(from, "rb"); /* Flawfinder: ignore */ - if (in) - { - LLFILE* out = LLFile::fopen(to, "wb"); /* Flawfinder: ignore */ - if (out) - { - char buf[16384]; /* Flawfinder: ignore */ - size_t readbytes; - bool write_ok = true; - while(write_ok && (readbytes = fread(buf, 1, 16384, in))) /* Flawfinder: ignore */ - { - if (fwrite(buf, 1, readbytes, out) != readbytes) - { - LL_WARNS("LLFile") << "Short write" << LL_ENDL; - write_ok = false; - } - } - if ( write_ok ) - { - copied = true; - } - fclose(out); - } - fclose(in); - } - return copied; + bool copied = false; + LLFILE* in = LLFile::fopen(from, "rb"); /* Flawfinder: ignore */ + if (in) + { + LLFILE* out = LLFile::fopen(to, "wb"); /* Flawfinder: ignore */ + if (out) + { + char buf[16384]; /* Flawfinder: ignore */ + size_t readbytes; + bool write_ok = true; + while(write_ok && (readbytes = fread(buf, 1, 16384, in))) /* Flawfinder: ignore */ + { + if (fwrite(buf, 1, readbytes, out) != readbytes) + { + LL_WARNS("LLFile") << "Short write" << LL_ENDL; + write_ok = false; + } + } + if ( write_ok ) + { + copied = true; + } + fclose(out); + } + fclose(in); + } + return copied; } -int LLFile::stat(const std::string& filename, llstat* filestatus) +int LLFile::stat(const std::string& filename, llstat* filestatus) { #if LL_WINDOWS - std::string utf8filename = filename; - llutf16string utf16filename = utf8str_to_utf16str(utf8filename); - int rc = _wstat(utf16filename.c_str(),filestatus); + std::string utf8filename = filename; + llutf16string utf16filename = utf8str_to_utf16str(utf8filename); + int rc = _wstat(utf16filename.c_str(),filestatus); #else - int rc = ::stat(filename.c_str(),filestatus); + int rc = ::stat(filename.c_str(),filestatus); #endif - // We use stat() to determine existence (see isfile(), isdir()). - // Don't spam the log if the subject pathname doesn't exist. - return warnif("stat", filename, rc, ENOENT); + // We use stat() to determine existence (see isfile(), isdir()). + // Don't spam the log if the subject pathname doesn't exist. + return warnif("stat", filename, rc, ENOENT); } bool LLFile::isdir(const std::string& filename) { - llstat st; + llstat st; - return stat(filename, &st) == 0 && S_ISDIR(st.st_mode); + return stat(filename, &st) == 0 && S_ISDIR(st.st_mode); } bool LLFile::isfile(const std::string& filename) { - llstat st; + llstat st; - return stat(filename, &st) == 0 && S_ISREG(st.st_mode); + return stat(filename, &st) == 0 && S_ISREG(st.st_mode); } const char *LLFile::tmpdir() { - static std::string utf8path; + static std::string utf8path; - if (utf8path.empty()) - { - char sep; + if (utf8path.empty()) + { + char sep; #if LL_WINDOWS - sep = '\\'; + sep = '\\'; - std::vector utf16path(MAX_PATH + 1); - GetTempPathW(utf16path.size(), &utf16path[0]); - utf8path = ll_convert_wide_to_string(&utf16path[0]); + std::vector utf16path(MAX_PATH + 1); + GetTempPathW(utf16path.size(), &utf16path[0]); + utf8path = ll_convert_wide_to_string(&utf16path[0]); #else - sep = '/'; + sep = '/'; - utf8path = LLStringUtil::getenv("TMPDIR", "/tmp/"); + utf8path = LLStringUtil::getenv("TMPDIR", "/tmp/"); #endif - if (utf8path[utf8path.size() - 1] != sep) - { - utf8path += sep; - } - } - return utf8path.c_str(); + if (utf8path[utf8path.size() - 1] != sep) + { + utf8path += sep; + } + } + return utf8path.c_str(); } @@ -365,64 +365,64 @@ const char *LLFile::tmpdir() #if LL_WINDOWS -LLFILE * LLFile::_Fiopen(const std::string& filename, - std::ios::openmode mode) -{ // open a file - static const char *mods[] = - { // fopen mode strings corresponding to valid[i] - "r", "w", "w", "a", "rb", "wb", "wb", "ab", - "r+", "w+", "a+", "r+b", "w+b", "a+b", - 0}; - static const int valid[] = - { // valid combinations of open flags - ios_base::in, - ios_base::out, - ios_base::out | ios_base::trunc, - ios_base::out | ios_base::app, - ios_base::in | ios_base::binary, - ios_base::out | ios_base::binary, - ios_base::out | ios_base::trunc | ios_base::binary, - ios_base::out | ios_base::app | ios_base::binary, - ios_base::in | ios_base::out, - ios_base::in | ios_base::out | ios_base::trunc, - ios_base::in | ios_base::out | ios_base::app, - ios_base::in | ios_base::out | ios_base::binary, - ios_base::in | ios_base::out | ios_base::trunc - | ios_base::binary, - ios_base::in | ios_base::out | ios_base::app - | ios_base::binary, - 0}; - - LLFILE *fp = 0; - int n; - ios_base::openmode atendflag = mode & ios_base::ate; - ios_base::openmode norepflag = mode & ios_base::_Noreplace; - - if (mode & ios_base::_Nocreate) - mode |= ios_base::in; // file must exist - mode &= ~(ios_base::ate | ios_base::_Nocreate | ios_base::_Noreplace); - for (n = 0; valid[n] != 0 && valid[n] != mode; ++n) - ; // look for a valid mode - - if (valid[n] == 0) - return (0); // no valid mode - else if (norepflag && mode & (ios_base::out || ios_base::app) - && (fp = LLFile::fopen(filename, "r")) != 0) /* Flawfinder: ignore */ - { // file must not exist, close and fail - fclose(fp); - return (0); - } - else if (fp != 0 && fclose(fp) != 0) - return (0); // can't close after test open +LLFILE * LLFile::_Fiopen(const std::string& filename, + std::ios::openmode mode) +{ // open a file + static const char *mods[] = + { // fopen mode strings corresponding to valid[i] + "r", "w", "w", "a", "rb", "wb", "wb", "ab", + "r+", "w+", "a+", "r+b", "w+b", "a+b", + 0}; + static const int valid[] = + { // valid combinations of open flags + ios_base::in, + ios_base::out, + ios_base::out | ios_base::trunc, + ios_base::out | ios_base::app, + ios_base::in | ios_base::binary, + ios_base::out | ios_base::binary, + ios_base::out | ios_base::trunc | ios_base::binary, + ios_base::out | ios_base::app | ios_base::binary, + ios_base::in | ios_base::out, + ios_base::in | ios_base::out | ios_base::trunc, + ios_base::in | ios_base::out | ios_base::app, + ios_base::in | ios_base::out | ios_base::binary, + ios_base::in | ios_base::out | ios_base::trunc + | ios_base::binary, + ios_base::in | ios_base::out | ios_base::app + | ios_base::binary, + 0}; + + LLFILE *fp = 0; + int n; + ios_base::openmode atendflag = mode & ios_base::ate; + ios_base::openmode norepflag = mode & ios_base::_Noreplace; + + if (mode & ios_base::_Nocreate) + mode |= ios_base::in; // file must exist + mode &= ~(ios_base::ate | ios_base::_Nocreate | ios_base::_Noreplace); + for (n = 0; valid[n] != 0 && valid[n] != mode; ++n) + ; // look for a valid mode + + if (valid[n] == 0) + return (0); // no valid mode + else if (norepflag && mode & (ios_base::out || ios_base::app) + && (fp = LLFile::fopen(filename, "r")) != 0) /* Flawfinder: ignore */ + { // file must not exist, close and fail + fclose(fp); + return (0); + } + else if (fp != 0 && fclose(fp) != 0) + return (0); // can't close after test open // should open with protection here, if other than default - else if ((fp = LLFile::fopen(filename, mods[n])) == 0) /* Flawfinder: ignore */ - return (0); // open failed + else if ((fp = LLFile::fopen(filename, mods[n])) == 0) /* Flawfinder: ignore */ + return (0); // open failed - if (!atendflag || fseek(fp, 0, SEEK_END) == 0) - return (fp); // no need to seek to end, or seek succeeded + if (!atendflag || fseek(fp, 0, SEEK_END) == 0) + return (fp); // no need to seek to end, or seek succeeded - fclose(fp); // can't position at end - return (0); + fclose(fp); // can't position at end + return (0); } #endif /* LL_WINDOWS */ @@ -469,26 +469,26 @@ void llofstream::open(const std::string& _Filename, ios_base::openmode _Mode) std::streamsize llifstream_size(llifstream& ifstr) { - if(!ifstr.is_open()) return 0; - std::streampos pos_old = ifstr.tellg(); - ifstr.seekg(0, ios_base::beg); - std::streampos pos_beg = ifstr.tellg(); - ifstr.seekg(0, ios_base::end); - std::streampos pos_end = ifstr.tellg(); - ifstr.seekg(pos_old, ios_base::beg); - return pos_end - pos_beg; + if(!ifstr.is_open()) return 0; + std::streampos pos_old = ifstr.tellg(); + ifstr.seekg(0, ios_base::beg); + std::streampos pos_beg = ifstr.tellg(); + ifstr.seekg(0, ios_base::end); + std::streampos pos_end = ifstr.tellg(); + ifstr.seekg(pos_old, ios_base::beg); + return pos_end - pos_beg; } std::streamsize llofstream_size(llofstream& ofstr) { - if(!ofstr.is_open()) return 0; - std::streampos pos_old = ofstr.tellp(); - ofstr.seekp(0, ios_base::beg); - std::streampos pos_beg = ofstr.tellp(); - ofstr.seekp(0, ios_base::end); - std::streampos pos_end = ofstr.tellp(); - ofstr.seekp(pos_old, ios_base::beg); - return pos_end - pos_beg; + if(!ofstr.is_open()) return 0; + std::streampos pos_old = ofstr.tellp(); + ofstr.seekp(0, ios_base::beg); + std::streampos pos_beg = ofstr.tellp(); + ofstr.seekp(0, ios_base::end); + std::streampos pos_end = ofstr.tellp(); + ofstr.seekp(pos_old, ios_base::beg); + return pos_end - pos_beg; } #endif // LL_WINDOWS diff --git a/indra/llcommon/llfile.h b/indra/llcommon/llfile.h index 9de095b45d..08a008c19a 100644 --- a/indra/llcommon/llfile.h +++ b/indra/llcommon/llfile.h @@ -1,4 +1,4 @@ -/** +/** * @file llfile.h * @author Michael Schlachter * @date 2006-03-23 @@ -8,21 +8,21 @@ * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -35,16 +35,16 @@ * Attempts to mostly mirror the POSIX style IO functions. */ -typedef FILE LLFILE; +typedef FILE LLFILE; #include #include #if LL_WINDOWS // windows version of stat function and stat data structure are called _stat -typedef struct _stat llstat; +typedef struct _stat llstat; #else -typedef struct stat llstat; +typedef struct stat llstat; #include #endif @@ -61,29 +61,29 @@ typedef struct stat llstat; class LL_COMMON_API LLFile { public: - // All these functions take UTF8 path/filenames. - static LLFILE* fopen(const std::string& filename,const char* accessmode); /* Flawfinder: ignore */ - static LLFILE* _fsopen(const std::string& filename,const char* accessmode,int sharingFlag); + // All these functions take UTF8 path/filenames. + static LLFILE* fopen(const std::string& filename,const char* accessmode); /* Flawfinder: ignore */ + static LLFILE* _fsopen(const std::string& filename,const char* accessmode,int sharingFlag); - static int close(LLFILE * file); + static int close(LLFILE * file); - // perms is a permissions mask like 0777 or 0700. In most cases it will - // be overridden by the user's umask. It is ignored on Windows. - // mkdir() considers "directory already exists" to be SUCCESS. - static int mkdir(const std::string& filename, int perms = 0700); + // perms is a permissions mask like 0777 or 0700. In most cases it will + // be overridden by the user's umask. It is ignored on Windows. + // mkdir() considers "directory already exists" to be SUCCESS. + static int mkdir(const std::string& filename, int perms = 0700); - static int rmdir(const std::string& filename); - static int remove(const std::string& filename, int supress_error = 0); - static int rename(const std::string& filename,const std::string& newname, int supress_error = 0); - static bool copy(const std::string from, const std::string to); + static int rmdir(const std::string& filename); + static int remove(const std::string& filename, int supress_error = 0); + static int rename(const std::string& filename,const std::string& newname, int supress_error = 0); + static bool copy(const std::string from, const std::string to); - static int stat(const std::string& filename,llstat* file_status); - static bool isdir(const std::string& filename); - static bool isfile(const std::string& filename); - static LLFILE * _Fiopen(const std::string& filename, - std::ios::openmode mode); + static int stat(const std::string& filename,llstat* file_status); + static bool isdir(const std::string& filename); + static bool isfile(const std::string& filename); + static LLFILE * _Fiopen(const std::string& filename, + std::ios::openmode mode); - static const char * tmpdir(); + static const char * tmpdir(); }; /// RAII class @@ -158,39 +158,39 @@ private: * Does The Right Thing when passed a non-ASCII pathname. Sadly, that isn't * true of Microsoft's std::ifstream. */ -class LL_COMMON_API llifstream : public std::ifstream +class LL_COMMON_API llifstream : public std::ifstream { - // input stream associated with a C stream + // input stream associated with a C stream public: - // Constructors: - /** - * @brief Default constructor. - * - * Initializes @c sb using its default constructor, and passes - * @c &sb to the base class initializer. Does not open any files - * (you haven't given it a filename to open). + // Constructors: + /** + * @brief Default constructor. + * + * Initializes @c sb using its default constructor, and passes + * @c &sb to the base class initializer. Does not open any files + * (you haven't given it a filename to open). */ - llifstream(); + llifstream(); - /** - * @brief Create an input file stream. - * @param Filename String specifying the filename. - * @param Mode Open file in specified mode (see std::ios_base). - * + /** + * @brief Create an input file stream. + * @param Filename String specifying the filename. + * @param Mode Open file in specified mode (see std::ios_base). + * * @c ios_base::in is automatically included in @a mode. */ - explicit llifstream(const std::string& _Filename, + explicit llifstream(const std::string& _Filename, ios_base::openmode _Mode = ios_base::in); - /** - * @brief Opens an external file. - * @param Filename The name of the file. - * @param Node The open mode flags. - * - * Calls @c llstdio_filebuf::open(s,mode|in). If that function - * fails, @c failbit is set in the stream's error state. + /** + * @brief Opens an external file. + * @param Filename The name of the file. + * @param Node The open mode flags. + * + * Calls @c llstdio_filebuf::open(s,mode|in). If that function + * fails, @c failbit is set in the stream's error state. */ - void open(const std::string& _Filename, + void open(const std::string& _Filename, ios_base::openmode _Mode = ios_base::in); }; @@ -203,37 +203,37 @@ class LL_COMMON_API llifstream : public std::ifstream * Right Thing when passed a non-ASCII pathname. Sadly, that isn't true of * Microsoft's std::ofstream. */ -class LL_COMMON_API llofstream : public std::ofstream +class LL_COMMON_API llofstream : public std::ofstream { public: - // Constructors: - /** - * @brief Default constructor. - * - * Initializes @c sb using its default constructor, and passes - * @c &sb to the base class initializer. Does not open any files - * (you haven't given it a filename to open). + // Constructors: + /** + * @brief Default constructor. + * + * Initializes @c sb using its default constructor, and passes + * @c &sb to the base class initializer. Does not open any files + * (you haven't given it a filename to open). */ - llofstream(); - - /** - * @brief Create an output file stream. - * @param Filename String specifying the filename. - * @param Mode Open file in specified mode (see std::ios_base). - * - * @c ios_base::out is automatically included in @a mode. + llofstream(); + + /** + * @brief Create an output file stream. + * @param Filename String specifying the filename. + * @param Mode Open file in specified mode (see std::ios_base). + * + * @c ios_base::out is automatically included in @a mode. */ - explicit llofstream(const std::string& _Filename, + explicit llofstream(const std::string& _Filename, ios_base::openmode _Mode = ios_base::out|ios_base::trunc); - /** - * @brief Opens an external file. - * @param Filename The name of the file. - * @param Node The open mode flags. - * - * @c ios_base::out is automatically included in @a mode. + /** + * @brief Opens an external file. + * @param Filename The name of the file. + * @param Node The open mode flags. + * + * @c ios_base::out is automatically included in @a mode. */ - void open(const std::string& _Filename, + void open(const std::string& _Filename, ios_base::openmode _Mode = ios_base::out|ios_base::trunc); }; diff --git a/indra/llcommon/llfindlocale.cpp b/indra/llcommon/llfindlocale.cpp index f019bd0c64..e39812bfc4 100644 --- a/indra/llcommon/llfindlocale.cpp +++ b/indra/llcommon/llfindlocale.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llfindlocale.cpp * @brief Detect system language setting * * $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$ */ diff --git a/indra/llcommon/llfindlocale.h b/indra/llcommon/llfindlocale.h index 6770db5774..07b59853c3 100644 --- a/indra/llcommon/llfindlocale.h +++ b/indra/llcommon/llfindlocale.h @@ -1,25 +1,25 @@ -/** +/** * @file llfindlocale.h * @brief Detect system language setting * * $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$ */ diff --git a/indra/llcommon/llfixedbuffer.cpp b/indra/llcommon/llfixedbuffer.cpp index bd4db8be84..4f28d2240e 100644 --- a/indra/llcommon/llfixedbuffer.cpp +++ b/indra/llcommon/llfixedbuffer.cpp @@ -1,24 +1,24 @@ -/** +/** * @file llfixedbuffer.cpp * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -29,69 +29,69 @@ //////////////////////////////////////////////////////////////////////////// LLFixedBuffer::LLFixedBuffer(const U32 max_lines) - : LLLineBuffer(), - mMaxLines(max_lines), - mMutex() + : LLLineBuffer(), + mMaxLines(max_lines), + mMutex() { - mTimer.reset(); + mTimer.reset(); } LLFixedBuffer::~LLFixedBuffer() { - clear(); + clear(); } void LLFixedBuffer::clear() { - mMutex.lock() ; - mLines.clear(); - mAddTimes.clear(); - mLineLengths.clear(); - mMutex.unlock() ; + mMutex.lock() ; + mLines.clear(); + mAddTimes.clear(); + mLineLengths.clear(); + mMutex.unlock() ; - mTimer.reset(); + mTimer.reset(); } void LLFixedBuffer::addLine(const std::string& utf8line) { - LLWString wstring = utf8str_to_wstring(utf8line); - addWLine(wstring); + LLWString wstring = utf8str_to_wstring(utf8line); + addWLine(wstring); } void LLFixedBuffer::addWLine(const LLWString& line) { - if (line.empty()) - { - return; - } - - removeExtraLines(); - - mMutex.lock() ; - mLines.push_back(line); - mLineLengths.push_back((S32)line.length()); - mAddTimes.push_back(mTimer.getElapsedTimeF32()); - mMutex.unlock() ; + if (line.empty()) + { + return; + } + + removeExtraLines(); + + mMutex.lock() ; + mLines.push_back(line); + mLineLengths.push_back((S32)line.length()); + mAddTimes.push_back(mTimer.getElapsedTimeF32()); + mMutex.unlock() ; } void LLFixedBuffer::setMaxLines(S32 max_lines) { - mMaxLines = max_lines; + mMaxLines = max_lines; - removeExtraLines(); + removeExtraLines(); } void LLFixedBuffer::removeExtraLines() { - mMutex.lock() ; - while ((S32)mLines.size() > llmax((S32)0, (S32)(mMaxLines - 1))) - { - mLines.pop_front(); - mAddTimes.pop_front(); - mLineLengths.pop_front(); - } - mMutex.unlock() ; + mMutex.lock() ; + while ((S32)mLines.size() > llmax((S32)0, (S32)(mMaxLines - 1))) + { + mLines.pop_front(); + mAddTimes.pop_front(); + mLineLengths.pop_front(); + } + mMutex.unlock() ; } diff --git a/indra/llcommon/llfixedbuffer.h b/indra/llcommon/llfixedbuffer.h index 554cf48a4c..eca0792d35 100644 --- a/indra/llcommon/llfixedbuffer.h +++ b/indra/llcommon/llfixedbuffer.h @@ -1,25 +1,25 @@ -/** +/** * @file llfixedbuffer.h * @brief A fixed size buffer of lines. * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -38,27 +38,27 @@ class LL_COMMON_API LLFixedBuffer : public LLLineBuffer { public: - LLFixedBuffer(const U32 max_lines = 20); - ~LLFixedBuffer(); + LLFixedBuffer(const U32 max_lines = 20); + ~LLFixedBuffer(); + + LLTimer mTimer; + U32 mMaxLines; + std::deque mLines; + std::deque mAddTimes; + std::deque mLineLengths; - LLTimer mTimer; - U32 mMaxLines; - std::deque mLines; - std::deque mAddTimes; - std::deque mLineLengths; + /*virtual*/ void clear(); // Clear the buffer, and reset it. - /*virtual*/ void clear(); // Clear the buffer, and reset it. + /*virtual*/ void addLine(const std::string& utf8line); - /*virtual*/ void addLine(const std::string& utf8line); + void setMaxLines(S32 max_lines); - void setMaxLines(S32 max_lines); - protected: - void removeExtraLines(); - void addWLine(const LLWString& line); + void removeExtraLines(); + void addWLine(const LLWString& line); protected: - LLMutex mMutex ; + LLMutex mMutex ; }; #endif //LL_FIXED_BUFFER_H diff --git a/indra/llcommon/llformat.cpp b/indra/llcommon/llformat.cpp index 3b2b3038ea..dc5726e29f 100644 --- a/indra/llcommon/llformat.cpp +++ b/indra/llcommon/llformat.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llformat.cpp * @date January 2007 * @brief string formatting utility @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -35,36 +35,36 @@ // wrapper for vsnprintf to be called from llformatXXX functions. static void va_format(std::string& out, const char *fmt, va_list va) { - char tstr[1024]; /* Flawfinder: ignore */ + char tstr[1024]; /* Flawfinder: ignore */ #if LL_WINDOWS - _vsnprintf(tstr, 1024, fmt, va); + _vsnprintf(tstr, 1024, fmt, va); #else - vsnprintf(tstr, 1024, fmt, va); /* Flawfinder: ignore */ + vsnprintf(tstr, 1024, fmt, va); /* Flawfinder: ignore */ #endif - out.assign(tstr); + out.assign(tstr); } std::string llformat(const char *fmt, ...) { - std::string res; - va_list va; - va_start(va, fmt); - va_format(res, fmt, va); - va_end(va); - return res; + std::string res; + va_list va; + va_start(va, fmt); + va_format(res, fmt, va); + va_end(va); + return res; } std::string llformat_to_utf8(const char *fmt, ...) { - std::string res; - va_list va; - va_start(va, fmt); - va_format(res, fmt, va); - va_end(va); + std::string res; + va_list va; + va_start(va, fmt); + va_format(res, fmt, va); + va_end(va); #if LL_WINDOWS - // made converting to utf8. See EXT-8318. - res = ll_convert_string_to_utf8_string(res); + // made converting to utf8. See EXT-8318. + res = ll_convert_string_to_utf8_string(res); #endif - return res; + return res; } diff --git a/indra/llcommon/llformat.h b/indra/llcommon/llformat.h index fb8e7cd045..4456a72696 100644 --- a/indra/llcommon/llformat.h +++ b/indra/llcommon/llformat.h @@ -1,4 +1,4 @@ -/** +/** * @file llformat.h * @date January 2007 * @brief string formatting utility @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcommon/llframetimer.cpp b/indra/llcommon/llframetimer.cpp index 1e9920746b..2805662d6f 100644 --- a/indra/llcommon/llframetimer.cpp +++ b/indra/llcommon/llframetimer.cpp @@ -1,24 +1,24 @@ -/** +/** * @file llframetimer.cpp * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -30,7 +30,7 @@ #include "llframetimer.h" // Static members -//LLTimer LLFrameTimer::sInternalTimer; +//LLTimer LLFrameTimer::sInternalTimer; U64 LLFrameTimer::sStartTotalTime = totalTime(); F64 LLFrameTimer::sFrameTime = 0.0; U64 LLFrameTimer::sTotalTime = 0; @@ -42,34 +42,34 @@ const F64 USEC_TO_SEC_F64 = 0.000001; // static void LLFrameTimer::updateFrameTime() { - U64 total_time = totalTime(); - sFrameDeltaTime = total_time - sTotalTime; - sTotalTime = total_time; - sTotalSeconds = U64_to_F64(sTotalTime) * USEC_TO_SEC_F64; - sFrameTime = U64_to_F64(sTotalTime - sStartTotalTime) * USEC_TO_SEC_F64; -} + U64 total_time = totalTime(); + sFrameDeltaTime = total_time - sTotalTime; + sTotalTime = total_time; + sTotalSeconds = U64_to_F64(sTotalTime) * USEC_TO_SEC_F64; + sFrameTime = U64_to_F64(sTotalTime - sStartTotalTime) * USEC_TO_SEC_F64; +} void LLFrameTimer::start() { - reset(); - mStarted = TRUE; + reset(); + mStarted = TRUE; } void LLFrameTimer::stop() { - mStarted = FALSE; + mStarted = FALSE; } void LLFrameTimer::reset() { - mStartTime = sFrameTime; - mExpiry = sFrameTime; + mStartTime = sFrameTime; + mExpiry = sFrameTime; } void LLFrameTimer::resetWithExpiry(F32 expiration) { - reset(); - setTimerExpirySec(expiration); + reset(); + setTimerExpirySec(expiration); } // Don't combine pause/unpause with start/stop @@ -82,69 +82,69 @@ void LLFrameTimer::resetWithExpiry(F32 expiration) // Note: elapsed would also be valid with no unpause() call (= time run until pause() called) void LLFrameTimer::pause() { - if (mStarted) - mStartTime = sFrameTime - mStartTime; // save dtime - mStarted = FALSE; + if (mStarted) + mStartTime = sFrameTime - mStartTime; // save dtime + mStarted = FALSE; } void LLFrameTimer::unpause() { - if (!mStarted) - mStartTime = sFrameTime - mStartTime; // restore dtime - mStarted = TRUE; + if (!mStarted) + mStartTime = sFrameTime - mStartTime; // restore dtime + mStarted = TRUE; } void LLFrameTimer::setTimerExpirySec(F32 expiration) { - mExpiry = expiration + mStartTime; + mExpiry = expiration + mStartTime; } void LLFrameTimer::setExpiryAt(F64 seconds_since_epoch) { - mStartTime = sFrameTime; - mExpiry = seconds_since_epoch - (USEC_TO_SEC_F64 * sStartTotalTime); + mStartTime = sFrameTime; + mExpiry = seconds_since_epoch - (USEC_TO_SEC_F64 * sStartTotalTime); } F64 LLFrameTimer::expiresAt() const { - F64 expires_at = U64_to_F64(sStartTotalTime) * USEC_TO_SEC_F64; - expires_at += mExpiry; - return expires_at; + F64 expires_at = U64_to_F64(sStartTotalTime) * USEC_TO_SEC_F64; + expires_at += mExpiry; + return expires_at; } BOOL LLFrameTimer::checkExpirationAndReset(F32 expiration) { - //LL_INFOS() << "LLFrameTimer::checkExpirationAndReset()" << LL_ENDL; - //LL_INFOS() << " mStartTime:" << mStartTime << LL_ENDL; - //LL_INFOS() << " sFrameTime:" << sFrameTime << LL_ENDL; - //LL_INFOS() << " mExpiry: " << mExpiry << LL_ENDL; - - if(hasExpired()) - { - reset(); - setTimerExpirySec(expiration); - return TRUE; - } - return FALSE; + //LL_INFOS() << "LLFrameTimer::checkExpirationAndReset()" << LL_ENDL; + //LL_INFOS() << " mStartTime:" << mStartTime << LL_ENDL; + //LL_INFOS() << " sFrameTime:" << sFrameTime << LL_ENDL; + //LL_INFOS() << " mExpiry: " << mExpiry << LL_ENDL; + + if(hasExpired()) + { + reset(); + setTimerExpirySec(expiration); + return TRUE; + } + return FALSE; } // static F32 LLFrameTimer::getFrameDeltaTimeF32() { - return (F32)(U64_to_F64(sFrameDeltaTime) * USEC_TO_SEC_F64); + return (F32)(U64_to_F64(sFrameDeltaTime) * USEC_TO_SEC_F64); } -// static +// static // Return seconds since the current frame started F32 LLFrameTimer::getCurrentFrameTime() { - U64 frame_time = totalTime() - sTotalTime; - return (F32)(U64_to_F64(frame_time) * USEC_TO_SEC_F64); + U64 frame_time = totalTime() - sTotalTime; + return (F32)(U64_to_F64(frame_time) * USEC_TO_SEC_F64); } // Glue code to avoid full class .h file #includes F32 getCurrentFrameTime() { - return (F32)(LLFrameTimer::getCurrentFrameTime()); + return (F32)(LLFrameTimer::getCurrentFrameTime()); } diff --git a/indra/llcommon/llframetimer.h b/indra/llcommon/llframetimer.h index 81bd5da8a3..876d933fd1 100644 --- a/indra/llcommon/llframetimer.h +++ b/indra/llcommon/llframetimer.h @@ -1,4 +1,4 @@ -/** +/** * @file llframetimer.h * @brief A lightweight timer that measures seconds and is only * updated once per frame. @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -36,113 +36,113 @@ #include "lltimer.h" -class LL_COMMON_API LLFrameTimer +class LL_COMMON_API LLFrameTimer { public: - LLFrameTimer() : mStartTime( sFrameTime ), mExpiry(0), mStarted(TRUE) {} + LLFrameTimer() : mStartTime( sFrameTime ), mExpiry(0), mStarted(TRUE) {} - // Return the number of seconds since the start of this - // application instance. - static F64SecondsImplicit getElapsedSeconds() - { - // Loses msec precision after ~4.5 hours... - return sFrameTime; - } - - // Return a low precision usec since epoch - static U64 getTotalTime() - { - return sTotalTime ? U64MicrosecondsImplicit(sTotalTime) : totalTime(); - } - - // Return a low precision seconds since epoch - static F64 getTotalSeconds() - { - return sTotalSeconds; - } - - // Call this method once per frame to update the current frame time. This is actually called - // at some other times as well - static void updateFrameTime(); - - // Call this method once, and only once, per frame to update the current frame count. - static void updateFrameCount() { sFrameCount++; } - - static U32 getFrameCount() { return sFrameCount; } - - static F32 getFrameDeltaTimeF32(); - - // Return seconds since the current frame started - static F32 getCurrentFrameTime(); - - // MANIPULATORS - void start(); - void stop(); - void reset(); - void resetWithExpiry(F32 expiration); - void pause(); - void unpause(); - void setTimerExpirySec(F32 expiration); - void setExpiryAt(F64 seconds_since_epoch); - BOOL checkExpirationAndReset(F32 expiration); - F32 getElapsedTimeAndResetF32() { F32 t = F32(sFrameTime - mStartTime); reset(); return t; } - - void setAge(const F64 age) { mStartTime = sFrameTime - age; } - - // ACCESSORS - BOOL hasExpired() const { return (sFrameTime >= mExpiry); } - F32 getTimeToExpireF32() const { return (F32)(mExpiry - sFrameTime); } - F32 getElapsedTimeF32() const { return mStarted ? (F32)(sFrameTime - mStartTime) : (F32)mStartTime; } - BOOL getStarted() const { return mStarted; } - - // return the seconds since epoch when this timer will expire. - F64 expiresAt() const; - -protected: - // A single, high resolution timer that drives all LLFrameTimers - // *NOTE: no longer used. - //static LLTimer sInternalTimer; - - // - // Aplication constants - // - - // Start time of opp in usec since epoch - static U64 sStartTotalTime; - - // - // Data updated per frame - // - - // Seconds since application start - static F64 sFrameTime; - - // Time that has elapsed since last call to updateFrameTime() - static U64 sFrameDeltaTime; - - // Total microseconds since epoch. - static U64 sTotalTime; - - // Seconds since epoch. - static F64 sTotalSeconds; - - // Total number of frames elapsed in application - static S32 sFrameCount; - - // - // Member data - // - - // Number of seconds after application start when this timer was - // started. Set equal to sFrameTime when reset. - F64 mStartTime; - - // Timer expires this many seconds after application start time. - F64 mExpiry; - - // Useful bit of state usually associated with timers, but does - // not affect actual functionality - BOOL mStarted; + // Return the number of seconds since the start of this + // application instance. + static F64SecondsImplicit getElapsedSeconds() + { + // Loses msec precision after ~4.5 hours... + return sFrameTime; + } + + // Return a low precision usec since epoch + static U64 getTotalTime() + { + return sTotalTime ? U64MicrosecondsImplicit(sTotalTime) : totalTime(); + } + + // Return a low precision seconds since epoch + static F64 getTotalSeconds() + { + return sTotalSeconds; + } + + // Call this method once per frame to update the current frame time. This is actually called + // at some other times as well + static void updateFrameTime(); + + // Call this method once, and only once, per frame to update the current frame count. + static void updateFrameCount() { sFrameCount++; } + + static U32 getFrameCount() { return sFrameCount; } + + static F32 getFrameDeltaTimeF32(); + + // Return seconds since the current frame started + static F32 getCurrentFrameTime(); + + // MANIPULATORS + void start(); + void stop(); + void reset(); + void resetWithExpiry(F32 expiration); + void pause(); + void unpause(); + void setTimerExpirySec(F32 expiration); + void setExpiryAt(F64 seconds_since_epoch); + BOOL checkExpirationAndReset(F32 expiration); + F32 getElapsedTimeAndResetF32() { F32 t = F32(sFrameTime - mStartTime); reset(); return t; } + + void setAge(const F64 age) { mStartTime = sFrameTime - age; } + + // ACCESSORS + BOOL hasExpired() const { return (sFrameTime >= mExpiry); } + F32 getTimeToExpireF32() const { return (F32)(mExpiry - sFrameTime); } + F32 getElapsedTimeF32() const { return mStarted ? (F32)(sFrameTime - mStartTime) : (F32)mStartTime; } + BOOL getStarted() const { return mStarted; } + + // return the seconds since epoch when this timer will expire. + F64 expiresAt() const; + +protected: + // A single, high resolution timer that drives all LLFrameTimers + // *NOTE: no longer used. + //static LLTimer sInternalTimer; + + // + // Aplication constants + // + + // Start time of opp in usec since epoch + static U64 sStartTotalTime; + + // + // Data updated per frame + // + + // Seconds since application start + static F64 sFrameTime; + + // Time that has elapsed since last call to updateFrameTime() + static U64 sFrameDeltaTime; + + // Total microseconds since epoch. + static U64 sTotalTime; + + // Seconds since epoch. + static F64 sTotalSeconds; + + // Total number of frames elapsed in application + static S32 sFrameCount; + + // + // Member data + // + + // Number of seconds after application start when this timer was + // started. Set equal to sFrameTime when reset. + F64 mStartTime; + + // Timer expires this many seconds after application start time. + F64 mExpiry; + + // Useful bit of state usually associated with timers, but does + // not affect actual functionality + BOOL mStarted; }; // Glue code for Havok (or anything else that doesn't want the full .h files) diff --git a/indra/llcommon/llhandle.h b/indra/llcommon/llhandle.h index 570cd330b8..ceea1d9c48 100644 --- a/indra/llcommon/llhandle.h +++ b/indra/llcommon/llhandle.h @@ -1,4 +1,4 @@ -/** +/** * @file llhandle.h * @brief "Handle" to an object (usually a floater) whose lifetime you don't * control. @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. -* +* * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. -* +* * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. -* +* * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -* +* * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -42,22 +42,22 @@ class LLTombStone : public LLRefCount { public: - LLTombStone(void* target = NULL) : mTarget(target) {} + LLTombStone(void* target = NULL) : mTarget(target) {} - void setTarget(void* target) { mTarget = target; } - void* getTarget() const { return mTarget; } + void setTarget(void* target) { mTarget = target; } + void* getTarget() const { return mTarget; } private: - mutable void* mTarget; + mutable void* mTarget; }; /** - * LLHandles are used to refer to objects whose lifetime you do not control or influence. - * Calling get() on a handle will return a pointer to the referenced object or NULL, - * if the object no longer exists. Note that during the lifetime of the returned pointer, - * you are assuming that the object will not be deleted by any action you perform, - * or any other thread, as normal when using pointers, so avoid using that pointer outside of - * the local code block. - * + * LLHandles are used to refer to objects whose lifetime you do not control or influence. + * Calling get() on a handle will return a pointer to the referenced object or NULL, + * if the object no longer exists. Note that during the lifetime of the returned pointer, + * you are assuming that the object will not be deleted by any action you perform, + * or any other thread, as normal when using pointers, so avoid using that pointer outside of + * the local code block. + * * https://wiki.lindenlab.com/mediawiki/index.php?title=LLHandle&oldid=79669 * * The implementation is like some "weak pointer" implementations. When we @@ -84,58 +84,58 @@ private: template class LLHandle { - template friend class LLHandle; - template friend class LLHandleProvider; + template friend class LLHandle; + template friend class LLHandleProvider; public: - LLHandle() : mTombStone(getDefaultTombStone()) {} - - template - LLHandle(const LLHandle& other, typename boost::enable_if< typename boost::is_convertible >::type* dummy = 0) - : mTombStone(other.mTombStone) - {} - - bool isDead() const - { - return mTombStone->getTarget() == NULL; - } - - void markDead() - { - mTombStone = getDefaultTombStone(); - } - - T* get() const - { - return reinterpret_cast(mTombStone->getTarget()); - } - - friend bool operator== (const LLHandle& lhs, const LLHandle& rhs) - { - return lhs.mTombStone == rhs.mTombStone; - } - friend bool operator!= (const LLHandle& lhs, const LLHandle& rhs) - { - return !(lhs == rhs); - } - friend bool operator< (const LLHandle& lhs, const LLHandle& rhs) - { - return lhs.mTombStone < rhs.mTombStone; - } - friend bool operator> (const LLHandle& lhs, const LLHandle& rhs) - { - return lhs.mTombStone > rhs.mTombStone; - } + LLHandle() : mTombStone(getDefaultTombStone()) {} + + template + LLHandle(const LLHandle& other, typename boost::enable_if< typename boost::is_convertible >::type* dummy = 0) + : mTombStone(other.mTombStone) + {} + + bool isDead() const + { + return mTombStone->getTarget() == NULL; + } + + void markDead() + { + mTombStone = getDefaultTombStone(); + } + + T* get() const + { + return reinterpret_cast(mTombStone->getTarget()); + } + + friend bool operator== (const LLHandle& lhs, const LLHandle& rhs) + { + return lhs.mTombStone == rhs.mTombStone; + } + friend bool operator!= (const LLHandle& lhs, const LLHandle& rhs) + { + return !(lhs == rhs); + } + friend bool operator< (const LLHandle& lhs, const LLHandle& rhs) + { + return lhs.mTombStone < rhs.mTombStone; + } + friend bool operator> (const LLHandle& lhs, const LLHandle& rhs) + { + return lhs.mTombStone > rhs.mTombStone; + } protected: - LLPointer mTombStone; + LLPointer mTombStone; private: - typedef T* pointer_t; - static LLPointer& getDefaultTombStone() - { - static LLPointer sDefaultTombStone = new LLTombStone; - return sDefaultTombStone; - } + typedef T* pointer_t; + static LLPointer& getDefaultTombStone() + { + static LLPointer sDefaultTombStone = new LLTombStone; + return sDefaultTombStone; + } }; /** @@ -150,36 +150,36 @@ template class LLRootHandle : public LLHandle { public: - typedef LLRootHandle self_t; - typedef LLHandle base_t; - - LLRootHandle(T* object) { bind(object); } - LLRootHandle() {}; - ~LLRootHandle() { unbind(); } - - // this is redundant, since an LLRootHandle *is* an LLHandle - //LLHandle getHandle() { return LLHandle(*this); } - - void bind(T* object) - { - // unbind existing tombstone - if (LLHandle::mTombStone.notNull()) - { - if (LLHandle::mTombStone->getTarget() == (void*)object) return; - LLHandle::mTombStone->setTarget(NULL); - } - // tombstone reference counted, so no paired delete - LLHandle::mTombStone = new LLTombStone((void*)object); - } - - void unbind() - { - LLHandle::mTombStone->setTarget(NULL); - } - - //don't allow copying of root handles, since there should only be one + typedef LLRootHandle self_t; + typedef LLHandle base_t; + + LLRootHandle(T* object) { bind(object); } + LLRootHandle() {}; + ~LLRootHandle() { unbind(); } + + // this is redundant, since an LLRootHandle *is* an LLHandle + //LLHandle getHandle() { return LLHandle(*this); } + + void bind(T* object) + { + // unbind existing tombstone + if (LLHandle::mTombStone.notNull()) + { + if (LLHandle::mTombStone->getTarget() == (void*)object) return; + LLHandle::mTombStone->setTarget(NULL); + } + // tombstone reference counted, so no paired delete + LLHandle::mTombStone = new LLTombStone((void*)object); + } + + void unbind() + { + LLHandle::mTombStone->setTarget(NULL); + } + + //don't allow copying of root handles, since there should only be one private: - LLRootHandle(const LLRootHandle& other) {}; + LLRootHandle(const LLRootHandle& other) {}; }; /** @@ -190,31 +190,31 @@ template class LLHandleProvider { public: - LLHandle getHandle() const - { - // perform lazy binding to avoid small tombstone allocations for handle - // providers whose handles are never referenced - mHandle.bind(static_cast(const_cast* >(this))); - return mHandle; - } - - template - LLHandle getDerivedHandle(typename boost::enable_if< typename boost::is_convertible >::type* dummy = 0) const - { - LLHandle downcast_handle; - downcast_handle.mTombStone = getHandle().mTombStone; - return downcast_handle; - } + LLHandle getHandle() const + { + // perform lazy binding to avoid small tombstone allocations for handle + // providers whose handles are never referenced + mHandle.bind(static_cast(const_cast* >(this))); + return mHandle; + } + + template + LLHandle getDerivedHandle(typename boost::enable_if< typename boost::is_convertible >::type* dummy = 0) const + { + LLHandle downcast_handle; + downcast_handle.mTombStone = getHandle().mTombStone; + return downcast_handle; + } protected: - typedef LLHandle handle_type_t; - LLHandleProvider() - { - // provided here to enforce T deriving from LLHandleProvider - } + typedef LLHandle handle_type_t; + LLHandleProvider() + { + // provided here to enforce T deriving from LLHandleProvider + } private: - mutable LLRootHandle mHandle; + mutable LLRootHandle mHandle; }; @@ -236,12 +236,12 @@ protected: }; /** - * This is a simple wrapper for Handles, allowing direct calls to the underlying - * pointer. The checked handle will throw a Stale if an attempt - * is made to access the object referenced by the handle and that object has + * This is a simple wrapper for Handles, allowing direct calls to the underlying + * pointer. The checked handle will throw a Stale if an attempt + * is made to access the object referenced by the handle and that object has * been destroyed. **/ -template +template class LLCheckedHandle: public LLCheckedHandleBase { public: @@ -269,7 +269,7 @@ public: } /** - * Converts the LLCheckedHandle to a bool. Allows for if (chkdHandle) {} + * Converts the LLCheckedHandle to a bool. Allows for if (chkdHandle) {} * Does not throw. */ /*explicit*/ operator bool() const // explicit conversion operator not available with Linux compiler @@ -278,8 +278,8 @@ public: } /** - * Attempt to call a method or access a member in the structure referenced - * by the handle. If the handle no longer points to a valid structure + * Attempt to call a method or access a member in the structure referenced + * by the handle. If the handle no longer points to a valid structure * throw a Stale. */ T* operator ->() const diff --git a/indra/llcommon/llhash.h b/indra/llcommon/llhash.h index 4b58e81565..aa1fa2d336 100644 --- a/indra/llcommon/llhash.h +++ b/indra/llcommon/llhash.h @@ -1,25 +1,25 @@ -/** +/** * @file llhash.h * @brief Wrapper for a hash function. * * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -36,17 +36,17 @@ inline size_t llhash( const char * value ) { - // boost::hash is defined for std::string and for char, but there's no - // special overload for const char*. The lazy approach would be to - // instantiate a std::string and take its hash, but that might be more - // overhead than our callers want. Or we could use boost::hash_range() -- - // but that would require a preliminary pass over the value to determine - // the end iterator. Instead, use boost::hash_combine() to hash individual - // characters. - std::size_t seed = 0; - for ( ; *value; ++value) - boost::hash_combine(seed, *value); - return seed; + // boost::hash is defined for std::string and for char, but there's no + // special overload for const char*. The lazy approach would be to + // instantiate a std::string and take its hash, but that might be more + // overhead than our callers want. Or we could use boost::hash_range() -- + // but that would require a preliminary pass over the value to determine + // the end iterator. Instead, use boost::hash_combine() to hash individual + // characters. + std::size_t seed = 0; + for ( ; *value; ++value) + boost::hash_combine(seed, *value); + return seed; } #endif diff --git a/indra/llcommon/llheartbeat.cpp b/indra/llcommon/llheartbeat.cpp index 19b7452748..96480050a5 100644 --- a/indra/llcommon/llheartbeat.cpp +++ b/indra/llcommon/llheartbeat.cpp @@ -5,21 +5,21 @@ * $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$ */ @@ -33,28 +33,28 @@ #include "llheartbeat.h" LLHeartbeat::LLHeartbeat(F32 secs_between_heartbeat, - F32 aggressive_heartbeat_panic_secs, - F32 aggressive_heartbeat_max_blocking_secs) - : mSecsBetweenHeartbeat(secs_between_heartbeat), - mAggressiveHeartbeatPanicSecs(aggressive_heartbeat_panic_secs), - mAggressiveHeartbeatMaxBlockingSecs(aggressive_heartbeat_max_blocking_secs), - mSuppressed(false) + F32 aggressive_heartbeat_panic_secs, + F32 aggressive_heartbeat_max_blocking_secs) + : mSecsBetweenHeartbeat(secs_between_heartbeat), + mAggressiveHeartbeatPanicSecs(aggressive_heartbeat_panic_secs), + mAggressiveHeartbeatMaxBlockingSecs(aggressive_heartbeat_max_blocking_secs), + mSuppressed(false) { - mBeatTimer.reset(); - mBeatTimer.setTimerExpirySec(mSecsBetweenHeartbeat); - mPanicTimer.reset(); - mPanicTimer.setTimerExpirySec(mAggressiveHeartbeatPanicSecs); + mBeatTimer.reset(); + mBeatTimer.setTimerExpirySec(mSecsBetweenHeartbeat); + mPanicTimer.reset(); + mPanicTimer.setTimerExpirySec(mAggressiveHeartbeatPanicSecs); } LLHeartbeat::~LLHeartbeat() { - // do nothing. + // do nothing. } void LLHeartbeat::setSuppressed(bool is_suppressed) { - mSuppressed = is_suppressed; + mSuppressed = is_suppressed; } // returns 0 on success, -1 on permanent failure, 1 on temporary failure @@ -62,104 +62,104 @@ int LLHeartbeat::rawSend() { #if LL_WINDOWS - return 0; // Pretend we succeeded. + return 0; // Pretend we succeeded. #else - if (mSuppressed) - return 0; // Pretend we succeeded. + if (mSuppressed) + return 0; // Pretend we succeeded. - int result; + int result; #ifndef LL_DARWIN - union sigval dummy; - result = sigqueue(getppid(), LL_HEARTBEAT_SIGNAL, dummy); + union sigval dummy; + result = sigqueue(getppid(), LL_HEARTBEAT_SIGNAL, dummy); #else - result = kill(getppid(), LL_HEARTBEAT_SIGNAL); + result = kill(getppid(), LL_HEARTBEAT_SIGNAL); #endif - if (result == 0) - return 0; // success + if (result == 0) + return 0; // success - int err = errno; - if (err == EAGAIN) - return 1; // failed to queue, try again + int err = errno; + if (err == EAGAIN) + return 1; // failed to queue, try again - return -1; // other failure. + return -1; // other failure. #endif } int LLHeartbeat::rawSendWithTimeout(F32 timeout_sec) { - int result = 0; - - // Spin tightly until our heartbeat is digested by the watchdog - // or we time-out. We don't really want to sleep because our - // wake-up time might be undesirably synchronised to a hidden - // clock by the system's scheduler. - mTimeoutTimer.reset(); - mTimeoutTimer.setTimerExpirySec(timeout_sec); - do { - result = rawSend(); - //LL_INFOS() << " HEARTSENDc=" << result << LL_ENDL; - } while (result==1 && !mTimeoutTimer.hasExpired()); - - return result; + int result = 0; + + // Spin tightly until our heartbeat is digested by the watchdog + // or we time-out. We don't really want to sleep because our + // wake-up time might be undesirably synchronised to a hidden + // clock by the system's scheduler. + mTimeoutTimer.reset(); + mTimeoutTimer.setTimerExpirySec(timeout_sec); + do { + result = rawSend(); + //LL_INFOS() << " HEARTSENDc=" << result << LL_ENDL; + } while (result==1 && !mTimeoutTimer.hasExpired()); + + return result; } bool LLHeartbeat::send(F32 timeout_sec) { - bool total_success = false; - int result = 1; - - if (timeout_sec > 0.f) { - // force a spin until success or timeout - result = rawSendWithTimeout(timeout_sec); - } else { - if (mBeatTimer.hasExpired()) { - // zero-timeout; we don't care too much whether our - // heartbeat was digested. - result = rawSend(); - //LL_INFOS() << " HEARTSENDb=" << result << LL_ENDL; - } - } - - if (result == -1) { - // big failure. - } else if (result == 0) { - total_success = true; - } else { - // need to retry at some point - } - - if (total_success) { - mBeatTimer.reset(); - mBeatTimer.setTimerExpirySec(mSecsBetweenHeartbeat); - // reset the time until we start panicking about lost - // heartbeats again. - mPanicTimer.reset(); - mPanicTimer.setTimerExpirySec(mAggressiveHeartbeatPanicSecs); - } else { - // leave mBeatTimer as expired so we'll lazily poke the - // watchdog again next time through. - } - - if (mPanicTimer.hasExpired()) { - // It's been ages since we successfully had a heartbeat - // digested by the watchdog. Sit here and spin a while - // in the hope that we can force it through. - LL_WARNS() << "Unable to deliver heartbeat to launcher for " << mPanicTimer.getElapsedTimeF32() << " seconds. Going to try very hard for up to " << mAggressiveHeartbeatMaxBlockingSecs << " seconds." << LL_ENDL; - result = rawSendWithTimeout(mAggressiveHeartbeatMaxBlockingSecs); - if (result == 0) { - total_success = true; - } else { - // we couldn't even force it through. That's bad, - // but we'll try again in a while. - LL_WARNS() << "Could not deliver heartbeat to launcher even after trying very hard for " << mAggressiveHeartbeatMaxBlockingSecs << " seconds." << LL_ENDL; - } - - // in any case, reset the panic timer. - mPanicTimer.reset(); - mPanicTimer.setTimerExpirySec(mAggressiveHeartbeatPanicSecs); - } - - return total_success; + bool total_success = false; + int result = 1; + + if (timeout_sec > 0.f) { + // force a spin until success or timeout + result = rawSendWithTimeout(timeout_sec); + } else { + if (mBeatTimer.hasExpired()) { + // zero-timeout; we don't care too much whether our + // heartbeat was digested. + result = rawSend(); + //LL_INFOS() << " HEARTSENDb=" << result << LL_ENDL; + } + } + + if (result == -1) { + // big failure. + } else if (result == 0) { + total_success = true; + } else { + // need to retry at some point + } + + if (total_success) { + mBeatTimer.reset(); + mBeatTimer.setTimerExpirySec(mSecsBetweenHeartbeat); + // reset the time until we start panicking about lost + // heartbeats again. + mPanicTimer.reset(); + mPanicTimer.setTimerExpirySec(mAggressiveHeartbeatPanicSecs); + } else { + // leave mBeatTimer as expired so we'll lazily poke the + // watchdog again next time through. + } + + if (mPanicTimer.hasExpired()) { + // It's been ages since we successfully had a heartbeat + // digested by the watchdog. Sit here and spin a while + // in the hope that we can force it through. + LL_WARNS() << "Unable to deliver heartbeat to launcher for " << mPanicTimer.getElapsedTimeF32() << " seconds. Going to try very hard for up to " << mAggressiveHeartbeatMaxBlockingSecs << " seconds." << LL_ENDL; + result = rawSendWithTimeout(mAggressiveHeartbeatMaxBlockingSecs); + if (result == 0) { + total_success = true; + } else { + // we couldn't even force it through. That's bad, + // but we'll try again in a while. + LL_WARNS() << "Could not deliver heartbeat to launcher even after trying very hard for " << mAggressiveHeartbeatMaxBlockingSecs << " seconds." << LL_ENDL; + } + + // in any case, reset the panic timer. + mPanicTimer.reset(); + mPanicTimer.setTimerExpirySec(mAggressiveHeartbeatPanicSecs); + } + + return total_success; } diff --git a/indra/llcommon/llheartbeat.h b/indra/llcommon/llheartbeat.h index 4a75fcc103..54feeb4c92 100644 --- a/indra/llcommon/llheartbeat.h +++ b/indra/llcommon/llheartbeat.h @@ -1,25 +1,25 @@ -/** +/** * @file llheartbeat.h * @brief Class encapsulating logic for telling a watchdog that we live. * * $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$ */ @@ -37,32 +37,32 @@ class LL_COMMON_API LLHeartbeat { public: - // secs_between_heartbeat: after a heartbeat is successfully delivered, - // we suppress sending more for this length of time. - // aggressive_heartbeat_panic_secs: if we've been failing to - // successfully deliver heartbeats for this length of time then - // we block for a while until we're really sure we got one delivered. - // aggressive_heartbeat_max_blocking_secs: this is the length of - // time we block for when we're aggressively ensuring that a 'panic' - // heartbeat was delivered. - LLHeartbeat(F32 secs_between_heartbeat = 5.0f, - F32 aggressive_heartbeat_panic_secs = 10.0f, - F32 aggressive_heartbeat_max_blocking_secs = 4.0f); - ~LLHeartbeat(); + // secs_between_heartbeat: after a heartbeat is successfully delivered, + // we suppress sending more for this length of time. + // aggressive_heartbeat_panic_secs: if we've been failing to + // successfully deliver heartbeats for this length of time then + // we block for a while until we're really sure we got one delivered. + // aggressive_heartbeat_max_blocking_secs: this is the length of + // time we block for when we're aggressively ensuring that a 'panic' + // heartbeat was delivered. + LLHeartbeat(F32 secs_between_heartbeat = 5.0f, + F32 aggressive_heartbeat_panic_secs = 10.0f, + F32 aggressive_heartbeat_max_blocking_secs = 4.0f); + ~LLHeartbeat(); - bool send(F32 timeout_sec = 0.0f); - void setSuppressed(bool is_suppressed); + bool send(F32 timeout_sec = 0.0f); + void setSuppressed(bool is_suppressed); private: - int rawSend(); - int rawSendWithTimeout(F32 timeout_sec); - F32 mSecsBetweenHeartbeat; - F32 mAggressiveHeartbeatPanicSecs; - F32 mAggressiveHeartbeatMaxBlockingSecs; - bool mSuppressed; - LLTimer mBeatTimer; - LLTimer mPanicTimer; - LLTimer mTimeoutTimer; + int rawSend(); + int rawSendWithTimeout(F32 timeout_sec); + F32 mSecsBetweenHeartbeat; + F32 mAggressiveHeartbeatPanicSecs; + F32 mAggressiveHeartbeatMaxBlockingSecs; + bool mSuppressed; + LLTimer mBeatTimer; + LLTimer mPanicTimer; + LLTimer mTimeoutTimer; }; #endif // LL_HEARTBEAT_H diff --git a/indra/llcommon/llheteromap.cpp b/indra/llcommon/llheteromap.cpp index c84e49d085..823bea7a3c 100644 --- a/indra/llcommon/llheteromap.cpp +++ b/indra/llcommon/llheteromap.cpp @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2016-10-12 * @brief Implementation for llheteromap. - * + * * $LicenseInfo:firstyear=2016&license=viewerlgpl$ * Copyright (c) 2016, Linden Research, Inc. * $/LicenseInfo$ @@ -22,7 +22,7 @@ LLHeteroMap::~LLHeteroMap() { // For each entry in our map, we must call its deleter, which is the only // record we have of its original type. - for (TypeMap::value_type& pair : mMap) + for (TypeMap::value_type& pair : mMap) { // pair.second is the std::pair; pair.second.first is the void*; // pair.second.second points to the deleter function diff --git a/indra/llcommon/llheteromap.h b/indra/llcommon/llheteromap.h index 7e96172333..d8e6fefb17 100644 --- a/indra/llcommon/llheteromap.h +++ b/indra/llcommon/llheteromap.h @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2016-10-12 * @brief Map capable of storing objects of diverse types, looked up by type. - * + * * $LicenseInfo:firstyear=2016&license=viewerlgpl$ * Copyright (c) 2016, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/llindexedvector.h b/indra/llcommon/llindexedvector.h index 68c3821802..de3ae0dcc4 100644 --- a/indra/llcommon/llindexedvector.h +++ b/indra/llcommon/llindexedvector.h @@ -1,25 +1,25 @@ -/** +/** * @file lldarray.h * @brief Wrapped std::vector for backward compatibility. * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -36,65 +36,65 @@ // LLIndexedVector //-------------------------------------------------------- -template +template class LLIndexedVector { public: - typedef typename std::vector::iterator iterator; - typedef typename std::vector::const_iterator const_iterator; - typedef typename std::vector::reverse_iterator reverse_iterator; - typedef typename std::vector::const_reverse_iterator const_reverse_iterator; - typedef typename std::vector::size_type size_type; + typedef typename std::vector::iterator iterator; + typedef typename std::vector::const_iterator const_iterator; + typedef typename std::vector::reverse_iterator reverse_iterator; + typedef typename std::vector::const_reverse_iterator const_reverse_iterator; + typedef typename std::vector::size_type size_type; protected: - std::vector mVector; - std::map mIndexMap; - + std::vector mVector; + std::map mIndexMap; + public: - LLIndexedVector() { mVector.reserve(BlockSize); } - - iterator begin() { return mVector.begin(); } - const_iterator begin() const { return mVector.begin(); } - iterator end() { return mVector.end(); } - const_iterator end() const { return mVector.end(); } + LLIndexedVector() { mVector.reserve(BlockSize); } + + iterator begin() { return mVector.begin(); } + const_iterator begin() const { return mVector.begin(); } + iterator end() { return mVector.end(); } + const_iterator end() const { return mVector.end(); } + + reverse_iterator rbegin() { return mVector.rbegin(); } + const_reverse_iterator rbegin() const { return mVector.rbegin(); } + reverse_iterator rend() { return mVector.rend(); } + const_reverse_iterator rend() const { return mVector.rend(); } - reverse_iterator rbegin() { return mVector.rbegin(); } - const_reverse_iterator rbegin() const { return mVector.rbegin(); } - reverse_iterator rend() { return mVector.rend(); } - const_reverse_iterator rend() const { return mVector.rend(); } + void reset() { mVector.resize(0); mIndexMap.resize(0); } + bool empty() const { return mVector.empty(); } + size_type size() const { return mVector.size(); } - void reset() { mVector.resize(0); mIndexMap.resize(0); } - bool empty() const { return mVector.empty(); } - size_type size() const { return mVector.size(); } - - Type& operator[](const Key& k) - { - typename std::map::const_iterator iter = mIndexMap.find(k); - if (iter == mIndexMap.end()) - { - U32 n = mVector.size(); - mIndexMap[k] = n; - mVector.push_back(Type()); - llassert(mVector.size() == mIndexMap.size()); - return mVector[n]; - } - else - { - return mVector[iter->second]; - } - } + Type& operator[](const Key& k) + { + typename std::map::const_iterator iter = mIndexMap.find(k); + if (iter == mIndexMap.end()) + { + U32 n = mVector.size(); + mIndexMap[k] = n; + mVector.push_back(Type()); + llassert(mVector.size() == mIndexMap.size()); + return mVector[n]; + } + else + { + return mVector[iter->second]; + } + } - const_iterator find(const Key& k) const - { - typename std::map::const_iterator iter = mIndexMap.find(k); - if(iter == mIndexMap.end()) - { - return mVector.end(); - } - else - { - return mVector.begin() + iter->second; - } - } + const_iterator find(const Key& k) const + { + typename std::map::const_iterator iter = mIndexMap.find(k); + if(iter == mIndexMap.end()) + { + return mVector.end(); + } + else + { + return mVector.begin() + iter->second; + } + } }; #endif diff --git a/indra/llcommon/llinitdestroyclass.cpp b/indra/llcommon/llinitdestroyclass.cpp index e3b9e6d099..50e6e24b8d 100644 --- a/indra/llcommon/llinitdestroyclass.cpp +++ b/indra/llcommon/llinitdestroyclass.cpp @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2016-08-30 * @brief Implementation for llinitdestroyclass. - * + * * $LicenseInfo:firstyear=2016&license=viewerlgpl$ * Copyright (c) 2016, Linden Research, Inc. * $/LicenseInfo$ @@ -21,9 +21,9 @@ void LLCallbackRegistry::fireCallbacks() const { - for (FuncList::value_type pair : mCallbacks) - { - LL_INFOS("LLInitDestroyClass") << "calling " << pair.first << "()" << LL_ENDL; - pair.second(); - } + for (FuncList::value_type pair : mCallbacks) + { + LL_INFOS("LLInitDestroyClass") << "calling " << pair.first << "()" << LL_ENDL; + pair.second(); + } } diff --git a/indra/llcommon/llinitdestroyclass.h b/indra/llcommon/llinitdestroyclass.h index 5f979614fe..2354c9f2ed 100644 --- a/indra/llcommon/llinitdestroyclass.h +++ b/indra/llcommon/llinitdestroyclass.h @@ -50,21 +50,21 @@ class LLCallbackRegistry { public: - typedef boost::function func_t; + typedef boost::function func_t; - void registerCallback(const std::string& name, const func_t& func) - { - mCallbacks.push_back(FuncList::value_type(name, func)); - } + void registerCallback(const std::string& name, const func_t& func) + { + mCallbacks.push_back(FuncList::value_type(name, func)); + } - void fireCallbacks() const; + void fireCallbacks() const; private: - // Arguably this should be a boost::signals2::signal, which is, after all, - // a sequence of callables. We manage it by hand so we can log a name for - // each registered function we call. - typedef std::vector< std::pair > FuncList; - FuncList mCallbacks; + // Arguably this should be a boost::signals2::signal, which is, after all, + // a sequence of callables. We manage it by hand so we can log a name for + // each registered function we call. + typedef std::vector< std::pair > FuncList; + FuncList mCallbacks; }; /** @@ -74,11 +74,11 @@ private: * (before main()), requiring LLInitClassList to be fully constructed on * demand regardless of module initialization order. */ -class LLInitClassList : - public LLCallbackRegistry, - public LLSingleton +class LLInitClassList : + public LLCallbackRegistry, + public LLSingleton { - LLSINGLETON_EMPTY_CTOR(LLInitClassList); + LLSINGLETON_EMPTY_CTOR(LLInitClassList); }; /** @@ -88,11 +88,11 @@ class LLInitClassList : * time (before main()), requiring LLDestroyClassList to be fully constructed * on demand regardless of module initialization order. */ -class LLDestroyClassList : - public LLCallbackRegistry, - public LLSingleton +class LLDestroyClassList : + public LLCallbackRegistry, + public LLSingleton { - LLSINGLETON_EMPTY_CTOR(LLDestroyClassList); + LLSINGLETON_EMPTY_CTOR(LLDestroyClassList); }; /** @@ -105,19 +105,19 @@ template class LLRegisterWith { public: - LLRegisterWith(const std::string& name, const LLCallbackRegistry::func_t& func) - { - T::instance().registerCallback(name, func); - } - - // this avoids a MSVC bug where non-referenced static members are "optimized" away - // even if their constructors have side effects - S32 reference() - { - S32 dummy; - dummy = 0; - return dummy; - } + LLRegisterWith(const std::string& name, const LLCallbackRegistry::func_t& func) + { + T::instance().registerCallback(name, func); + } + + // this avoids a MSVC bug where non-referenced static members are "optimized" away + // even if their constructors have side effects + S32 reference() + { + S32 dummy; + dummy = 0; + return dummy; + } }; /** @@ -133,11 +133,11 @@ template class LLInitClass { public: - LLInitClass() { sRegister.reference(); } + LLInitClass() { sRegister.reference(); } - // When this static member is initialized, the subclass initClass() method - // is registered on LLInitClassList. See sRegister definition below. - static LLRegisterWith sRegister; + // When this static member is initialized, the subclass initClass() method + // is registered on LLInitClassList. See sRegister definition below. + static LLRegisterWith sRegister; }; /** @@ -153,23 +153,23 @@ template class LLDestroyClass { public: - LLDestroyClass() { sRegister.reference(); } + LLDestroyClass() { sRegister.reference(); } - // When this static member is initialized, the subclass destroyClass() - // method is registered on LLInitClassList. See sRegister definition - // below. - static LLRegisterWith sRegister; + // When this static member is initialized, the subclass destroyClass() + // method is registered on LLInitClassList. See sRegister definition + // below. + static LLRegisterWith sRegister; }; // Here's where LLInitClass specifies the subclass initClass() method. template LLRegisterWith LLInitClass::sRegister(std::string(typeid(T).name()) + "::initClass", - &T::initClass); + &T::initClass); // Here's where LLDestroyClass specifies the subclass destroyClass() method. template LLRegisterWith LLDestroyClass::sRegister(std::string(typeid(T).name()) + "::destroyClass", - &T::destroyClass); + &T::destroyClass); #endif /* ! defined(LL_LLINITDESTROYCLASS_H) */ diff --git a/indra/llcommon/llinitparam.cpp b/indra/llcommon/llinitparam.cpp index d15bd2f619..7bba1a540d 100644 --- a/indra/llcommon/llinitparam.cpp +++ b/indra/llcommon/llinitparam.cpp @@ -1,26 +1,26 @@ -/** +/** * @file llinitparam.cpp - * @brief parameter block abstraction for creating complex objects and + * @brief parameter block abstraction for creating complex objects and * parsing construction parameters from xml and LLSD * * $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$ */ @@ -34,434 +34,434 @@ namespace LLInitParam { - predicate_rule_t default_parse_rules() - { - return ll_make_predicate(PROVIDED) && !ll_make_predicate(EMPTY); - } - - // - // Param - // - Param::Param(BaseBlock* enclosing_block) - : mIsProvided(false) - { - const U8* my_addr = reinterpret_cast(this); - const U8* block_addr = reinterpret_cast(enclosing_block); - U32 enclosing_block_offset = 0x7FFFffff & (U32)(my_addr - block_addr); - mEnclosingBlockOffsetLow = enclosing_block_offset & 0x0000ffff; - mEnclosingBlockOffsetHigh = (enclosing_block_offset & 0x007f0000) >> 16; - } - - // - // ParamDescriptor - // - ParamDescriptor::ParamDescriptor(param_handle_t p, - merge_func_t merge_func, - deserialize_func_t deserialize_func, - serialize_func_t serialize_func, - validation_func_t validation_func, - inspect_func_t inspect_func, - S32 min_count, - S32 max_count) - : mParamHandle(p), - mMergeFunc(merge_func), - mDeserializeFunc(deserialize_func), - mSerializeFunc(serialize_func), - mValidationFunc(validation_func), - mInspectFunc(inspect_func), - mMinCount(min_count), - mMaxCount(max_count), - mUserData(NULL) - {} - - ParamDescriptor::ParamDescriptor() - : mParamHandle(0), - mMergeFunc(NULL), - mDeserializeFunc(NULL), - mSerializeFunc(NULL), - mValidationFunc(NULL), - mInspectFunc(NULL), - mMinCount(0), - mMaxCount(0), - mUserData(NULL) - {} - - ParamDescriptor::~ParamDescriptor() - { - delete mUserData; - } - - // - // Parser - // - Parser::~Parser() - {} - - void Parser::parserWarning(const std::string& message) - { - if (mParseSilently) return; - LL_WARNS() << message << LL_ENDL; - } - - void Parser::parserError(const std::string& message) - { - if (mParseSilently) return; - LL_ERRS() << message << LL_ENDL; - } - - - // - // BlockDescriptor - // - void BlockDescriptor::aggregateBlockData(BlockDescriptor& src_block_data) - { - mNamedParams.insert(src_block_data.mNamedParams.begin(), src_block_data.mNamedParams.end()); - std::copy(src_block_data.mUnnamedParams.begin(), src_block_data.mUnnamedParams.end(), std::back_inserter(mUnnamedParams)); - std::copy(src_block_data.mValidationList.begin(), src_block_data.mValidationList.end(), std::back_inserter(mValidationList)); - std::copy(src_block_data.mAllParams.begin(), src_block_data.mAllParams.end(), std::back_inserter(mAllParams)); - } - - void BlockDescriptor::addParam(const ParamDescriptorPtr in_param, const char* char_name) - { - // create a copy of the param descriptor in mAllParams - // so other data structures can store a pointer to it - mAllParams.push_back(in_param); - ParamDescriptorPtr param(mAllParams.back()); - - std::string name(char_name); - if ((size_t)param->mParamHandle > mMaxParamOffset) - { - LL_ERRS() << "Attempted to register param with block defined for parent class, make sure to derive from LLInitParam::Block" << LL_ENDL; - } - - if (name.empty()) - { - mUnnamedParams.push_back(param); - } - else - { - // don't use insert, since we want to overwrite existing entries - mNamedParams[name] = param; - } - - if (param->mValidationFunc) - { - mValidationList.push_back(std::make_pair(param->mParamHandle, param->mValidationFunc)); - } - } - - BlockDescriptor::BlockDescriptor() - : mMaxParamOffset(0), - mInitializationState(UNINITIALIZED), - mCurrentBlockPtr(NULL) - {} - - // called by each derived class in least to most derived order - void BaseBlock::init(BlockDescriptor& descriptor, BlockDescriptor& base_descriptor, size_t block_size) - { - descriptor.mCurrentBlockPtr = this; - descriptor.mMaxParamOffset = block_size; - - switch(descriptor.mInitializationState) - { - case BlockDescriptor::UNINITIALIZED: - // copy params from base class here - descriptor.aggregateBlockData(base_descriptor); - - descriptor.mInitializationState = BlockDescriptor::INITIALIZING; - break; - case BlockDescriptor::INITIALIZING: - descriptor.mInitializationState = BlockDescriptor::INITIALIZED; - break; - case BlockDescriptor::INITIALIZED: - // nothing to do - break; - } - } - - param_handle_t BaseBlock::getHandleFromParam(const Param* param) const - { - const U8* param_address = reinterpret_cast(param); - const U8* baseblock_address = reinterpret_cast(this); - return (param_address - baseblock_address); - } - - bool BaseBlock::submitValue(Parser::name_stack_t& name_stack, Parser& p, bool silent) - { - Parser::name_stack_range_t range = std::make_pair(name_stack.begin(), name_stack.end()); - if (!deserializeBlock(p, range, true)) - { - if (!silent) - { - p.parserWarning(llformat("Failed to parse parameter \"%s\"", p.getCurrentElementName().c_str())); - } - return false; - } - return true; - } - - - bool BaseBlock::validateBlock(bool emit_errors) const - { - // only validate block when it hasn't already passed validation with current data - if (!mValidated) - { - const BlockDescriptor& block_data = mostDerivedBlockDescriptor(); - for (const BlockDescriptor::param_validation_list_t::value_type& pair : block_data.mValidationList) - { - const Param* param = getParamFromHandle(pair.first); - if (!pair.second(param)) - { - if (emit_errors) - { - LL_WARNS() << "Invalid param \"" << getParamName(block_data, param) << "\"" << LL_ENDL; - } - return false; - } - } - mValidated = true; - } - return mValidated; - } - - bool BaseBlock::serializeBlock(Parser& parser, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const LLInitParam::BaseBlock* diff_block) const - { - bool serialized = false; - if (!predicate_rule.check(ll_make_predicate(PROVIDED, isProvided()))) - { - return false; - } - // named param is one like LLView::Params::follows - // unnamed param is like LLView::Params::rect - implicit - const BlockDescriptor& block_data = mostDerivedBlockDescriptor(); - - for (const ParamDescriptorPtr& ptr : block_data.mUnnamedParams) - { - param_handle_t param_handle = ptr->mParamHandle; - const Param* param = getParamFromHandle(param_handle); - ParamDescriptor::serialize_func_t serialize_func = ptr->mSerializeFunc; - if (serialize_func && predicate_rule.check(ll_make_predicate(PROVIDED, param->anyProvided()))) - { - const Param* diff_param = diff_block ? diff_block->getParamFromHandle(param_handle) : NULL; - serialized |= serialize_func(*param, parser, name_stack, predicate_rule, diff_param); - } - } - - for (const BlockDescriptor::param_map_t::value_type& pair : block_data.mNamedParams) - { - param_handle_t param_handle = pair.second->mParamHandle; - const Param* param = getParamFromHandle(param_handle); - ParamDescriptor::serialize_func_t serialize_func = pair.second->mSerializeFunc; - if (serialize_func && predicate_rule.check(ll_make_predicate(PROVIDED, param->anyProvided()))) - { - // Ensure this param has not already been serialized - // Prevents from being serialized as its own tag. - bool duplicate = false; - for (const ParamDescriptorPtr& ptr : block_data.mUnnamedParams) - { - if (param_handle == ptr->mParamHandle) - { - duplicate = true; - break; - } - } - - //FIXME: for now, don't attempt to serialize values under synonyms, as current parsers - // don't know how to detect them - if (duplicate) - { - continue; - } - - name_stack.push_back(std::make_pair(pair.first, !duplicate)); - const Param* diff_param = diff_block ? diff_block->getParamFromHandle(param_handle) : NULL; - serialized |= serialize_func(*param, parser, name_stack, predicate_rule, diff_param); - name_stack.pop_back(); - } - } - - if (!serialized && predicate_rule.check(ll_make_predicate(EMPTY))) - { - serialized |= parser.writeValue(Flag(), name_stack); - } - // was anything serialized in this block? - return serialized; - } - - bool BaseBlock::inspectBlock(Parser& parser, Parser::name_stack_t name_stack, S32 min_count, S32 max_count) const - { - // named param is one like LLView::Params::follows - // unnamed param is like LLView::Params::rect - implicit - const BlockDescriptor& block_data = mostDerivedBlockDescriptor(); - - for (const ParamDescriptorPtr& ptr : block_data.mUnnamedParams) - { - param_handle_t param_handle = ptr->mParamHandle; - const Param* param = getParamFromHandle(param_handle); - ParamDescriptor::inspect_func_t inspect_func = ptr->mInspectFunc; - if (inspect_func) - { - name_stack.push_back(std::make_pair("", true)); - inspect_func(*param, parser, name_stack, ptr->mMinCount, ptr->mMaxCount); - name_stack.pop_back(); - } - } - - for(const BlockDescriptor::param_map_t::value_type& pair : block_data.mNamedParams) - { - param_handle_t param_handle = pair.second->mParamHandle; - const Param* param = getParamFromHandle(param_handle); - ParamDescriptor::inspect_func_t inspect_func = pair.second->mInspectFunc; - if (inspect_func) - { - // Ensure this param has not already been inspected - bool duplicate = false; + predicate_rule_t default_parse_rules() + { + return ll_make_predicate(PROVIDED) && !ll_make_predicate(EMPTY); + } + + // + // Param + // + Param::Param(BaseBlock* enclosing_block) + : mIsProvided(false) + { + const U8* my_addr = reinterpret_cast(this); + const U8* block_addr = reinterpret_cast(enclosing_block); + U32 enclosing_block_offset = 0x7FFFffff & (U32)(my_addr - block_addr); + mEnclosingBlockOffsetLow = enclosing_block_offset & 0x0000ffff; + mEnclosingBlockOffsetHigh = (enclosing_block_offset & 0x007f0000) >> 16; + } + + // + // ParamDescriptor + // + ParamDescriptor::ParamDescriptor(param_handle_t p, + merge_func_t merge_func, + deserialize_func_t deserialize_func, + serialize_func_t serialize_func, + validation_func_t validation_func, + inspect_func_t inspect_func, + S32 min_count, + S32 max_count) + : mParamHandle(p), + mMergeFunc(merge_func), + mDeserializeFunc(deserialize_func), + mSerializeFunc(serialize_func), + mValidationFunc(validation_func), + mInspectFunc(inspect_func), + mMinCount(min_count), + mMaxCount(max_count), + mUserData(NULL) + {} + + ParamDescriptor::ParamDescriptor() + : mParamHandle(0), + mMergeFunc(NULL), + mDeserializeFunc(NULL), + mSerializeFunc(NULL), + mValidationFunc(NULL), + mInspectFunc(NULL), + mMinCount(0), + mMaxCount(0), + mUserData(NULL) + {} + + ParamDescriptor::~ParamDescriptor() + { + delete mUserData; + } + + // + // Parser + // + Parser::~Parser() + {} + + void Parser::parserWarning(const std::string& message) + { + if (mParseSilently) return; + LL_WARNS() << message << LL_ENDL; + } + + void Parser::parserError(const std::string& message) + { + if (mParseSilently) return; + LL_ERRS() << message << LL_ENDL; + } + + + // + // BlockDescriptor + // + void BlockDescriptor::aggregateBlockData(BlockDescriptor& src_block_data) + { + mNamedParams.insert(src_block_data.mNamedParams.begin(), src_block_data.mNamedParams.end()); + std::copy(src_block_data.mUnnamedParams.begin(), src_block_data.mUnnamedParams.end(), std::back_inserter(mUnnamedParams)); + std::copy(src_block_data.mValidationList.begin(), src_block_data.mValidationList.end(), std::back_inserter(mValidationList)); + std::copy(src_block_data.mAllParams.begin(), src_block_data.mAllParams.end(), std::back_inserter(mAllParams)); + } + + void BlockDescriptor::addParam(const ParamDescriptorPtr in_param, const char* char_name) + { + // create a copy of the param descriptor in mAllParams + // so other data structures can store a pointer to it + mAllParams.push_back(in_param); + ParamDescriptorPtr param(mAllParams.back()); + + std::string name(char_name); + if ((size_t)param->mParamHandle > mMaxParamOffset) + { + LL_ERRS() << "Attempted to register param with block defined for parent class, make sure to derive from LLInitParam::Block" << LL_ENDL; + } + + if (name.empty()) + { + mUnnamedParams.push_back(param); + } + else + { + // don't use insert, since we want to overwrite existing entries + mNamedParams[name] = param; + } + + if (param->mValidationFunc) + { + mValidationList.push_back(std::make_pair(param->mParamHandle, param->mValidationFunc)); + } + } + + BlockDescriptor::BlockDescriptor() + : mMaxParamOffset(0), + mInitializationState(UNINITIALIZED), + mCurrentBlockPtr(NULL) + {} + + // called by each derived class in least to most derived order + void BaseBlock::init(BlockDescriptor& descriptor, BlockDescriptor& base_descriptor, size_t block_size) + { + descriptor.mCurrentBlockPtr = this; + descriptor.mMaxParamOffset = block_size; + + switch(descriptor.mInitializationState) + { + case BlockDescriptor::UNINITIALIZED: + // copy params from base class here + descriptor.aggregateBlockData(base_descriptor); + + descriptor.mInitializationState = BlockDescriptor::INITIALIZING; + break; + case BlockDescriptor::INITIALIZING: + descriptor.mInitializationState = BlockDescriptor::INITIALIZED; + break; + case BlockDescriptor::INITIALIZED: + // nothing to do + break; + } + } + + param_handle_t BaseBlock::getHandleFromParam(const Param* param) const + { + const U8* param_address = reinterpret_cast(param); + const U8* baseblock_address = reinterpret_cast(this); + return (param_address - baseblock_address); + } + + bool BaseBlock::submitValue(Parser::name_stack_t& name_stack, Parser& p, bool silent) + { + Parser::name_stack_range_t range = std::make_pair(name_stack.begin(), name_stack.end()); + if (!deserializeBlock(p, range, true)) + { + if (!silent) + { + p.parserWarning(llformat("Failed to parse parameter \"%s\"", p.getCurrentElementName().c_str())); + } + return false; + } + return true; + } + + + bool BaseBlock::validateBlock(bool emit_errors) const + { + // only validate block when it hasn't already passed validation with current data + if (!mValidated) + { + const BlockDescriptor& block_data = mostDerivedBlockDescriptor(); + for (const BlockDescriptor::param_validation_list_t::value_type& pair : block_data.mValidationList) + { + const Param* param = getParamFromHandle(pair.first); + if (!pair.second(param)) + { + if (emit_errors) + { + LL_WARNS() << "Invalid param \"" << getParamName(block_data, param) << "\"" << LL_ENDL; + } + return false; + } + } + mValidated = true; + } + return mValidated; + } + + bool BaseBlock::serializeBlock(Parser& parser, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const LLInitParam::BaseBlock* diff_block) const + { + bool serialized = false; + if (!predicate_rule.check(ll_make_predicate(PROVIDED, isProvided()))) + { + return false; + } + // named param is one like LLView::Params::follows + // unnamed param is like LLView::Params::rect - implicit + const BlockDescriptor& block_data = mostDerivedBlockDescriptor(); + + for (const ParamDescriptorPtr& ptr : block_data.mUnnamedParams) + { + param_handle_t param_handle = ptr->mParamHandle; + const Param* param = getParamFromHandle(param_handle); + ParamDescriptor::serialize_func_t serialize_func = ptr->mSerializeFunc; + if (serialize_func && predicate_rule.check(ll_make_predicate(PROVIDED, param->anyProvided()))) + { + const Param* diff_param = diff_block ? diff_block->getParamFromHandle(param_handle) : NULL; + serialized |= serialize_func(*param, parser, name_stack, predicate_rule, diff_param); + } + } + + for (const BlockDescriptor::param_map_t::value_type& pair : block_data.mNamedParams) + { + param_handle_t param_handle = pair.second->mParamHandle; + const Param* param = getParamFromHandle(param_handle); + ParamDescriptor::serialize_func_t serialize_func = pair.second->mSerializeFunc; + if (serialize_func && predicate_rule.check(ll_make_predicate(PROVIDED, param->anyProvided()))) + { + // Ensure this param has not already been serialized + // Prevents from being serialized as its own tag. + bool duplicate = false; + for (const ParamDescriptorPtr& ptr : block_data.mUnnamedParams) + { + if (param_handle == ptr->mParamHandle) + { + duplicate = true; + break; + } + } + + //FIXME: for now, don't attempt to serialize values under synonyms, as current parsers + // don't know how to detect them + if (duplicate) + { + continue; + } + + name_stack.push_back(std::make_pair(pair.first, !duplicate)); + const Param* diff_param = diff_block ? diff_block->getParamFromHandle(param_handle) : NULL; + serialized |= serialize_func(*param, parser, name_stack, predicate_rule, diff_param); + name_stack.pop_back(); + } + } + + if (!serialized && predicate_rule.check(ll_make_predicate(EMPTY))) + { + serialized |= parser.writeValue(Flag(), name_stack); + } + // was anything serialized in this block? + return serialized; + } + + bool BaseBlock::inspectBlock(Parser& parser, Parser::name_stack_t name_stack, S32 min_count, S32 max_count) const + { + // named param is one like LLView::Params::follows + // unnamed param is like LLView::Params::rect - implicit + const BlockDescriptor& block_data = mostDerivedBlockDescriptor(); + + for (const ParamDescriptorPtr& ptr : block_data.mUnnamedParams) + { + param_handle_t param_handle = ptr->mParamHandle; + const Param* param = getParamFromHandle(param_handle); + ParamDescriptor::inspect_func_t inspect_func = ptr->mInspectFunc; + if (inspect_func) + { + name_stack.push_back(std::make_pair("", true)); + inspect_func(*param, parser, name_stack, ptr->mMinCount, ptr->mMaxCount); + name_stack.pop_back(); + } + } + + for(const BlockDescriptor::param_map_t::value_type& pair : block_data.mNamedParams) + { + param_handle_t param_handle = pair.second->mParamHandle; + const Param* param = getParamFromHandle(param_handle); + ParamDescriptor::inspect_func_t inspect_func = pair.second->mInspectFunc; + if (inspect_func) + { + // Ensure this param has not already been inspected + bool duplicate = false; for (const ParamDescriptorPtr &ptr : block_data.mUnnamedParams) - { - if (param_handle == ptr->mParamHandle) - { - duplicate = true; - break; - } - } - - name_stack.push_back(std::make_pair(pair.first, !duplicate)); - inspect_func(*param, parser, name_stack, pair.second->mMinCount, pair.second->mMaxCount); - name_stack.pop_back(); - } - } - - return true; - } - - bool BaseBlock::deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack_range, bool ignored) - { - BlockDescriptor& block_data = mostDerivedBlockDescriptor(); - bool names_left = name_stack_range.first != name_stack_range.second; - - bool new_name = names_left - ? name_stack_range.first->second - : true; - - if (names_left) - { - const std::string& top_name = name_stack_range.first->first; - - BlockDescriptor::param_map_t::iterator found_it = block_data.mNamedParams.find(top_name); - if (found_it != block_data.mNamedParams.end()) - { - // find pointer to member parameter from offset table - Param* paramp = getParamFromHandle(found_it->second->mParamHandle); - ParamDescriptor::deserialize_func_t deserialize_func = found_it->second->mDeserializeFunc; - - Parser::name_stack_range_t new_name_stack(name_stack_range.first, name_stack_range.second); - ++new_name_stack.first; - if (deserialize_func(*paramp, p, new_name_stack, new_name)) - { - // value is no longer new, we know about it now - name_stack_range.first->second = false; - return true; - } - else - { - return false; - } - } - } - - // try to parse unnamed parameters, in declaration order - for (ParamDescriptorPtr& ptr : block_data.mUnnamedParams) - { - Param* paramp = getParamFromHandle(ptr->mParamHandle); - ParamDescriptor::deserialize_func_t deserialize_func = ptr->mDeserializeFunc; - - if (deserialize_func && deserialize_func(*paramp, p, name_stack_range, new_name)) - { - return true; - } - } - - // if no match, and no names left on stack, this is just an existence assertion of this block - // verify by calling readValue with NoParamValue type, an inherently unparseable type - if (!names_left) - { - Flag no_value; - return p.readValue(no_value); - } - - return false; - } - - void BaseBlock::addSynonym(Param& param, const std::string& synonym) - { - BlockDescriptor& block_data = mostDerivedBlockDescriptor(); - if (block_data.mInitializationState == BlockDescriptor::INITIALIZING) - { - param_handle_t handle = getHandleFromParam(¶m); - - // check for invalid derivation from a paramblock (i.e. without using - // Block - if ((size_t)handle > block_data.mMaxParamOffset) - { - LL_ERRS() << "Attempted to register param with block defined for parent class, make sure to derive from LLInitParam::Block" << LL_ENDL; - } - - ParamDescriptorPtr param_descriptor = findParamDescriptor(param); - if (param_descriptor) - { - if (synonym.empty()) - { - block_data.mUnnamedParams.push_back(param_descriptor); - } - else - { - block_data.mNamedParams[synonym] = param_descriptor; - } - } - } - } - - const std::string& BaseBlock::getParamName(const BlockDescriptor& block_data, const Param* paramp) const - { - param_handle_t handle = getHandleFromParam(paramp); - for (BlockDescriptor::param_map_t::const_iterator it = block_data.mNamedParams.begin(); it != block_data.mNamedParams.end(); ++it) - { - if (it->second->mParamHandle == handle) - { - return it->first; - } - } - - return LLStringUtil::null; - } - - ParamDescriptorPtr BaseBlock::findParamDescriptor(const Param& param) - { - param_handle_t handle = getHandleFromParam(¶m); - BlockDescriptor& descriptor = mostDerivedBlockDescriptor(); - for (ParamDescriptorPtr& ptr : descriptor.mAllParams) - { - if (ptr->mParamHandle == handle) return ptr; - } - return ParamDescriptorPtr(); - } - - // take all provided params from other and apply to self - // NOTE: this requires that "other" is of the same derived type as this - bool BaseBlock::mergeBlock(BlockDescriptor& block_data, const BaseBlock& other, bool overwrite) - { - bool some_param_changed = false; - for (const ParamDescriptorPtr& ptr : block_data.mAllParams) - { - const Param* other_paramp = other.getParamFromHandle(ptr->mParamHandle); - ParamDescriptor::merge_func_t merge_func = ptr->mMergeFunc; - if (merge_func) - { - Param* paramp = getParamFromHandle(ptr->mParamHandle); - llassert(paramp->getEnclosingBlockOffset() == ptr->mParamHandle); - some_param_changed |= merge_func(*paramp, *other_paramp, overwrite); - } - } - return some_param_changed; - } + { + if (param_handle == ptr->mParamHandle) + { + duplicate = true; + break; + } + } + + name_stack.push_back(std::make_pair(pair.first, !duplicate)); + inspect_func(*param, parser, name_stack, pair.second->mMinCount, pair.second->mMaxCount); + name_stack.pop_back(); + } + } + + return true; + } + + bool BaseBlock::deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack_range, bool ignored) + { + BlockDescriptor& block_data = mostDerivedBlockDescriptor(); + bool names_left = name_stack_range.first != name_stack_range.second; + + bool new_name = names_left + ? name_stack_range.first->second + : true; + + if (names_left) + { + const std::string& top_name = name_stack_range.first->first; + + BlockDescriptor::param_map_t::iterator found_it = block_data.mNamedParams.find(top_name); + if (found_it != block_data.mNamedParams.end()) + { + // find pointer to member parameter from offset table + Param* paramp = getParamFromHandle(found_it->second->mParamHandle); + ParamDescriptor::deserialize_func_t deserialize_func = found_it->second->mDeserializeFunc; + + Parser::name_stack_range_t new_name_stack(name_stack_range.first, name_stack_range.second); + ++new_name_stack.first; + if (deserialize_func(*paramp, p, new_name_stack, new_name)) + { + // value is no longer new, we know about it now + name_stack_range.first->second = false; + return true; + } + else + { + return false; + } + } + } + + // try to parse unnamed parameters, in declaration order + for (ParamDescriptorPtr& ptr : block_data.mUnnamedParams) + { + Param* paramp = getParamFromHandle(ptr->mParamHandle); + ParamDescriptor::deserialize_func_t deserialize_func = ptr->mDeserializeFunc; + + if (deserialize_func && deserialize_func(*paramp, p, name_stack_range, new_name)) + { + return true; + } + } + + // if no match, and no names left on stack, this is just an existence assertion of this block + // verify by calling readValue with NoParamValue type, an inherently unparseable type + if (!names_left) + { + Flag no_value; + return p.readValue(no_value); + } + + return false; + } + + void BaseBlock::addSynonym(Param& param, const std::string& synonym) + { + BlockDescriptor& block_data = mostDerivedBlockDescriptor(); + if (block_data.mInitializationState == BlockDescriptor::INITIALIZING) + { + param_handle_t handle = getHandleFromParam(¶m); + + // check for invalid derivation from a paramblock (i.e. without using + // Block + if ((size_t)handle > block_data.mMaxParamOffset) + { + LL_ERRS() << "Attempted to register param with block defined for parent class, make sure to derive from LLInitParam::Block" << LL_ENDL; + } + + ParamDescriptorPtr param_descriptor = findParamDescriptor(param); + if (param_descriptor) + { + if (synonym.empty()) + { + block_data.mUnnamedParams.push_back(param_descriptor); + } + else + { + block_data.mNamedParams[synonym] = param_descriptor; + } + } + } + } + + const std::string& BaseBlock::getParamName(const BlockDescriptor& block_data, const Param* paramp) const + { + param_handle_t handle = getHandleFromParam(paramp); + for (BlockDescriptor::param_map_t::const_iterator it = block_data.mNamedParams.begin(); it != block_data.mNamedParams.end(); ++it) + { + if (it->second->mParamHandle == handle) + { + return it->first; + } + } + + return LLStringUtil::null; + } + + ParamDescriptorPtr BaseBlock::findParamDescriptor(const Param& param) + { + param_handle_t handle = getHandleFromParam(¶m); + BlockDescriptor& descriptor = mostDerivedBlockDescriptor(); + for (ParamDescriptorPtr& ptr : descriptor.mAllParams) + { + if (ptr->mParamHandle == handle) return ptr; + } + return ParamDescriptorPtr(); + } + + // take all provided params from other and apply to self + // NOTE: this requires that "other" is of the same derived type as this + bool BaseBlock::mergeBlock(BlockDescriptor& block_data, const BaseBlock& other, bool overwrite) + { + bool some_param_changed = false; + for (const ParamDescriptorPtr& ptr : block_data.mAllParams) + { + const Param* other_paramp = other.getParamFromHandle(ptr->mParamHandle); + ParamDescriptor::merge_func_t merge_func = ptr->mMergeFunc; + if (merge_func) + { + Param* paramp = getParamFromHandle(ptr->mParamHandle); + llassert(paramp->getEnclosingBlockOffset() == ptr->mParamHandle); + some_param_changed |= merge_func(*paramp, *other_paramp, overwrite); + } + } + return some_param_changed; + } } diff --git a/indra/llcommon/llinitparam.h b/indra/llcommon/llinitparam.h index e0d0ab9ac7..206aa51ba3 100644 --- a/indra/llcommon/llinitparam.h +++ b/indra/llcommon/llinitparam.h @@ -1,26 +1,26 @@ -/** +/** * @file llinitparam.h - * @brief parameter block abstraction for creating complex objects and + * @brief parameter block abstraction for creating complex objects and * parsing construction parameters from xml and LLSD * * $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$ */ @@ -43,2796 +43,2796 @@ namespace LLTypeTags { - template - struct TypeTagBase - { - typedef void is_tag_t; - typedef INNER_TYPE inner_t; - static const int SORT_ORDER=_SORT_ORDER; - }; - - template - struct GreaterThan - { - static const bool value = VAL1 > VAL2; - }; - - template::value > - struct Swap - { - typedef typename ITEM::template Cons::value_t value_t; - }; - - template - struct Swap - { - typedef typename REST::template Cons::value_t>::value_t value_t; - }; - - template - struct IsSortable - { - static const bool value = false; - }; - - template - struct IsSortable - { - static const bool value = true; - }; - - template::value> - struct InsertInto - { - typedef typename ITEM::template Cons::value_t value_t; - }; - - template - struct InsertInto - { - typedef typename Swap::value_t value_t; - }; - - template::value> - struct Sorted - { - typedef T value_t; - }; - - template - struct Sorted - { - typedef typename InsertInto::value_t>::value_t value_t; - }; + template + struct TypeTagBase + { + typedef void is_tag_t; + typedef INNER_TYPE inner_t; + static const int SORT_ORDER=_SORT_ORDER; + }; + + template + struct GreaterThan + { + static const bool value = VAL1 > VAL2; + }; + + template::value > + struct Swap + { + typedef typename ITEM::template Cons::value_t value_t; + }; + + template + struct Swap + { + typedef typename REST::template Cons::value_t>::value_t value_t; + }; + + template + struct IsSortable + { + static const bool value = false; + }; + + template + struct IsSortable + { + static const bool value = true; + }; + + template::value> + struct InsertInto + { + typedef typename ITEM::template Cons::value_t value_t; + }; + + template + struct InsertInto + { + typedef typename Swap::value_t value_t; + }; + + template::value> + struct Sorted + { + typedef T value_t; + }; + + template + struct Sorted + { + typedef typename InsertInto::value_t>::value_t value_t; + }; } namespace LLInitParam { - // used to indicate no matching value to a given name when parsing - struct Flag{}; - - template const T& defaultValue() { static T value; return value; } - - // wraps comparison operator between any 2 values of the same type - // specialize to handle cases where equality isn't defined well, or at all - template ::value > - struct ParamCompare - { - static bool equals(const T &a, const T &b) - { - return a == b; - } + // used to indicate no matching value to a given name when parsing + struct Flag{}; + + template const T& defaultValue() { static T value; return value; } + + // wraps comparison operator between any 2 values of the same type + // specialize to handle cases where equality isn't defined well, or at all + template ::value > + struct ParamCompare + { + static bool equals(const T &a, const T &b) + { + return a == b; + } + }; + + // boost function types are not comparable + template + struct ParamCompare + { + static bool equals(const T&a, const T &b) + { + return false; + } + }; + + template<> + struct ParamCompare + { + static bool equals(const LLSD &a, const LLSD &b) { return false; } + }; + + template<> + struct ParamCompare + { + static bool equals(const Flag& a, const Flag& b) { return false; } + }; + + + // helper functions and classes + typedef ptrdiff_t param_handle_t; + struct IS_A_BLOCK {}; + struct NOT_BLOCK {}; + + // these templates allow us to distinguish between template parameters + // that derive from BaseBlock and those that don't + template + struct IsBlock + { + typedef NOT_BLOCK value_t; + }; + + template + struct IsBlock + { + typedef IS_A_BLOCK value_t; + }; + + // ParamValue class directly manages the wrapped value + // by holding on to a copy (scalar params) + // or deriving from it (blocks) + // has specializations for custom value behavior + // and "tag" values like Lazy and Atomic + template::value_t> + class ParamValue + { + typedef ParamValue self_t; + + public: + typedef T default_value_t; + typedef T value_t; + + ParamValue(): mValue() {} + ParamValue(const default_value_t& other) : mValue(other) {} + + void setValue(const value_t& val) + { + mValue = val; + } + + const value_t& getValue() const + { + return mValue; + } + + T& getValue() + { + return mValue; + } + + bool isValid() const { return true; } + + protected: + T mValue; + }; + + template + class ParamValue + : public T + { + typedef ParamValue self_t; + public: + typedef T default_value_t; + typedef T value_t; + + ParamValue() + : T() + {} + + ParamValue(const default_value_t& other) + : T(other) + {} + + void setValue(const value_t& val) + { + *this = val; + } + + const value_t& getValue() const + { + return *this; + } + + T& getValue() + { + return *this; + } }; - // boost function types are not comparable - template - struct ParamCompare - { - static bool equals(const T&a, const T &b) - { - return false; - } - }; - - template<> - struct ParamCompare - { - static bool equals(const LLSD &a, const LLSD &b) { return false; } - }; - - template<> - struct ParamCompare - { - static bool equals(const Flag& a, const Flag& b) { return false; } - }; - - - // helper functions and classes - typedef ptrdiff_t param_handle_t; - struct IS_A_BLOCK {}; - struct NOT_BLOCK {}; - - // these templates allow us to distinguish between template parameters - // that derive from BaseBlock and those that don't - template - struct IsBlock - { - typedef NOT_BLOCK value_t; - }; - - template - struct IsBlock - { - typedef IS_A_BLOCK value_t; - }; - - // ParamValue class directly manages the wrapped value - // by holding on to a copy (scalar params) - // or deriving from it (blocks) - // has specializations for custom value behavior - // and "tag" values like Lazy and Atomic - template::value_t> - class ParamValue - { - typedef ParamValue self_t; - - public: - typedef T default_value_t; - typedef T value_t; - - ParamValue(): mValue() {} - ParamValue(const default_value_t& other) : mValue(other) {} - - void setValue(const value_t& val) - { - mValue = val; - } - - const value_t& getValue() const - { - return mValue; - } - - T& getValue() - { - return mValue; - } - - bool isValid() const { return true; } - - protected: - T mValue; - }; - - template - class ParamValue - : public T - { - typedef ParamValue self_t; - public: - typedef T default_value_t; - typedef T value_t; - - ParamValue() - : T() - {} - - ParamValue(const default_value_t& other) - : T(other) - {} - - void setValue(const value_t& val) - { - *this = val; - } - - const value_t& getValue() const - { - return *this; - } - - T& getValue() - { - return *this; - } - }; - - - // empty default implementation of key cache - // leverages empty base class optimization - template - class TypeValues - : public ParamValue::value_t> - { - private: - struct Inaccessable{}; - public: - typedef std::map value_name_map_t; - typedef Inaccessable name_t; - typedef TypeValues type_value_t; - typedef ParamValue::value_t> param_value_t; - typedef typename param_value_t::value_t value_t; - - TypeValues(const typename param_value_t::value_t& val) - : param_value_t(val) - {} - - void setValueName(const std::string& key) {} - std::string getValueName() const { return ""; } - std::string calcValueName(const value_t& value) const { return ""; } - void clearValueName() const {} - - static bool getValueFromName(const std::string& name, value_t& value) - { - return false; - } - - static bool valueNamesExist() - { - return false; - } - - static std::vector* getPossibleValues() - { - return NULL; - } - - void assignNamedValue(const Inaccessable& name) - {} - - operator const value_t&() const - { - return param_value_t::getValue(); - } - - const value_t& operator()() const - { - return param_value_t::getValue(); - } - - static value_name_map_t* getValueNames() {return NULL;} - }; - - // helper class to implement name value lookups - // and caching of last used name - template , bool IS_SPECIALIZED = true > - class TypeValuesHelper - : public ParamValue::value_t> - { - typedef TypeValuesHelper self_t; - public: - typedef typename std::map value_name_map_t; - typedef std::string name_t; - typedef self_t type_value_t; - typedef ParamValue::value_t> param_value_t; - typedef typename param_value_t::value_t value_t; - - TypeValuesHelper(const typename param_value_t::value_t& val) - : param_value_t(val) - {} - - //TODO: cache key by index to save on param block size - void setValueName(const std::string& value_name) - { - mValueName = value_name; - } - - std::string getValueName() const - { - return mValueName; - } - - std::string calcValueName(const value_t& value) const - { - value_name_map_t* map = getValueNames(); - for (typename value_name_map_t::value_type& map_pair : *map) - { - if (ParamCompare::equals(map_pair.second, value)) - { - return map_pair.first; - } - } - - return ""; - } - - void clearValueName() const - { - mValueName.clear(); - } - - static bool getValueFromName(const std::string& name, value_t& value) - { - value_name_map_t* map = getValueNames(); - typename value_name_map_t::iterator found_it = map->find(name); - if (found_it == map->end()) return false; - - value = found_it->second; - return true; - } - - static bool valueNamesExist() - { - return !getValueNames()->empty(); - } - - static value_name_map_t* getValueNames() - { - static value_name_map_t sMap; - static bool sInitialized = false; - - if (!sInitialized) - { - sInitialized = true; - DERIVED_TYPE::declareValues(); - } - return &sMap; - } - - static std::vector* getPossibleValues() - { - static std::vector sValues; - - value_name_map_t* map = getValueNames(); - for (typename value_name_map_t::value_type& map_pair : *map) - { - sValues.push_back(map_pair.first); - } - return &sValues; - } - - static void declare(const std::string& name, const value_t& value) - { - (*getValueNames())[name] = value; - } - - void operator ()(const std::string& name) - { - *this = name; - } - - void assignNamedValue(const std::string& name) - { - if (getValueFromName(name, param_value_t::getValue())) - { - setValueName(name); - } - } - - operator const value_t&() const - { - return param_value_t::getValue(); - } - - const value_t& operator()() const - { - return param_value_t::getValue(); - } - - protected: - static void getName(const std::string& name, const value_t& value) - {} - - mutable std::string mValueName; - }; - - // string types can support custom named values, but need - // to disambiguate in code between a string that is a named value - // and a string that is a name - template - class TypeValuesHelper - : public TypeValuesHelper - { - public: - typedef TypeValuesHelper self_t; - typedef TypeValuesHelper base_t; - typedef std::string value_t; - typedef std::string name_t; - typedef self_t type_value_t; - - TypeValuesHelper(const std::string& val) - : base_t(val) - {} - - void operator ()(const std::string& name) - { - *this = name; - } - - self_t& operator =(const std::string& name) - { - if (base_t::getValueFromName(name, ParamValue::getValue())) - { - base_t::setValueName(name); - } - else - { - ParamValue::setValue(name); - } - return *this; - } - - operator const value_t&() const - { - return ParamValue::getValue(); - } - - const value_t& operator()() const - { - return ParamValue::getValue(); - } - - }; - - // parser base class with mechanisms for registering readers/writers/inspectors of different types - class LL_COMMON_API Parser - { - LOG_CLASS(Parser); - public: - typedef std::vector > name_stack_t; - typedef std::pair name_stack_range_t; - typedef std::vector possible_values_t; - - typedef bool (*parser_read_func_t)(Parser& parser, void* output); - typedef bool (*parser_write_func_t)(Parser& parser, const void*, name_stack_t&); - typedef boost::function parser_inspect_func_t; - - typedef std::map parser_read_func_map_t; - typedef std::map parser_write_func_map_t; - typedef std::map parser_inspect_func_map_t; - - public: - - Parser(parser_read_func_map_t& read_map, parser_write_func_map_t& write_map, parser_inspect_func_map_t& inspect_map) - : mParseSilently(false), - mParserReadFuncs(&read_map), - mParserWriteFuncs(&write_map), - mParserInspectFuncs(&inspect_map) - {} - - virtual ~Parser(); - - template bool readValue(T& param, typename boost::disable_if >::type* dummy = 0) - { - parser_read_func_map_t::iterator found_it = mParserReadFuncs->find(&typeid(T)); - if (found_it != mParserReadFuncs->end()) - { - return found_it->second(*this, (void*)¶m); - } - - return false; - } - - template bool readValue(T& param, typename boost::enable_if >::type* dummy = 0) - { - parser_read_func_map_t::iterator found_it = mParserReadFuncs->find(&typeid(T)); - if (found_it != mParserReadFuncs->end()) - { - return found_it->second(*this, (void*)¶m); - } - else - { - found_it = mParserReadFuncs->find(&typeid(S32)); - if (found_it != mParserReadFuncs->end()) - { - S32 int_value; - bool parsed = found_it->second(*this, (void*)&int_value); - param = (T)int_value; - return parsed; - } - } - return false; - } - - template bool writeValue(const T& param, name_stack_t& name_stack) - { - parser_write_func_map_t::iterator found_it = mParserWriteFuncs->find(&typeid(T)); - if (found_it != mParserWriteFuncs->end()) - { - return found_it->second(*this, (const void*)¶m, name_stack); - } - return false; - } - - // dispatch inspection to registered inspection functions, for each parameter in a param block - template bool inspectValue(name_stack_t& name_stack, S32 min_count, S32 max_count, const possible_values_t* possible_values) - { - parser_inspect_func_map_t::iterator found_it = mParserInspectFuncs->find(&typeid(T)); - if (found_it != mParserInspectFuncs->end()) - { - found_it->second(name_stack, min_count, max_count, possible_values); - return true; - } - return false; - } - - virtual std::string getCurrentElementName() = 0; - virtual std::string getCurrentFileName() = 0; - virtual void parserWarning(const std::string& message); - virtual void parserError(const std::string& message); - void setParseSilently(bool silent) { mParseSilently = silent; } - - protected: - template - void registerParserFuncs(parser_read_func_t read_func, parser_write_func_t write_func = NULL) - { - mParserReadFuncs->insert(std::make_pair(&typeid(T), read_func)); - mParserWriteFuncs->insert(std::make_pair(&typeid(T), write_func)); - } - - template - void registerInspectFunc(parser_inspect_func_t inspect_func) - { - mParserInspectFuncs->insert(std::make_pair(&typeid(T), inspect_func)); - } - - bool mParseSilently; - - private: - parser_read_func_map_t* mParserReadFuncs; - parser_write_func_map_t* mParserWriteFuncs; - parser_inspect_func_map_t* mParserInspectFuncs; - }; - - class Param; - - enum ESerializePredicates - { - PROVIDED, - REQUIRED, - VALID, - HAS_DEFAULT_VALUE, - EMPTY - }; - - typedef LLPredicate::Rule predicate_rule_t; - - predicate_rule_t default_parse_rules(); - - // various callbacks and constraints associated with an individual param - struct LL_COMMON_API ParamDescriptor - { - struct UserData - { - virtual ~UserData() {} - }; - - typedef bool(*merge_func_t)(Param&, const Param&, bool); - typedef bool(*deserialize_func_t)(Param&, Parser&, Parser::name_stack_range_t&, bool); - typedef bool(*serialize_func_t)(const Param&, Parser&, Parser::name_stack_t&, const predicate_rule_t rules, const Param* diff_param); - typedef void(*inspect_func_t)(const Param&, Parser&, Parser::name_stack_t&, S32 min_count, S32 max_count); - typedef bool(*validation_func_t)(const Param*); - - ParamDescriptor(param_handle_t p, - merge_func_t merge_func, - deserialize_func_t deserialize_func, - serialize_func_t serialize_func, - validation_func_t validation_func, - inspect_func_t inspect_func, - S32 min_count, - S32 max_count); - - ParamDescriptor(); - ~ParamDescriptor(); - - param_handle_t mParamHandle; - merge_func_t mMergeFunc; - deserialize_func_t mDeserializeFunc; - serialize_func_t mSerializeFunc; - inspect_func_t mInspectFunc; - validation_func_t mValidationFunc; - S32 mMinCount; - S32 mMaxCount; - S32 mNumRefs; - UserData* mUserData; - }; - - typedef std::shared_ptr ParamDescriptorPtr; - - // each derived Block class keeps a static data structure maintaining offsets to various params - class LL_COMMON_API BlockDescriptor - { - public: - BlockDescriptor(); - - typedef enum e_initialization_state - { - UNINITIALIZED, - INITIALIZING, - INITIALIZED - } EInitializationState; - - void aggregateBlockData(BlockDescriptor& src_block_data); - void addParam(ParamDescriptorPtr param, const char* name); - - typedef boost::unordered_map param_map_t; - typedef std::vector param_list_t; - typedef std::list all_params_list_t; - typedef std::vector > param_validation_list_t; - - param_map_t mNamedParams; // parameters with associated names - param_list_t mUnnamedParams; // parameters with_out_ associated names - param_validation_list_t mValidationList; // parameters that must be validated - all_params_list_t mAllParams; // all parameters, owns descriptors - size_t mMaxParamOffset; - EInitializationState mInitializationState; // whether or not static block data has been initialized - class BaseBlock* mCurrentBlockPtr; // pointer to block currently being constructed - }; - - //TODO: implement in terms of owned_ptr - template - class LazyValue - { - public: - LazyValue() - : mPtr(NULL) - {} - - ~LazyValue() - { - delete mPtr; - } - - LazyValue(const T& value) - { - mPtr = new T(value); - } - - LazyValue(const LazyValue& other) - : mPtr(NULL) - { - *this = other; - } - - LazyValue& operator = (const LazyValue& other) - { - if (!other.mPtr) - { - delete mPtr; - mPtr = NULL; - } - else - { - if (!mPtr) - { - mPtr = new T(*other.mPtr); - } - else - { - *mPtr = *(other.mPtr); - } - } - return *this; - } - - bool operator==(const LazyValue& other) const - { - if (empty() || other.empty()) return false; - return *mPtr == *other.mPtr; - } - - bool empty() const - { - return mPtr == NULL; - } - - void set(const T& other) - { - if (!mPtr) - { - mPtr = new T(other); - } - else - { - *mPtr = other; - } - } - - const T& get() const - { - return *ensureInstance(); - } - - T& get() - { - return *ensureInstance(); - } - - operator const T&() const - { - return get(); - } - - private: - // lazily allocate an instance of T - T* ensureInstance() const - { - if (mPtr == NULL) - { - mPtr = new T(); - } - return mPtr; - } - - private: - - mutable T* mPtr; - }; - - // root class of all parameter blocks - - class LL_COMMON_API BaseBlock - { - public: - // lift block tags into baseblock namespace so derived classes do not need to qualify them - typedef LLInitParam::IS_A_BLOCK IS_A_BLOCK; - typedef LLInitParam::NOT_BLOCK NOT_A_BLOCK; - - template - struct Sequential : public LLTypeTags::TypeTagBase - { - template struct Cons { typedef Sequential > value_t; }; - template struct Cons > { typedef Sequential value_t; }; - }; - - template - struct Atomic : public LLTypeTags::TypeTagBase - { - template struct Cons { typedef Atomic > value_t; }; - template struct Cons > { typedef Atomic value_t; }; - }; - - template::value_t > - struct Lazy : public LLTypeTags::TypeTagBase - { - template struct Cons - { - typedef Lazy, BLOCK_T> value_t; - }; - template struct Cons > - { - typedef Lazy value_t; - }; - template struct Cons > - { - typedef Lazy value_t; - }; - }; - - // "Multiple" constraint types, put here in root class to avoid ambiguity during use - struct AnyAmount - { - enum { minCount = 0 }; - enum { maxCount = U32_MAX }; - }; - - template - struct AtLeast - { - enum { minCount = MIN_AMOUNT }; - enum { maxCount = U32_MAX }; - }; - - template - struct AtMost - { - enum { minCount = 0 }; - enum { maxCount = MAX_AMOUNT }; - }; - - template - struct Between - { - enum { minCount = MIN_AMOUNT }; - enum { maxCount = MAX_AMOUNT }; - }; - - template - struct Exactly - { - enum { minCount = EXACT_COUNT }; - enum { maxCount = EXACT_COUNT }; - }; - - // this typedef identifies derived classes as being blocks - typedef void baseblock_base_class_t; - LOG_CLASS(BaseBlock); - friend class Param; - - BaseBlock() - : mValidated(false), - mParamProvided(false) - {} - - virtual ~BaseBlock() {} - bool submitValue(Parser::name_stack_t& name_stack, Parser& p, bool silent=false); - - param_handle_t getHandleFromParam(const Param* param) const; - bool validateBlock(bool emit_errors = true) const; - - bool isProvided() const - { - return mParamProvided; - } - - bool isValid() const - { - return validateBlock(false); - } - - - Param* getParamFromHandle(const param_handle_t param_handle) - { - if (param_handle == 0) return NULL; - - U8* baseblock_address = reinterpret_cast(this); - return reinterpret_cast(baseblock_address + param_handle); - } - - const Param* getParamFromHandle(const param_handle_t param_handle) const - { - const U8* baseblock_address = reinterpret_cast(this); - return reinterpret_cast(baseblock_address + param_handle); - } - - void addSynonym(Param& param, const std::string& synonym); - - // Blocks can override this to do custom tracking of changes - virtual void paramChanged(const Param& changed_param, bool user_provided) - { - if (user_provided) - { - // a child param has been explicitly changed - // so *some* aspect of this block is now provided - mValidated = false; - mParamProvided = true; - } - } - - bool deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack_range, bool new_name); - bool serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const predicate_rule_t rule, const BaseBlock* diff_block = NULL) const; - bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const; - - virtual const BlockDescriptor& mostDerivedBlockDescriptor() const { return getBlockDescriptor(); } - virtual BlockDescriptor& mostDerivedBlockDescriptor() { return getBlockDescriptor(); } - - // take all provided params from other and apply to self - bool overwriteFrom(const BaseBlock& other) - { - return false; - } - - // take all provided params that are not already provided, and apply to self - bool fillFrom(const BaseBlock& other) - { - return false; - } - - ParamDescriptorPtr findParamDescriptor(const Param& param); - - // take all provided params from other and apply to self - bool mergeBlock(BlockDescriptor& block_data, const BaseBlock& other, bool overwrite); - - static BlockDescriptor& getBlockDescriptor() - { - static BlockDescriptor sBlockDescriptor; - return sBlockDescriptor; - } - - protected: - void init(BlockDescriptor& descriptor, BlockDescriptor& base_descriptor, size_t block_size); - - - bool mergeBlockParam(bool source_provided, bool dst_provided, BlockDescriptor& block_data, const BaseBlock& source, bool overwrite) - { - return mergeBlock(block_data, source, overwrite); - } - - mutable bool mValidated; // lazy validation flag - bool mParamProvided; - - private: - const std::string& getParamName(const BlockDescriptor& block_data, const Param* paramp) const; - }; - - class LL_COMMON_API Param - { - public: - void setProvided(bool is_provided = true) - { - mIsProvided = is_provided; - enclosingBlock().paramChanged(*this, is_provided); - } - - Param& operator =(const Param& other) - { - mIsProvided = other.mIsProvided; - // don't change mEnclosingblockoffset - return *this; - } - protected: - - bool anyProvided() const { return mIsProvided; } - - Param(BaseBlock* enclosing_block); - - // store pointer to enclosing block as offset to reduce space and allow for quick copying - BaseBlock& enclosingBlock() const - { - const U8* my_addr = reinterpret_cast(this); - // get address of enclosing BLOCK class using stored offset to enclosing BaseBlock class - return *const_cast - (reinterpret_cast - (my_addr - (ptrdiff_t)getEnclosingBlockOffset())); - } - - U32 getEnclosingBlockOffset() const - { - return ((U32)mEnclosingBlockOffsetHigh << 16) | (U32)mEnclosingBlockOffsetLow; - } - - private: - friend class BaseBlock; - - //24 bits for member offset field and 1 bit for provided flag - U16 mEnclosingBlockOffsetLow; - U8 mEnclosingBlockOffsetHigh:7; - U8 mIsProvided:1; - - }; - - template > - struct ParamIterator - { - typedef typename std::vector::const_iterator const_iterator; - typedef typename std::vector::iterator iterator; - }; - - // wrapper for parameter with a known type - // specialized to handle 4 cases: - // simple "scalar" value - // parameter that is itself a block - // multiple scalar values, stored in a vector - // multiple blocks, stored in a vector - template, - bool HAS_MULTIPLE_VALUES = false, - typename VALUE_IS_BLOCK = typename IsBlock::value_t> >::value_t> - class TypedParam - : public Param, - public NAME_VALUE_LOOKUP::type_value_t - { - protected: - typedef TypedParam self_t; - typedef ParamValue::value_t> param_value_t; - typedef typename param_value_t::default_value_t default_value_t; - typedef typename NAME_VALUE_LOOKUP::type_value_t named_value_t; - public: - typedef typename param_value_t::value_t value_t; - - using named_value_t::operator(); - - TypedParam(BlockDescriptor& block_descriptor, const char* name, const default_value_t& value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count) - : Param(block_descriptor.mCurrentBlockPtr), - named_value_t(value) - { - if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING)) - { - init(block_descriptor, validate_func, min_count, max_count, name); - } - } - - bool isProvided() const { return Param::anyProvided(); } - - bool isValid() const { return true; } - - static bool deserializeParam(Param& param, Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name) - { - self_t& typed_param = static_cast(param); - // no further names in stack, attempt to parse value now - if (name_stack_range.first == name_stack_range.second) - { - std::string name; - - // try to parse a known named value - if(named_value_t::valueNamesExist() - && parser.readValue(name) - && named_value_t::getValueFromName(name, typed_param.getValue())) - { - typed_param.setValueName(name); - typed_param.setProvided(); - return true; - } - // try to read value directly - else if (parser.readValue(typed_param.getValue())) - { - typed_param.clearValueName(); - typed_param.setProvided(); - return true; - } - } - return false; - } - - static bool serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const Param* diff_param) - { - bool serialized = false; - const self_t& typed_param = static_cast(param); - const self_t* diff_typed_param = static_cast(diff_param); - - LLPredicate::Value predicate; - if (diff_typed_param && ParamCompare::equals(typed_param.getValue(), diff_typed_param->getValue())) - { - predicate.set(HAS_DEFAULT_VALUE); - } - - predicate.set(VALID, typed_param.isValid()); - predicate.set(PROVIDED, typed_param.anyProvided()); - predicate.set(EMPTY, false); - - if (!predicate_rule.check(predicate)) return false; - - if (!name_stack.empty()) - { - name_stack.back().second = true; - } - - std::string key = typed_param.getValueName(); - - // first try to write out name of name/value pair - - if (!key.empty()) - { - if (!diff_typed_param || !ParamCompare::equals(diff_typed_param->getValueName(), key)) - { - serialized = parser.writeValue(key, name_stack); - } - } - // then try to serialize value directly - else if (!diff_typed_param || ParamCompare::equals(typed_param.getValue(), diff_typed_param->getValue())) - { - serialized = parser.writeValue(typed_param.getValue(), name_stack); - if (!serialized) - { - std::string calculated_key = typed_param.calcValueName(typed_param.getValue()); - if (calculated_key.size() - && (!diff_typed_param - || !ParamCompare::equals(static_cast(diff_param)->getValueName(), calculated_key))) - { - serialized = parser.writeValue(calculated_key, name_stack); - } - } - } - return serialized; - } - - static void inspectParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, S32 min_count, S32 max_count) - { - // tell parser about our actual type - parser.inspectValue(name_stack, min_count, max_count, NULL); - // then tell it about string-based alternatives ("red", "blue", etc. for LLColor4) - if (named_value_t::getPossibleValues()) - { - parser.inspectValue(name_stack, min_count, max_count, named_value_t::getPossibleValues()); - } - } - - void set(const value_t& val, bool flag_as_provided = true) - { - named_value_t::clearValueName(); - named_value_t::setValue(val); - setProvided(flag_as_provided); - } - - self_t& operator =(const typename named_value_t::name_t& name) - { - named_value_t::assignNamedValue(name); - return *this; - } - - protected: - - self_t& operator =(const self_t& other) - { - param_value_t::operator =(other); - Param::operator =(other); - return *this; - } - - static bool mergeWith(Param& dst, const Param& src, bool overwrite) - { - const self_t& src_typed_param = static_cast(src); - self_t& dst_typed_param = static_cast(dst); - - if (src_typed_param.isProvided() - && (overwrite || !dst_typed_param.isProvided())) - { - dst_typed_param.set(src_typed_param.getValue()); - return true; - } - return false; - } - private: - void init( BlockDescriptor &block_descriptor, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count, const char* name ) - { - ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor( - block_descriptor.mCurrentBlockPtr->getHandleFromParam(this), - &mergeWith, - &deserializeParam, - &serializeParam, - validate_func, - &inspectParam, - min_count, max_count)); - block_descriptor.addParam(param_descriptor, name); - } - }; - - // parameter that is a block - template - class TypedParam - : public Param, - public NAME_VALUE_LOOKUP::type_value_t - { - protected: - typedef ParamValue::value_t> param_value_t; - typedef typename param_value_t::default_value_t default_value_t; - typedef TypedParam self_t; - typedef typename NAME_VALUE_LOOKUP::type_value_t named_value_t; - public: - using named_value_t::operator(); - typedef typename param_value_t::value_t value_t; - - TypedParam(BlockDescriptor& block_descriptor, const char* name, const default_value_t& value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count) - : Param(block_descriptor.mCurrentBlockPtr), - named_value_t(value) - { - if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING)) - { - init(block_descriptor, validate_func, min_count, max_count, name); - } - } - - static bool deserializeParam(Param& param, Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name) - { - self_t& typed_param = static_cast(param); - - if (name_stack_range.first == name_stack_range.second) - { // try to parse a known named value - std::string name; - - if(named_value_t::valueNamesExist() - && parser.readValue(name) - && named_value_t::getValueFromName(name, typed_param.getValue())) - { - typed_param.setValueName(name); - typed_param.setProvided(); - return true; - } - } - - if(typed_param.deserializeBlock(parser, name_stack_range, new_name)) - { // attempt to parse block... - typed_param.clearValueName(); - typed_param.setProvided(); - return true; - } - - - return false; - } - - static bool serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const Param* diff_param) - { - const self_t& typed_param = static_cast(param); - - LLPredicate::Value predicate; - - predicate.set(VALID, typed_param.isValid()); - predicate.set(PROVIDED, typed_param.anyProvided()); - - if (!predicate_rule.check(predicate)) return false; - - if (!name_stack.empty()) - { - name_stack.back().second = true; - } - - std::string key = typed_param.getValueName(); - if (!key.empty()) - { - if (!diff_param || !ParamCompare::equals(static_cast(diff_param)->getValueName(), key)) - { - parser.writeValue(key, name_stack); - return true; - } - } - else - { - return typed_param.serializeBlock(parser, name_stack, predicate_rule, static_cast(diff_param)); - } - - return false; - } - - static void inspectParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, S32 min_count, S32 max_count) - { - const self_t& typed_param = static_cast(param); - - // tell parser about our actual type - parser.inspectValue(name_stack, min_count, max_count, NULL); - // then tell it about string-based alternatives ("red", "blue", etc. for LLColor4) - if (named_value_t::getPossibleValues()) - { - parser.inspectValue(name_stack, min_count, max_count, named_value_t::getPossibleValues()); - } - - typed_param.inspectBlock(parser, name_stack, min_count, max_count); - } - - // a param-that-is-a-block is provided when the user has set one of its child params - // *and* the block as a whole validates - bool isProvided() const - { - return Param::anyProvided() && isValid(); - } - - bool isValid() const - { - return param_value_t::isValid(); - } - - // assign block contents to this param-that-is-a-block - void set(const value_t& val, bool flag_as_provided = true) - { - named_value_t::setValue(val); - named_value_t::clearValueName(); - setProvided(flag_as_provided); - } - - self_t& operator =(const typename named_value_t::name_t& name) - { - named_value_t::assignNamedValue(name); - return *this; - } - - // propagate changed status up to enclosing block - /*virtual*/ void paramChanged(const Param& changed_param, bool user_provided) - { - param_value_t::paramChanged(changed_param, user_provided); - - if (user_provided) - { - setProvided(); - named_value_t::clearValueName(); - } - else - { - Param::enclosingBlock().paramChanged(*this, user_provided); - } - } - - protected: - - self_t& operator =(const self_t& other) - { - param_value_t::operator =(other); - Param::operator =(other); - return *this; - } - - static bool mergeWith(Param& dst, const Param& src, bool overwrite) - { - const self_t& src_typed_param = static_cast(src); - self_t& dst_typed_param = static_cast(dst); - - if (src_typed_param.anyProvided()) - { - if (dst_typed_param.mergeBlockParam(src_typed_param.isProvided(), dst_typed_param.isProvided(), param_value_t::getBlockDescriptor(), src_typed_param, overwrite)) - { - dst_typed_param.clearValueName(); - dst_typed_param.setProvided(true); - return true; - } - } - return false; - } - - private: - void init( BlockDescriptor &block_descriptor, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count, const char* name ) - { - ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor( - block_descriptor.mCurrentBlockPtr->getHandleFromParam(this), - &mergeWith, - &deserializeParam, - &serializeParam, - validate_func, - &inspectParam, - min_count, max_count)); - block_descriptor.addParam(param_descriptor, name); - } - }; - - // list of non-block parameters - template - class TypedParam - : public Param - { - protected: - typedef TypedParam self_t; - typedef ParamValue::value_t> param_value_t; - typedef typename std::vector container_t; - typedef container_t default_value_t; - typedef typename NAME_VALUE_LOOKUP::type_value_t named_value_t; - - public: - typedef typename param_value_t::value_t value_t; - - TypedParam(BlockDescriptor& block_descriptor, const char* name, const default_value_t& value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count) - : Param(block_descriptor.mCurrentBlockPtr), - mMinCount(min_count), - mMaxCount(max_count) - { - std::copy(value.begin(), value.end(), std::back_inserter(mValues)); - - if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING)) - { - init(block_descriptor, validate_func, min_count, max_count, name); - - } - } - - bool isProvided() const { return Param::anyProvided() && isValid(); } - - bool isValid() const - { - size_t num_elements = numValidElements(); - return mMinCount < num_elements && num_elements < mMaxCount; - } - - static bool deserializeParam(Param& param, Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name) - { - Parser::name_stack_range_t new_name_stack_range(name_stack_range); - self_t& typed_param = static_cast(param); - value_t value; - - // pop first element if empty string - if (new_name_stack_range.first != new_name_stack_range.second && new_name_stack_range.first->first.empty()) - { - ++new_name_stack_range.first; - } - - // no further names in stack, attempt to parse value now - if (new_name_stack_range.first == new_name_stack_range.second) - { - std::string name; - - // try to parse a known named value - if(named_value_t::valueNamesExist() - && parser.readValue(name) - && named_value_t::getValueFromName(name, value)) - { - typed_param.add(value); - typed_param.mValues.back().setValueName(name); - return true; - } - else if (parser.readValue(value)) // attempt to read value directly - { - typed_param.add(value); - return true; - } - } - return false; - } - - static bool serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const Param* diff_param) - { - bool serialized = false; - const self_t& typed_param = static_cast(param); - - LLPredicate::Value predicate; - - predicate.set(REQUIRED, typed_param.mMinCount > 0); - predicate.set(VALID, typed_param.isValid()); - predicate.set(PROVIDED, typed_param.anyProvided()); - predicate.set(EMPTY, typed_param.mValues.empty()); - - if (!predicate_rule.check(predicate)) return false; - - for (const_iterator it = typed_param.mValues.begin(), end_it = typed_param.mValues.end(); - it != end_it; - ++it) - { - std::string key = it->getValueName(); - name_stack.push_back(std::make_pair(std::string(), true)); - - if(key.empty()) - // not parsed via name values, write out value directly - { - bool value_written = parser.writeValue(*it, name_stack); - if (!value_written) - { - std::string calculated_key = it->calcValueName(it->getValue()); - if (parser.writeValue(calculated_key, name_stack)) - { - serialized = true; - } - else - { - break; - } - } - } - else - { - if(parser.writeValue(key, name_stack)) - { - serialized = true; - } - else - { - break; - } - } - } - - return serialized; - } - - static void inspectParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, S32 min_count, S32 max_count) - { - parser.inspectValue(name_stack, min_count, max_count, NULL); - if (named_value_t::getPossibleValues()) - { - parser.inspectValue(name_stack, min_count, max_count, named_value_t::getPossibleValues()); - } - } - - void set(const container_t& val, bool flag_as_provided = true) - { - mValues = val; - setProvided(flag_as_provided); - } - - param_value_t& add() - { - mValues.push_back(value_t()); - Param::setProvided(); - return mValues.back(); - } - - self_t& add(const value_t& item) - { - mValues.push_back(item); - setProvided(); - return *this; - } - - self_t& add(const typename named_value_t::name_t& name) - { - value_t value; - - // try to parse a per type named value - if (named_value_t::getValueFromName(name, value)) - { - add(value); - mValues.back().setValueName(name); - } - - return *this; - } - - // implicit conversion - operator const container_t&() const { return mValues; } - // explicit conversion - const container_t& operator()() const { return mValues; } - - typedef typename container_t::iterator iterator; - typedef typename container_t::const_iterator const_iterator; - iterator begin() { return mValues.begin(); } - iterator end() { return mValues.end(); } - const_iterator begin() const { return mValues.begin(); } - const_iterator end() const { return mValues.end(); } - bool empty() const { return mValues.empty(); } - size_t size() const { return mValues.size(); } - - size_t numValidElements() const - { - return mValues.size(); - } - - protected: - static bool mergeWith(Param& dst, const Param& src, bool overwrite) - { - const self_t& src_typed_param = static_cast(src); - self_t& dst_typed_param = static_cast(dst); - - if (overwrite) - { - std::copy(src_typed_param.begin(), src_typed_param.end(), std::back_inserter(dst_typed_param.mValues)); - } - else - { - container_t new_values(src_typed_param.mValues); - std::copy(dst_typed_param.begin(), dst_typed_param.end(), std::back_inserter(new_values)); - std::swap(dst_typed_param.mValues, new_values); - } - - if (src_typed_param.begin() != src_typed_param.end()) - { - dst_typed_param.setProvided(); - } - return true; - } - - container_t mValues; - size_t mMinCount, - mMaxCount; - - private: - void init( BlockDescriptor &block_descriptor, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count, const char* name ) - { - ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor( - block_descriptor.mCurrentBlockPtr->getHandleFromParam(this), - &mergeWith, - &deserializeParam, - &serializeParam, - validate_func, - &inspectParam, - min_count, max_count)); - block_descriptor.addParam(param_descriptor, name); - } - }; - - // list of block parameters - template - class TypedParam - : public Param - { - protected: - typedef TypedParam self_t; - typedef ParamValue::value_t> param_value_t; - typedef typename std::vector container_t; - typedef typename NAME_VALUE_LOOKUP::type_value_t named_value_t; - typedef container_t default_value_t; - typedef typename container_t::iterator iterator; - typedef typename container_t::const_iterator const_iterator; - public: - typedef typename param_value_t::value_t value_t; - - TypedParam(BlockDescriptor& block_descriptor, const char* name, const default_value_t& value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count) - : Param(block_descriptor.mCurrentBlockPtr), - mMinCount(min_count), - mMaxCount(max_count) - { - std::copy(value.begin(), value.end(), back_inserter(mValues)); - - if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING)) - { - init(block_descriptor, validate_func, min_count, max_count, name); - } - } - - bool isProvided() const { return Param::anyProvided() && isValid(); } - - bool isValid() const - { - size_t num_elements = numValidElements(); - return mMinCount < num_elements && num_elements < mMaxCount; - } - - - static bool deserializeParam(Param& param, Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name) - { - Parser::name_stack_range_t new_name_stack_range(name_stack_range); - self_t& typed_param = static_cast(param); - bool new_value = false; - bool new_array_value = false; - - // pop first element if empty string - if (new_name_stack_range.first != new_name_stack_range.second && new_name_stack_range.first->first.empty()) - { - new_array_value = new_name_stack_range.first->second; - ++new_name_stack_range.first; - } - - if (new_name || new_array_value || typed_param.mValues.empty()) - { - new_value = true; - typed_param.mValues.push_back(value_t()); - } - param_value_t& value = typed_param.mValues.back(); - - if (new_name_stack_range.first == new_name_stack_range.second) - { // try to parse a known named value - std::string name; - - if(named_value_t::valueNamesExist() - && parser.readValue(name) - && named_value_t::getValueFromName(name, value.getValue())) - { - typed_param.mValues.back().setValueName(name); - typed_param.setProvided(); - if (new_array_value) - { - name_stack_range.first->second = false; - } - return true; - } - } - - // attempt to parse block... - if(value.deserializeBlock(parser, new_name_stack_range, new_name)) - { - typed_param.setProvided(); - if (new_array_value) - { - name_stack_range.first->second = false; - } - return true; - } - - - if (new_value) - { // failed to parse new value, pop it off - typed_param.mValues.pop_back(); - } - - return false; - } - - static bool serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const Param* diff_param) - { - bool serialized = false; - const self_t& typed_param = static_cast(param); - LLPredicate::Value predicate; - - predicate.set(REQUIRED, typed_param.mMinCount > 0); - predicate.set(VALID, typed_param.isValid()); - predicate.set(PROVIDED, typed_param.anyProvided()); - predicate.set(EMPTY, typed_param.mValues.empty()); - - if (!predicate_rule.check(predicate)) return false; - - for (const_iterator it = typed_param.mValues.begin(), end_it = typed_param.mValues.end(); - it != end_it; - ++it) - { - name_stack.push_back(std::make_pair(std::string(), true)); - - std::string key = it->getValueName(); - if (!key.empty()) - { - serialized |= parser.writeValue(key, name_stack); - } - // Not parsed via named values, write out value directly - // NOTE: currently we don't do diffing of Multiples - else - { - serialized = it->serializeBlock(parser, name_stack, predicate_rule, NULL); - } - - name_stack.pop_back(); - } - - if (!serialized && predicate_rule.check(ll_make_predicate(EMPTY))) - { - serialized |= parser.writeValue(Flag(), name_stack); - } - - return serialized; - } - - static void inspectParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, S32 min_count, S32 max_count) - { - const param_value_t& value_param = param_value_t(value_t()); - - // tell parser about our actual type - parser.inspectValue(name_stack, min_count, max_count, NULL); - // then tell it about string-based alternatives ("red", "blue", etc. for LLColor4) - if (named_value_t::getPossibleValues()) - { - parser.inspectValue(name_stack, min_count, max_count, named_value_t::getPossibleValues()); - } - - value_param.inspectBlock(parser, name_stack, min_count, max_count); - } - - void set(const container_t& val, bool flag_as_provided = true) - { - mValues = val; - setProvided(flag_as_provided); - } - - param_value_t& add() - { - mValues.push_back(value_t()); - setProvided(); - return mValues.back(); - } - - self_t& add(const value_t& item) - { - mValues.push_back(item); - setProvided(); - return *this; - } - - self_t& add(const typename named_value_t::name_t& name) - { - value_t value; - - // try to parse a per type named value - if (named_value_t::getValueFromName(name, value)) - { - add(value); - mValues.back().setValueName(name); - } - return *this; - } - - // implicit conversion - operator const container_t&() const { return mValues; } - // explicit conversion - const container_t& operator()() const { return mValues; } - - iterator begin() { return mValues.begin(); } - iterator end() { return mValues.end(); } - const_iterator begin() const { return mValues.begin(); } - const_iterator end() const { return mValues.end(); } - bool empty() const { return mValues.empty(); } - size_t size() const { return mValues.size(); } - - size_t numValidElements() const - { - size_t count = 0; - for (const_iterator it = mValues.begin(), end_it = mValues.end(); - it != end_it; - ++it) - { - if(it->isValid()) count++; - } - return count; - } - - protected: - - static bool mergeWith(Param& dst, const Param& src, bool overwrite) - { - const self_t& src_typed_param = static_cast(src); - self_t& dst_typed_param = static_cast(dst); - - if (overwrite) - { - std::copy(src_typed_param.begin(), src_typed_param.end(), std::back_inserter(dst_typed_param.mValues)); - } - else - { - container_t new_values(src_typed_param.mValues); - std::copy(dst_typed_param.begin(), dst_typed_param.end(), std::back_inserter(new_values)); - std::swap(dst_typed_param.mValues, new_values); - } - - if (src_typed_param.begin() != src_typed_param.end()) - { - dst_typed_param.setProvided(); - } - - return true; - } - - container_t mValues; - size_t mMinCount, - mMaxCount; - - private: - void init( BlockDescriptor &block_descriptor, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count, const char* name ) - { - ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor( - block_descriptor.mCurrentBlockPtr->getHandleFromParam(this), - &mergeWith, - &deserializeParam, - &serializeParam, - validate_func, - &inspectParam, - min_count, max_count)); - block_descriptor.addParam(param_descriptor, name); - } - }; - - template - class ChoiceBlock : public BASE_BLOCK - { - typedef ChoiceBlock self_t; - typedef ChoiceBlock enclosing_block_t; - typedef BASE_BLOCK base_block_t; - - LOG_CLASS(self_t); - public: - // take all provided params from other and apply to self - bool overwriteFrom(const self_t& other) - { - return static_cast(this)->mergeBlock(getBlockDescriptor(), other, true); - } - - // take all provided params that are not already provided, and apply to self - bool fillFrom(const self_t& other) - { - return static_cast(this)->mergeBlock(getBlockDescriptor(), other, false); - } - - bool mergeBlockParam(bool source_provided, bool dest_provided, BlockDescriptor& block_data, const self_t& source, bool overwrite) - { - bool source_override = source_provided && (overwrite || !dest_provided); - - if (source_override || source.mCurChoice == mCurChoice) - { - return mergeBlock(block_data, source, overwrite); - } - return false; - } - - // merge with other block - bool mergeBlock(BlockDescriptor& block_data, const self_t& other, bool overwrite) - { - mCurChoice = other.mCurChoice; - return base_block_t::mergeBlock(getBlockDescriptor(), other, overwrite); - } - - // clear out old choice when param has changed - /*virtual*/ void paramChanged(const Param& changed_param, bool user_provided) - { - param_handle_t changed_param_handle = base_block_t::getHandleFromParam(&changed_param); - // if we have a new choice... - if (changed_param_handle != mCurChoice) - { - // clear provided flag on previous choice - Param* previous_choice = base_block_t::getParamFromHandle(mCurChoice); - if (previous_choice) - { - previous_choice->setProvided(false); - } - mCurChoice = changed_param_handle; - } - base_block_t::paramChanged(changed_param, user_provided); - } - - virtual const BlockDescriptor& mostDerivedBlockDescriptor() const { return getBlockDescriptor(); } - virtual BlockDescriptor& mostDerivedBlockDescriptor() { return getBlockDescriptor(); } - - protected: - ChoiceBlock() - : mCurChoice(0) - { - BaseBlock::init(getBlockDescriptor(), base_block_t::getBlockDescriptor(), sizeof(DERIVED_BLOCK)); - } - - // Alternatives are mutually exclusive wrt other Alternatives in the same block. - // One alternative in a block will always have isChosen() == true. - // At most one alternative in a block will have isProvided() == true. - template ::type_value_t > - class Alternative : public TypedParam - { - typedef TypedParam super_t; - typedef typename super_t::value_t value_t; - typedef typename super_t::default_value_t default_value_t; - - public: - friend class ChoiceBlock; - - using super_t::operator =; - - explicit Alternative(const char* name = "", const default_value_t& val = defaultValue()) - : super_t(DERIVED_BLOCK::getBlockDescriptor(), name, val, NULL, 0, 1), - mOriginalValue(val) - { - // assign initial choice to first declared option - DERIVED_BLOCK* blockp = ((DERIVED_BLOCK*)DERIVED_BLOCK::getBlockDescriptor().mCurrentBlockPtr); - if (LL_UNLIKELY(DERIVED_BLOCK::getBlockDescriptor().mInitializationState == BlockDescriptor::INITIALIZING)) - { - if(blockp->mCurChoice == 0) - { - blockp->mCurChoice = Param::enclosingBlock().getHandleFromParam(this); - } - } - } - - void choose() - { - static_cast(Param::enclosingBlock()).paramChanged(*this, true); - } - - void chooseAs(const value_t& val) - { - super_t::set(val); - } - - void operator =(const value_t& val) - { - super_t::set(val); - } - - void operator()(const value_t& val) - { - super_t::set(val); - } - - operator const value_t&() const - { - return (*this)(); - } - - const value_t& operator()() const - { - if (static_cast(Param::enclosingBlock()).getCurrentChoice() == this) - { - return super_t::getValue(); - } - return mOriginalValue; - } - - bool isChosen() const - { - return static_cast(Param::enclosingBlock()).getCurrentChoice() == this; - } - - private: - default_value_t mOriginalValue; - }; - - public: - static BlockDescriptor& getBlockDescriptor() - { - static BlockDescriptor sBlockDescriptor; - return sBlockDescriptor; - } - - private: - param_handle_t mCurChoice; - - const Param* getCurrentChoice() const - { - return base_block_t::getParamFromHandle(mCurChoice); - } - }; - - template - class Block - : public BASE_BLOCK - { - typedef Block self_t; - - protected: - typedef Block block_t; - - public: - typedef BASE_BLOCK base_block_t; - - // take all provided params from other and apply to self - bool overwriteFrom(const self_t& other) - { - return static_cast(this)->mergeBlock(getBlockDescriptor(), other, true); - } - - // take all provided params that are not already provided, and apply to self - bool fillFrom(const self_t& other) - { - return static_cast(this)->mergeBlock(getBlockDescriptor(), other, false); - } - - virtual const BlockDescriptor& mostDerivedBlockDescriptor() const { return getBlockDescriptor(); } - virtual BlockDescriptor& mostDerivedBlockDescriptor() { return getBlockDescriptor(); } - - protected: - Block() - { - //#pragma message("Parsing LLInitParam::Block") - BaseBlock::init(getBlockDescriptor(), BASE_BLOCK::getBlockDescriptor(), sizeof(DERIVED_BLOCK)); - } - - // - // Nested classes for declaring parameters - // - template ::type_value_t > - class Optional : public TypedParam - { - typedef TypedParam super_t; - typedef typename super_t::value_t value_t; - typedef typename super_t::default_value_t default_value_t; - - public: - using super_t::operator(); - using super_t::operator =; - - explicit Optional(const char* name = "", const default_value_t& val = defaultValue()) - : super_t(DERIVED_BLOCK::getBlockDescriptor(), name, val, NULL, 0, 1) - { - //#pragma message("Parsing LLInitParam::Block::Optional") - } - - Optional& operator =(const value_t& val) - { - super_t::set(val); - return *this; - } - - DERIVED_BLOCK& operator()(const value_t& val) - { - super_t::set(val); - return static_cast(Param::enclosingBlock()); - } - }; - - template ::type_value_t > - class Mandatory : public TypedParam - { - typedef TypedParam super_t; - typedef Mandatory self_t; - typedef typename super_t::value_t value_t; - typedef typename super_t::default_value_t default_value_t; - - public: - using super_t::operator(); - using super_t::operator =; - - // mandatory parameters require a name to be parseable - explicit Mandatory(const char* name = "", const default_value_t& val = defaultValue()) - : super_t(DERIVED_BLOCK::getBlockDescriptor(), name, val, &validate, 1, 1) - {} - - Mandatory& operator =(const value_t& val) - { - super_t::set(val); - return *this; - } - - DERIVED_BLOCK& operator()(const value_t& val) - { - super_t::set(val); - return static_cast(Param::enclosingBlock()); - } - - static bool validate(const Param* p) - { - // valid only if provided - return static_cast(p)->isProvided(); - } - - }; - - template ::type_value_t > - class Multiple : public TypedParam - { - typedef TypedParam super_t; - typedef Multiple self_t; - typedef typename super_t::container_t container_t; - typedef typename super_t::value_t value_t; - - public: - typedef typename super_t::iterator iterator; - typedef typename super_t::const_iterator const_iterator; - - using super_t::operator(); - using super_t::operator const container_t&; - - explicit Multiple(const char* name = "") - : super_t(DERIVED_BLOCK::getBlockDescriptor(), name, container_t(), &validate, RANGE::minCount, RANGE::maxCount) - {} - - Multiple& operator =(const container_t& val) - { - super_t::set(val); - return *this; - } - - DERIVED_BLOCK& operator()(const container_t& val) - { - super_t::set(val); - return static_cast(Param::enclosingBlock()); - } - - static bool validate(const Param* paramp) - { - size_t num_valid = ((super_t*)paramp)->numValidElements(); - return RANGE::minCount <= num_valid && num_valid <= RANGE::maxCount; - } - }; - - // can appear in data files, but will ignored during parsing - // cannot read or write in code - class Ignored : public Param - { - public: - explicit Ignored(const char* name) - : Param(DERIVED_BLOCK::getBlockDescriptor().mCurrentBlockPtr) - { - BlockDescriptor& block_descriptor = DERIVED_BLOCK::getBlockDescriptor(); - if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING)) - { - ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor( - block_descriptor.mCurrentBlockPtr->getHandleFromParam(this), - NULL, - &deserializeParam, - NULL, - NULL, - NULL, - 0, S32_MAX)); - block_descriptor.addParam(param_descriptor, name); - } - } - - static bool deserializeParam(Param& param, Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name) - { - if (name_stack_range.first == name_stack_range.second) - { - //std::string message = llformat("Deprecated value %s ignored", getName().c_str()); - //parser.parserWarning(message); - return true; - } - - return false; - } - }; - - // can appear in data files, or be written to in code, but data will be ignored - // cannot be read in code - class Deprecated : public Ignored - { - public: - explicit Deprecated(const char* name) : Ignored(name) {} - - // dummy writer interfaces - template - Deprecated& operator =(const T& val) - { - // do nothing - return *this; - } - - template - DERIVED_BLOCK& operator()(const T& val) - { - // do nothing - return static_cast(Param::enclosingBlock()); - } - - template - void set(const T& val, bool flag_as_provided = true) - { - // do nothing - } - }; - - public: - static BlockDescriptor& getBlockDescriptor() - { - static BlockDescriptor sBlockDescriptor; - return sBlockDescriptor; - } - - protected: - template - void changeDefault(TypedParam& param, - const typename TypedParam::value_t& value) - { - if (!param.isProvided()) - { - param.set(value, false); - } - } - - }; - - template - struct IsBlock, BLOCK_T >, void> - { - typedef IS_A_BLOCK value_t; - }; - - template - struct IsBlock, BLOCK_T >, void> - { - typedef NOT_BLOCK value_t; - }; - - template - struct IsBlock, typename IsBlock >::value_t >, BLOCK_IDENTIFIER> - { - typedef typename IsBlock::value_t value_t; - }; - - template - struct IsBlock, typename IsBlock >::value_t >, BLOCK_IDENTIFIER> - { - typedef typename IsBlock::value_t value_t; - }; - - - template - struct InnerMostType - { - typedef T value_t; - }; - - template - struct InnerMostType > - { - typedef typename InnerMostType::value_t value_t; - }; - - template - struct InnerMostType > - { - typedef typename InnerMostType::value_t value_t; - }; - - template - class ParamValue , BLOCK_T> - { - typedef ParamValue , BLOCK_T> self_t; - - public: - typedef typename InnerMostType::value_t value_t; - typedef T default_value_t; - - ParamValue() - : mValue() - {} - - ParamValue(const default_value_t& value) - : mValue(value) - {} - - void setValue(const value_t& val) - { - mValue.setValue(val); - } - - const value_t& getValue() const - { - return mValue.getValue(); - } - - value_t& getValue() - { - return mValue.getValue(); - } - - bool deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack_range, bool new_name) - { - if (new_name) - { - resetToDefault(); - } - return mValue.deserializeBlock(p, name_stack_range, new_name); - } - - bool serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const self_t* diff_block = NULL) const - { - const BaseBlock* base_block = diff_block - ? &(diff_block->mValue) - : NULL; - return mValue.serializeBlock(p, name_stack, predicate_rule, base_block); - } - - bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const - { - return mValue.inspectBlock(p, name_stack, min_count, max_count); - } - - bool mergeBlockParam(bool source_provided, bool dst_provided, BlockDescriptor& block_data, const self_t& source, bool overwrite) - { - if ((overwrite && source_provided) // new values coming in on top or... - || (!overwrite && !dst_provided)) // values being pushed under with nothing already there - { - // clear away what is there and take the new stuff as a whole - resetToDefault(); - return mValue.mergeBlock(block_data, source.getValue(), overwrite); - } - return mValue.mergeBlock(block_data, source.getValue(), overwrite); - } - - bool validateBlock(bool emit_errors = true) const - { - return mValue.validateBlock(emit_errors); - } - - bool isValid() const - { - return validateBlock(false); - } - - static BlockDescriptor& getBlockDescriptor() - { - return value_t::getBlockDescriptor(); - } - - - private: - void resetToDefault() - { - static T default_value; - mValue = default_value; - } - - T mValue; - }; - - template - class ParamValue , IS_A_BLOCK> - { - typedef ParamValue , IS_A_BLOCK> self_t; - - public: - typedef typename InnerMostType::value_t value_t; - typedef T default_value_t; - - ParamValue() - : mValue() - { - mCurParam = getBlockDescriptor().mAllParams.begin(); - } - - ParamValue(const default_value_t& value) - : mValue(value) - { - mCurParam = getBlockDescriptor().mAllParams.begin(); - } - - void setValue(const value_t& val) - { - mValue.setValue(val); - } - - const value_t& getValue() const - { - return mValue.getValue(); - } - - value_t& getValue() - { - return mValue.getValue(); - } - - bool deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack_range, bool new_name) - { - if (new_name) - { - mCurParam = getBlockDescriptor().mAllParams.begin(); - } - if (name_stack_range.first == name_stack_range.second - && mCurParam != getBlockDescriptor().mAllParams.end()) - { - // deserialize to mCurParam - ParamDescriptor& pd = *(*mCurParam); - ParamDescriptor::deserialize_func_t deserialize_func = pd.mDeserializeFunc; - Param* paramp = mValue.getParamFromHandle(pd.mParamHandle); - - if (deserialize_func - && paramp - && deserialize_func(*paramp, p, name_stack_range, new_name)) - { - ++mCurParam; - return true; - } - else - { - return false; - } - } - else - { - return mValue.deserializeBlock(p, name_stack_range, new_name); - } - } - - bool serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const self_t* diff_block = NULL) const - { - const BaseBlock* base_block = diff_block - ? &(diff_block->mValue) - : NULL; - return mValue.serializeBlock(p, name_stack, predicate_rule, base_block); - } - - bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const - { - return mValue.inspectBlock(p, name_stack, min_count, max_count); - } - - bool mergeBlockParam(bool source_provided, bool dst_provided, BlockDescriptor& block_data, const self_t& source, bool overwrite) - { - return mValue.mergeBlock(block_data, source.getValue(), overwrite); - } - - bool validateBlock(bool emit_errors = true) const - { - return mValue.validateBlock(emit_errors); - } - - bool isValid() const - { - return validateBlock(false); - } - - static BlockDescriptor& getBlockDescriptor() - { - return value_t::getBlockDescriptor(); - } - - private: - - BlockDescriptor::all_params_list_t::iterator mCurParam; - T mValue; - }; - - template - class ParamValue , NOT_BLOCK> - : public T - { - typedef ParamValue , NOT_BLOCK> self_t; - - public: - typedef typename InnerMostType::value_t value_t; - typedef T default_value_t; - - ParamValue() - : T() - {} - - ParamValue(const default_value_t& value) - : T(value.getValue()) - {} - - bool isValid() const { return true; } - }; - - template - class ParamValue , BLOCK_T> - { - typedef ParamValue , BLOCK_T> self_t; - - public: - typedef typename InnerMostType::value_t value_t; - typedef LazyValue default_value_t; - - ParamValue() - : mValue() - {} - - ParamValue(const default_value_t& other) - : mValue(other) - {} - - ParamValue(const T& value) - : mValue(value) - {} - - void setValue(const value_t& val) - { - mValue.set(val); - } - - const value_t& getValue() const - { - return mValue.get().getValue(); - } - - value_t& getValue() - { - return mValue.get().getValue(); - } - - bool deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack_range, bool new_name) - { - return mValue.get().deserializeBlock(p, name_stack_range, new_name); - } - - bool serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const self_t* diff_block = NULL) const - { - if (mValue.empty()) return false; - - const BaseBlock* base_block = (diff_block && !diff_block->mValue.empty()) - ? &(diff_block->mValue.get().getValue()) - : NULL; - return mValue.get().serializeBlock(p, name_stack, predicate_rule, base_block); - } - - bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const - { - return mValue.get().inspectBlock(p, name_stack, min_count, max_count); - } - - bool mergeBlockParam(bool source_provided, bool dst_provided, BlockDescriptor& block_data, const self_t& source, bool overwrite) - { - return source.mValue.empty() || mValue.get().mergeBlock(block_data, source.getValue(), overwrite); - } - - bool validateBlock(bool emit_errors = true) const - { - return mValue.empty() || mValue.get().validateBlock(emit_errors); - } - - bool isValid() const - { - return validateBlock(false); - } - - static BlockDescriptor& getBlockDescriptor() - { - return value_t::getBlockDescriptor(); - } - - private: - LazyValue mValue; - }; - - template - class ParamValue , BLOCK_T> - { - typedef ParamValue , BLOCK_T> self_t; - - public: - typedef typename InnerMostType::value_t value_t; - typedef LazyValue default_value_t; - - ParamValue() - : mValue() - {} - - ParamValue(const default_value_t& other) - : mValue(other) - {} - - ParamValue(const T& value) - : mValue(value) - {} - - void setValue(const value_t& val) - { - mValue.set(val); - } - - const value_t& getValue() const - { - return mValue.get().getValue(); - } - - value_t& getValue() - { - return mValue.get().getValue(); - } - - bool isValid() const - { - return true; - } - - private: - LazyValue mValue; - }; - - template <> - class ParamValue - : public BaseBlock - { - public: - typedef LLSD value_t; - typedef LLSD default_value_t; - - ParamValue() - {} - - ParamValue(const default_value_t& other) - : mValue(other) - {} - - void setValue(const value_t& val) { mValue = val; } - - const value_t& getValue() const { return mValue; } - LLSD& getValue() { return mValue; } - - // block param interface - LL_COMMON_API bool deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack_range, bool new_name); - LL_COMMON_API bool serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const BaseBlock* diff_block = NULL) const; - bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const - { - //TODO: implement LLSD params as schema type Any - return true; - } - - private: - static void serializeElement(Parser& p, const LLSD& sd, Parser::name_stack_t& name_stack); - - LLSD mValue; - }; - - template - class CustomParamValue - : public Block > - { - public: - typedef enum e_value_age - { - VALUE_NEEDS_UPDATE, // mValue needs to be refreshed from the block parameters - VALUE_AUTHORITATIVE, // mValue holds the authoritative value (which has been replicated to the block parameters via updateBlockFromValue) - BLOCK_AUTHORITATIVE // mValue is derived from the block parameters, which are authoritative - } EValueAge; - - typedef TypeValues derived_t; - typedef CustomParamValue self_t; - typedef Block > block_t; - typedef T default_value_t; - typedef T value_t; - typedef void baseblock_base_class_t; - - - CustomParamValue(const default_value_t& value = T()) - : mValue(value), - mValueAge(VALUE_AUTHORITATIVE) - {} - - bool deserializeBlock(Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name) - { - derived_t& typed_param = static_cast(*this); - // try to parse direct value T - if (name_stack_range.first == name_stack_range.second) - { - if(parser.readValue(typed_param.mValue)) - { - typed_param.mValueAge = VALUE_AUTHORITATIVE; - typed_param.updateBlockFromValue(false); - - return true; - } - } - - // fall back on parsing block components for T - return typed_param.BaseBlock::deserializeBlock(parser, name_stack_range, new_name); - } - - bool serializeBlock(Parser& parser, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const BaseBlock* diff_block = NULL) const - { - const derived_t& typed_param = static_cast(*this); - const derived_t* diff_param = static_cast(diff_block); - - //std::string key = typed_param.getValueName(); - - //// first try to write out name of name/value pair - //if (!key.empty()) - //{ - // if (!diff_param || !ParamCompare::equals(diff_param->getValueName(), key)) - // { - // return parser.writeValue(key, name_stack); - // } - //} - // then try to serialize value directly - if (!diff_param || !ParamCompare::equals(typed_param.getValue(), diff_param->getValue())) - { - - if (parser.writeValue(typed_param.getValue(), name_stack)) - { - return true; - } - else - { - //RN: *always* serialize provided components of BlockValue (don't pass diff_param on), - // since these tend to be viewed as the constructor arguments for the value T. It seems - // cleaner to treat the uniqueness of a BlockValue according to the generated value, and - // not the individual components. This way will not - // be exported as , since it was probably the intent of the user to - // be specific about the RGB color values. This also fixes an issue where we distinguish - // between rect.left not being provided and rect.left being explicitly set to 0 (same as default) - - if (typed_param.mValueAge == VALUE_AUTHORITATIVE) - { - // if the value is authoritative but the parser doesn't accept the value type - // go ahead and make a copy, and splat the value out to its component params - // and serialize those params - derived_t copy(typed_param); - copy.updateBlockFromValue(true); - return copy.block_t::serializeBlock(parser, name_stack, predicate_rule, NULL); - } - else - { - return block_t::serializeBlock(parser, name_stack, predicate_rule, NULL); - } - } - } - return false; - } - - bool validateBlock(bool emit_errors = true) const - { - if (mValueAge == VALUE_NEEDS_UPDATE) - { - if (block_t::validateBlock(emit_errors)) - { - // clear stale keyword associated with old value - mValueAge = BLOCK_AUTHORITATIVE; - static_cast(const_cast(this))->updateValueFromBlock(); - return true; - } - else - { - //block value incomplete, so not considered provided - // will attempt to revalidate on next call to isProvided() - return false; - } - } - else - { - // we have a valid value in hand - return true; - } - } - - // propagate change status up to enclosing block - /*virtual*/ void paramChanged(const Param& changed_param, bool user_provided) - { - BaseBlock::paramChanged(changed_param, user_provided); - if (user_provided) - { - // a parameter changed, so our value is out of date - mValueAge = VALUE_NEEDS_UPDATE; - } - } - - void setValue(const value_t& val) - { - // set param version number to be up to date, so we ignore block contents - mValueAge = VALUE_AUTHORITATIVE; - mValue = val; - static_cast(this)->updateBlockFromValue(false); - } - - const value_t& getValue() const - { - validateBlock(true); - return mValue; - } - - T& getValue() - { - validateBlock(true); - return mValue; - } - - protected: - - // use this from within updateValueFromBlock() to set the value without making it authoritative - void updateValue(const value_t& value) - { - mValue = value; - } - - bool mergeBlockParam(bool source_provided, bool dst_provided, BlockDescriptor& block_data, const BaseBlock& source, bool overwrite) - { - bool source_override = source_provided && (overwrite || !dst_provided); - - const derived_t& src_typed_param = static_cast(source); - - if (source_override && src_typed_param.mValueAge == VALUE_AUTHORITATIVE) - { - // copy value over - setValue(src_typed_param.getValue()); - return true; - } - // merge individual parameters into destination - if (mValueAge == VALUE_AUTHORITATIVE) - { - static_cast(this)->updateBlockFromValue(dst_provided); - } - return mergeBlock(block_data, source, overwrite); - } - - bool mergeBlock(BlockDescriptor& block_data, const BaseBlock& source, bool overwrite) - { - return block_t::mergeBlock(block_data, source, overwrite); - } - - private: - mutable T mValue; - mutable EValueAge mValueAge; - }; + + // empty default implementation of key cache + // leverages empty base class optimization + template + class TypeValues + : public ParamValue::value_t> + { + private: + struct Inaccessable{}; + public: + typedef std::map value_name_map_t; + typedef Inaccessable name_t; + typedef TypeValues type_value_t; + typedef ParamValue::value_t> param_value_t; + typedef typename param_value_t::value_t value_t; + + TypeValues(const typename param_value_t::value_t& val) + : param_value_t(val) + {} + + void setValueName(const std::string& key) {} + std::string getValueName() const { return ""; } + std::string calcValueName(const value_t& value) const { return ""; } + void clearValueName() const {} + + static bool getValueFromName(const std::string& name, value_t& value) + { + return false; + } + + static bool valueNamesExist() + { + return false; + } + + static std::vector* getPossibleValues() + { + return NULL; + } + + void assignNamedValue(const Inaccessable& name) + {} + + operator const value_t&() const + { + return param_value_t::getValue(); + } + + const value_t& operator()() const + { + return param_value_t::getValue(); + } + + static value_name_map_t* getValueNames() {return NULL;} + }; + + // helper class to implement name value lookups + // and caching of last used name + template , bool IS_SPECIALIZED = true > + class TypeValuesHelper + : public ParamValue::value_t> + { + typedef TypeValuesHelper self_t; + public: + typedef typename std::map value_name_map_t; + typedef std::string name_t; + typedef self_t type_value_t; + typedef ParamValue::value_t> param_value_t; + typedef typename param_value_t::value_t value_t; + + TypeValuesHelper(const typename param_value_t::value_t& val) + : param_value_t(val) + {} + + //TODO: cache key by index to save on param block size + void setValueName(const std::string& value_name) + { + mValueName = value_name; + } + + std::string getValueName() const + { + return mValueName; + } + + std::string calcValueName(const value_t& value) const + { + value_name_map_t* map = getValueNames(); + for (typename value_name_map_t::value_type& map_pair : *map) + { + if (ParamCompare::equals(map_pair.second, value)) + { + return map_pair.first; + } + } + + return ""; + } + + void clearValueName() const + { + mValueName.clear(); + } + + static bool getValueFromName(const std::string& name, value_t& value) + { + value_name_map_t* map = getValueNames(); + typename value_name_map_t::iterator found_it = map->find(name); + if (found_it == map->end()) return false; + + value = found_it->second; + return true; + } + + static bool valueNamesExist() + { + return !getValueNames()->empty(); + } + + static value_name_map_t* getValueNames() + { + static value_name_map_t sMap; + static bool sInitialized = false; + + if (!sInitialized) + { + sInitialized = true; + DERIVED_TYPE::declareValues(); + } + return &sMap; + } + + static std::vector* getPossibleValues() + { + static std::vector sValues; + + value_name_map_t* map = getValueNames(); + for (typename value_name_map_t::value_type& map_pair : *map) + { + sValues.push_back(map_pair.first); + } + return &sValues; + } + + static void declare(const std::string& name, const value_t& value) + { + (*getValueNames())[name] = value; + } + + void operator ()(const std::string& name) + { + *this = name; + } + + void assignNamedValue(const std::string& name) + { + if (getValueFromName(name, param_value_t::getValue())) + { + setValueName(name); + } + } + + operator const value_t&() const + { + return param_value_t::getValue(); + } + + const value_t& operator()() const + { + return param_value_t::getValue(); + } + + protected: + static void getName(const std::string& name, const value_t& value) + {} + + mutable std::string mValueName; + }; + + // string types can support custom named values, but need + // to disambiguate in code between a string that is a named value + // and a string that is a name + template + class TypeValuesHelper + : public TypeValuesHelper + { + public: + typedef TypeValuesHelper self_t; + typedef TypeValuesHelper base_t; + typedef std::string value_t; + typedef std::string name_t; + typedef self_t type_value_t; + + TypeValuesHelper(const std::string& val) + : base_t(val) + {} + + void operator ()(const std::string& name) + { + *this = name; + } + + self_t& operator =(const std::string& name) + { + if (base_t::getValueFromName(name, ParamValue::getValue())) + { + base_t::setValueName(name); + } + else + { + ParamValue::setValue(name); + } + return *this; + } + + operator const value_t&() const + { + return ParamValue::getValue(); + } + + const value_t& operator()() const + { + return ParamValue::getValue(); + } + + }; + + // parser base class with mechanisms for registering readers/writers/inspectors of different types + class LL_COMMON_API Parser + { + LOG_CLASS(Parser); + public: + typedef std::vector > name_stack_t; + typedef std::pair name_stack_range_t; + typedef std::vector possible_values_t; + + typedef bool (*parser_read_func_t)(Parser& parser, void* output); + typedef bool (*parser_write_func_t)(Parser& parser, const void*, name_stack_t&); + typedef boost::function parser_inspect_func_t; + + typedef std::map parser_read_func_map_t; + typedef std::map parser_write_func_map_t; + typedef std::map parser_inspect_func_map_t; + + public: + + Parser(parser_read_func_map_t& read_map, parser_write_func_map_t& write_map, parser_inspect_func_map_t& inspect_map) + : mParseSilently(false), + mParserReadFuncs(&read_map), + mParserWriteFuncs(&write_map), + mParserInspectFuncs(&inspect_map) + {} + + virtual ~Parser(); + + template bool readValue(T& param, typename boost::disable_if >::type* dummy = 0) + { + parser_read_func_map_t::iterator found_it = mParserReadFuncs->find(&typeid(T)); + if (found_it != mParserReadFuncs->end()) + { + return found_it->second(*this, (void*)¶m); + } + + return false; + } + + template bool readValue(T& param, typename boost::enable_if >::type* dummy = 0) + { + parser_read_func_map_t::iterator found_it = mParserReadFuncs->find(&typeid(T)); + if (found_it != mParserReadFuncs->end()) + { + return found_it->second(*this, (void*)¶m); + } + else + { + found_it = mParserReadFuncs->find(&typeid(S32)); + if (found_it != mParserReadFuncs->end()) + { + S32 int_value; + bool parsed = found_it->second(*this, (void*)&int_value); + param = (T)int_value; + return parsed; + } + } + return false; + } + + template bool writeValue(const T& param, name_stack_t& name_stack) + { + parser_write_func_map_t::iterator found_it = mParserWriteFuncs->find(&typeid(T)); + if (found_it != mParserWriteFuncs->end()) + { + return found_it->second(*this, (const void*)¶m, name_stack); + } + return false; + } + + // dispatch inspection to registered inspection functions, for each parameter in a param block + template bool inspectValue(name_stack_t& name_stack, S32 min_count, S32 max_count, const possible_values_t* possible_values) + { + parser_inspect_func_map_t::iterator found_it = mParserInspectFuncs->find(&typeid(T)); + if (found_it != mParserInspectFuncs->end()) + { + found_it->second(name_stack, min_count, max_count, possible_values); + return true; + } + return false; + } + + virtual std::string getCurrentElementName() = 0; + virtual std::string getCurrentFileName() = 0; + virtual void parserWarning(const std::string& message); + virtual void parserError(const std::string& message); + void setParseSilently(bool silent) { mParseSilently = silent; } + + protected: + template + void registerParserFuncs(parser_read_func_t read_func, parser_write_func_t write_func = NULL) + { + mParserReadFuncs->insert(std::make_pair(&typeid(T), read_func)); + mParserWriteFuncs->insert(std::make_pair(&typeid(T), write_func)); + } + + template + void registerInspectFunc(parser_inspect_func_t inspect_func) + { + mParserInspectFuncs->insert(std::make_pair(&typeid(T), inspect_func)); + } + + bool mParseSilently; + + private: + parser_read_func_map_t* mParserReadFuncs; + parser_write_func_map_t* mParserWriteFuncs; + parser_inspect_func_map_t* mParserInspectFuncs; + }; + + class Param; + + enum ESerializePredicates + { + PROVIDED, + REQUIRED, + VALID, + HAS_DEFAULT_VALUE, + EMPTY + }; + + typedef LLPredicate::Rule predicate_rule_t; + + predicate_rule_t default_parse_rules(); + + // various callbacks and constraints associated with an individual param + struct LL_COMMON_API ParamDescriptor + { + struct UserData + { + virtual ~UserData() {} + }; + + typedef bool(*merge_func_t)(Param&, const Param&, bool); + typedef bool(*deserialize_func_t)(Param&, Parser&, Parser::name_stack_range_t&, bool); + typedef bool(*serialize_func_t)(const Param&, Parser&, Parser::name_stack_t&, const predicate_rule_t rules, const Param* diff_param); + typedef void(*inspect_func_t)(const Param&, Parser&, Parser::name_stack_t&, S32 min_count, S32 max_count); + typedef bool(*validation_func_t)(const Param*); + + ParamDescriptor(param_handle_t p, + merge_func_t merge_func, + deserialize_func_t deserialize_func, + serialize_func_t serialize_func, + validation_func_t validation_func, + inspect_func_t inspect_func, + S32 min_count, + S32 max_count); + + ParamDescriptor(); + ~ParamDescriptor(); + + param_handle_t mParamHandle; + merge_func_t mMergeFunc; + deserialize_func_t mDeserializeFunc; + serialize_func_t mSerializeFunc; + inspect_func_t mInspectFunc; + validation_func_t mValidationFunc; + S32 mMinCount; + S32 mMaxCount; + S32 mNumRefs; + UserData* mUserData; + }; + + typedef std::shared_ptr ParamDescriptorPtr; + + // each derived Block class keeps a static data structure maintaining offsets to various params + class LL_COMMON_API BlockDescriptor + { + public: + BlockDescriptor(); + + typedef enum e_initialization_state + { + UNINITIALIZED, + INITIALIZING, + INITIALIZED + } EInitializationState; + + void aggregateBlockData(BlockDescriptor& src_block_data); + void addParam(ParamDescriptorPtr param, const char* name); + + typedef boost::unordered_map param_map_t; + typedef std::vector param_list_t; + typedef std::list all_params_list_t; + typedef std::vector > param_validation_list_t; + + param_map_t mNamedParams; // parameters with associated names + param_list_t mUnnamedParams; // parameters with_out_ associated names + param_validation_list_t mValidationList; // parameters that must be validated + all_params_list_t mAllParams; // all parameters, owns descriptors + size_t mMaxParamOffset; + EInitializationState mInitializationState; // whether or not static block data has been initialized + class BaseBlock* mCurrentBlockPtr; // pointer to block currently being constructed + }; + + //TODO: implement in terms of owned_ptr + template + class LazyValue + { + public: + LazyValue() + : mPtr(NULL) + {} + + ~LazyValue() + { + delete mPtr; + } + + LazyValue(const T& value) + { + mPtr = new T(value); + } + + LazyValue(const LazyValue& other) + : mPtr(NULL) + { + *this = other; + } + + LazyValue& operator = (const LazyValue& other) + { + if (!other.mPtr) + { + delete mPtr; + mPtr = NULL; + } + else + { + if (!mPtr) + { + mPtr = new T(*other.mPtr); + } + else + { + *mPtr = *(other.mPtr); + } + } + return *this; + } + + bool operator==(const LazyValue& other) const + { + if (empty() || other.empty()) return false; + return *mPtr == *other.mPtr; + } + + bool empty() const + { + return mPtr == NULL; + } + + void set(const T& other) + { + if (!mPtr) + { + mPtr = new T(other); + } + else + { + *mPtr = other; + } + } + + const T& get() const + { + return *ensureInstance(); + } + + T& get() + { + return *ensureInstance(); + } + + operator const T&() const + { + return get(); + } + + private: + // lazily allocate an instance of T + T* ensureInstance() const + { + if (mPtr == NULL) + { + mPtr = new T(); + } + return mPtr; + } + + private: + + mutable T* mPtr; + }; + + // root class of all parameter blocks + + class LL_COMMON_API BaseBlock + { + public: + // lift block tags into baseblock namespace so derived classes do not need to qualify them + typedef LLInitParam::IS_A_BLOCK IS_A_BLOCK; + typedef LLInitParam::NOT_BLOCK NOT_A_BLOCK; + + template + struct Sequential : public LLTypeTags::TypeTagBase + { + template struct Cons { typedef Sequential > value_t; }; + template struct Cons > { typedef Sequential value_t; }; + }; + + template + struct Atomic : public LLTypeTags::TypeTagBase + { + template struct Cons { typedef Atomic > value_t; }; + template struct Cons > { typedef Atomic value_t; }; + }; + + template::value_t > + struct Lazy : public LLTypeTags::TypeTagBase + { + template struct Cons + { + typedef Lazy, BLOCK_T> value_t; + }; + template struct Cons > + { + typedef Lazy value_t; + }; + template struct Cons > + { + typedef Lazy value_t; + }; + }; + + // "Multiple" constraint types, put here in root class to avoid ambiguity during use + struct AnyAmount + { + enum { minCount = 0 }; + enum { maxCount = U32_MAX }; + }; + + template + struct AtLeast + { + enum { minCount = MIN_AMOUNT }; + enum { maxCount = U32_MAX }; + }; + + template + struct AtMost + { + enum { minCount = 0 }; + enum { maxCount = MAX_AMOUNT }; + }; + + template + struct Between + { + enum { minCount = MIN_AMOUNT }; + enum { maxCount = MAX_AMOUNT }; + }; + + template + struct Exactly + { + enum { minCount = EXACT_COUNT }; + enum { maxCount = EXACT_COUNT }; + }; + + // this typedef identifies derived classes as being blocks + typedef void baseblock_base_class_t; + LOG_CLASS(BaseBlock); + friend class Param; + + BaseBlock() + : mValidated(false), + mParamProvided(false) + {} + + virtual ~BaseBlock() {} + bool submitValue(Parser::name_stack_t& name_stack, Parser& p, bool silent=false); + + param_handle_t getHandleFromParam(const Param* param) const; + bool validateBlock(bool emit_errors = true) const; + + bool isProvided() const + { + return mParamProvided; + } + + bool isValid() const + { + return validateBlock(false); + } + + + Param* getParamFromHandle(const param_handle_t param_handle) + { + if (param_handle == 0) return NULL; + + U8* baseblock_address = reinterpret_cast(this); + return reinterpret_cast(baseblock_address + param_handle); + } + + const Param* getParamFromHandle(const param_handle_t param_handle) const + { + const U8* baseblock_address = reinterpret_cast(this); + return reinterpret_cast(baseblock_address + param_handle); + } + + void addSynonym(Param& param, const std::string& synonym); + + // Blocks can override this to do custom tracking of changes + virtual void paramChanged(const Param& changed_param, bool user_provided) + { + if (user_provided) + { + // a child param has been explicitly changed + // so *some* aspect of this block is now provided + mValidated = false; + mParamProvided = true; + } + } + + bool deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack_range, bool new_name); + bool serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const predicate_rule_t rule, const BaseBlock* diff_block = NULL) const; + bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const; + + virtual const BlockDescriptor& mostDerivedBlockDescriptor() const { return getBlockDescriptor(); } + virtual BlockDescriptor& mostDerivedBlockDescriptor() { return getBlockDescriptor(); } + + // take all provided params from other and apply to self + bool overwriteFrom(const BaseBlock& other) + { + return false; + } + + // take all provided params that are not already provided, and apply to self + bool fillFrom(const BaseBlock& other) + { + return false; + } + + ParamDescriptorPtr findParamDescriptor(const Param& param); + + // take all provided params from other and apply to self + bool mergeBlock(BlockDescriptor& block_data, const BaseBlock& other, bool overwrite); + + static BlockDescriptor& getBlockDescriptor() + { + static BlockDescriptor sBlockDescriptor; + return sBlockDescriptor; + } + + protected: + void init(BlockDescriptor& descriptor, BlockDescriptor& base_descriptor, size_t block_size); + + + bool mergeBlockParam(bool source_provided, bool dst_provided, BlockDescriptor& block_data, const BaseBlock& source, bool overwrite) + { + return mergeBlock(block_data, source, overwrite); + } + + mutable bool mValidated; // lazy validation flag + bool mParamProvided; + + private: + const std::string& getParamName(const BlockDescriptor& block_data, const Param* paramp) const; + }; + + class LL_COMMON_API Param + { + public: + void setProvided(bool is_provided = true) + { + mIsProvided = is_provided; + enclosingBlock().paramChanged(*this, is_provided); + } + + Param& operator =(const Param& other) + { + mIsProvided = other.mIsProvided; + // don't change mEnclosingblockoffset + return *this; + } + protected: + + bool anyProvided() const { return mIsProvided; } + + Param(BaseBlock* enclosing_block); + + // store pointer to enclosing block as offset to reduce space and allow for quick copying + BaseBlock& enclosingBlock() const + { + const U8* my_addr = reinterpret_cast(this); + // get address of enclosing BLOCK class using stored offset to enclosing BaseBlock class + return *const_cast + (reinterpret_cast + (my_addr - (ptrdiff_t)getEnclosingBlockOffset())); + } + + U32 getEnclosingBlockOffset() const + { + return ((U32)mEnclosingBlockOffsetHigh << 16) | (U32)mEnclosingBlockOffsetLow; + } + + private: + friend class BaseBlock; + + //24 bits for member offset field and 1 bit for provided flag + U16 mEnclosingBlockOffsetLow; + U8 mEnclosingBlockOffsetHigh:7; + U8 mIsProvided:1; + + }; + + template > + struct ParamIterator + { + typedef typename std::vector::const_iterator const_iterator; + typedef typename std::vector::iterator iterator; + }; + + // wrapper for parameter with a known type + // specialized to handle 4 cases: + // simple "scalar" value + // parameter that is itself a block + // multiple scalar values, stored in a vector + // multiple blocks, stored in a vector + template, + bool HAS_MULTIPLE_VALUES = false, + typename VALUE_IS_BLOCK = typename IsBlock::value_t> >::value_t> + class TypedParam + : public Param, + public NAME_VALUE_LOOKUP::type_value_t + { + protected: + typedef TypedParam self_t; + typedef ParamValue::value_t> param_value_t; + typedef typename param_value_t::default_value_t default_value_t; + typedef typename NAME_VALUE_LOOKUP::type_value_t named_value_t; + public: + typedef typename param_value_t::value_t value_t; + + using named_value_t::operator(); + + TypedParam(BlockDescriptor& block_descriptor, const char* name, const default_value_t& value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count) + : Param(block_descriptor.mCurrentBlockPtr), + named_value_t(value) + { + if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING)) + { + init(block_descriptor, validate_func, min_count, max_count, name); + } + } + + bool isProvided() const { return Param::anyProvided(); } + + bool isValid() const { return true; } + + static bool deserializeParam(Param& param, Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name) + { + self_t& typed_param = static_cast(param); + // no further names in stack, attempt to parse value now + if (name_stack_range.first == name_stack_range.second) + { + std::string name; + + // try to parse a known named value + if(named_value_t::valueNamesExist() + && parser.readValue(name) + && named_value_t::getValueFromName(name, typed_param.getValue())) + { + typed_param.setValueName(name); + typed_param.setProvided(); + return true; + } + // try to read value directly + else if (parser.readValue(typed_param.getValue())) + { + typed_param.clearValueName(); + typed_param.setProvided(); + return true; + } + } + return false; + } + + static bool serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const Param* diff_param) + { + bool serialized = false; + const self_t& typed_param = static_cast(param); + const self_t* diff_typed_param = static_cast(diff_param); + + LLPredicate::Value predicate; + if (diff_typed_param && ParamCompare::equals(typed_param.getValue(), diff_typed_param->getValue())) + { + predicate.set(HAS_DEFAULT_VALUE); + } + + predicate.set(VALID, typed_param.isValid()); + predicate.set(PROVIDED, typed_param.anyProvided()); + predicate.set(EMPTY, false); + + if (!predicate_rule.check(predicate)) return false; + + if (!name_stack.empty()) + { + name_stack.back().second = true; + } + + std::string key = typed_param.getValueName(); + + // first try to write out name of name/value pair + + if (!key.empty()) + { + if (!diff_typed_param || !ParamCompare::equals(diff_typed_param->getValueName(), key)) + { + serialized = parser.writeValue(key, name_stack); + } + } + // then try to serialize value directly + else if (!diff_typed_param || ParamCompare::equals(typed_param.getValue(), diff_typed_param->getValue())) + { + serialized = parser.writeValue(typed_param.getValue(), name_stack); + if (!serialized) + { + std::string calculated_key = typed_param.calcValueName(typed_param.getValue()); + if (calculated_key.size() + && (!diff_typed_param + || !ParamCompare::equals(static_cast(diff_param)->getValueName(), calculated_key))) + { + serialized = parser.writeValue(calculated_key, name_stack); + } + } + } + return serialized; + } + + static void inspectParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, S32 min_count, S32 max_count) + { + // tell parser about our actual type + parser.inspectValue(name_stack, min_count, max_count, NULL); + // then tell it about string-based alternatives ("red", "blue", etc. for LLColor4) + if (named_value_t::getPossibleValues()) + { + parser.inspectValue(name_stack, min_count, max_count, named_value_t::getPossibleValues()); + } + } + + void set(const value_t& val, bool flag_as_provided = true) + { + named_value_t::clearValueName(); + named_value_t::setValue(val); + setProvided(flag_as_provided); + } + + self_t& operator =(const typename named_value_t::name_t& name) + { + named_value_t::assignNamedValue(name); + return *this; + } + + protected: + + self_t& operator =(const self_t& other) + { + param_value_t::operator =(other); + Param::operator =(other); + return *this; + } + + static bool mergeWith(Param& dst, const Param& src, bool overwrite) + { + const self_t& src_typed_param = static_cast(src); + self_t& dst_typed_param = static_cast(dst); + + if (src_typed_param.isProvided() + && (overwrite || !dst_typed_param.isProvided())) + { + dst_typed_param.set(src_typed_param.getValue()); + return true; + } + return false; + } + private: + void init( BlockDescriptor &block_descriptor, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count, const char* name ) + { + ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor( + block_descriptor.mCurrentBlockPtr->getHandleFromParam(this), + &mergeWith, + &deserializeParam, + &serializeParam, + validate_func, + &inspectParam, + min_count, max_count)); + block_descriptor.addParam(param_descriptor, name); + } + }; + + // parameter that is a block + template + class TypedParam + : public Param, + public NAME_VALUE_LOOKUP::type_value_t + { + protected: + typedef ParamValue::value_t> param_value_t; + typedef typename param_value_t::default_value_t default_value_t; + typedef TypedParam self_t; + typedef typename NAME_VALUE_LOOKUP::type_value_t named_value_t; + public: + using named_value_t::operator(); + typedef typename param_value_t::value_t value_t; + + TypedParam(BlockDescriptor& block_descriptor, const char* name, const default_value_t& value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count) + : Param(block_descriptor.mCurrentBlockPtr), + named_value_t(value) + { + if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING)) + { + init(block_descriptor, validate_func, min_count, max_count, name); + } + } + + static bool deserializeParam(Param& param, Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name) + { + self_t& typed_param = static_cast(param); + + if (name_stack_range.first == name_stack_range.second) + { // try to parse a known named value + std::string name; + + if(named_value_t::valueNamesExist() + && parser.readValue(name) + && named_value_t::getValueFromName(name, typed_param.getValue())) + { + typed_param.setValueName(name); + typed_param.setProvided(); + return true; + } + } + + if(typed_param.deserializeBlock(parser, name_stack_range, new_name)) + { // attempt to parse block... + typed_param.clearValueName(); + typed_param.setProvided(); + return true; + } + + + return false; + } + + static bool serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const Param* diff_param) + { + const self_t& typed_param = static_cast(param); + + LLPredicate::Value predicate; + + predicate.set(VALID, typed_param.isValid()); + predicate.set(PROVIDED, typed_param.anyProvided()); + + if (!predicate_rule.check(predicate)) return false; + + if (!name_stack.empty()) + { + name_stack.back().second = true; + } + + std::string key = typed_param.getValueName(); + if (!key.empty()) + { + if (!diff_param || !ParamCompare::equals(static_cast(diff_param)->getValueName(), key)) + { + parser.writeValue(key, name_stack); + return true; + } + } + else + { + return typed_param.serializeBlock(parser, name_stack, predicate_rule, static_cast(diff_param)); + } + + return false; + } + + static void inspectParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, S32 min_count, S32 max_count) + { + const self_t& typed_param = static_cast(param); + + // tell parser about our actual type + parser.inspectValue(name_stack, min_count, max_count, NULL); + // then tell it about string-based alternatives ("red", "blue", etc. for LLColor4) + if (named_value_t::getPossibleValues()) + { + parser.inspectValue(name_stack, min_count, max_count, named_value_t::getPossibleValues()); + } + + typed_param.inspectBlock(parser, name_stack, min_count, max_count); + } + + // a param-that-is-a-block is provided when the user has set one of its child params + // *and* the block as a whole validates + bool isProvided() const + { + return Param::anyProvided() && isValid(); + } + + bool isValid() const + { + return param_value_t::isValid(); + } + + // assign block contents to this param-that-is-a-block + void set(const value_t& val, bool flag_as_provided = true) + { + named_value_t::setValue(val); + named_value_t::clearValueName(); + setProvided(flag_as_provided); + } + + self_t& operator =(const typename named_value_t::name_t& name) + { + named_value_t::assignNamedValue(name); + return *this; + } + + // propagate changed status up to enclosing block + /*virtual*/ void paramChanged(const Param& changed_param, bool user_provided) + { + param_value_t::paramChanged(changed_param, user_provided); + + if (user_provided) + { + setProvided(); + named_value_t::clearValueName(); + } + else + { + Param::enclosingBlock().paramChanged(*this, user_provided); + } + } + + protected: + + self_t& operator =(const self_t& other) + { + param_value_t::operator =(other); + Param::operator =(other); + return *this; + } + + static bool mergeWith(Param& dst, const Param& src, bool overwrite) + { + const self_t& src_typed_param = static_cast(src); + self_t& dst_typed_param = static_cast(dst); + + if (src_typed_param.anyProvided()) + { + if (dst_typed_param.mergeBlockParam(src_typed_param.isProvided(), dst_typed_param.isProvided(), param_value_t::getBlockDescriptor(), src_typed_param, overwrite)) + { + dst_typed_param.clearValueName(); + dst_typed_param.setProvided(true); + return true; + } + } + return false; + } + + private: + void init( BlockDescriptor &block_descriptor, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count, const char* name ) + { + ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor( + block_descriptor.mCurrentBlockPtr->getHandleFromParam(this), + &mergeWith, + &deserializeParam, + &serializeParam, + validate_func, + &inspectParam, + min_count, max_count)); + block_descriptor.addParam(param_descriptor, name); + } + }; + + // list of non-block parameters + template + class TypedParam + : public Param + { + protected: + typedef TypedParam self_t; + typedef ParamValue::value_t> param_value_t; + typedef typename std::vector container_t; + typedef container_t default_value_t; + typedef typename NAME_VALUE_LOOKUP::type_value_t named_value_t; + + public: + typedef typename param_value_t::value_t value_t; + + TypedParam(BlockDescriptor& block_descriptor, const char* name, const default_value_t& value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count) + : Param(block_descriptor.mCurrentBlockPtr), + mMinCount(min_count), + mMaxCount(max_count) + { + std::copy(value.begin(), value.end(), std::back_inserter(mValues)); + + if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING)) + { + init(block_descriptor, validate_func, min_count, max_count, name); + + } + } + + bool isProvided() const { return Param::anyProvided() && isValid(); } + + bool isValid() const + { + size_t num_elements = numValidElements(); + return mMinCount < num_elements && num_elements < mMaxCount; + } + + static bool deserializeParam(Param& param, Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name) + { + Parser::name_stack_range_t new_name_stack_range(name_stack_range); + self_t& typed_param = static_cast(param); + value_t value; + + // pop first element if empty string + if (new_name_stack_range.first != new_name_stack_range.second && new_name_stack_range.first->first.empty()) + { + ++new_name_stack_range.first; + } + + // no further names in stack, attempt to parse value now + if (new_name_stack_range.first == new_name_stack_range.second) + { + std::string name; + + // try to parse a known named value + if(named_value_t::valueNamesExist() + && parser.readValue(name) + && named_value_t::getValueFromName(name, value)) + { + typed_param.add(value); + typed_param.mValues.back().setValueName(name); + return true; + } + else if (parser.readValue(value)) // attempt to read value directly + { + typed_param.add(value); + return true; + } + } + return false; + } + + static bool serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const Param* diff_param) + { + bool serialized = false; + const self_t& typed_param = static_cast(param); + + LLPredicate::Value predicate; + + predicate.set(REQUIRED, typed_param.mMinCount > 0); + predicate.set(VALID, typed_param.isValid()); + predicate.set(PROVIDED, typed_param.anyProvided()); + predicate.set(EMPTY, typed_param.mValues.empty()); + + if (!predicate_rule.check(predicate)) return false; + + for (const_iterator it = typed_param.mValues.begin(), end_it = typed_param.mValues.end(); + it != end_it; + ++it) + { + std::string key = it->getValueName(); + name_stack.push_back(std::make_pair(std::string(), true)); + + if(key.empty()) + // not parsed via name values, write out value directly + { + bool value_written = parser.writeValue(*it, name_stack); + if (!value_written) + { + std::string calculated_key = it->calcValueName(it->getValue()); + if (parser.writeValue(calculated_key, name_stack)) + { + serialized = true; + } + else + { + break; + } + } + } + else + { + if(parser.writeValue(key, name_stack)) + { + serialized = true; + } + else + { + break; + } + } + } + + return serialized; + } + + static void inspectParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, S32 min_count, S32 max_count) + { + parser.inspectValue(name_stack, min_count, max_count, NULL); + if (named_value_t::getPossibleValues()) + { + parser.inspectValue(name_stack, min_count, max_count, named_value_t::getPossibleValues()); + } + } + + void set(const container_t& val, bool flag_as_provided = true) + { + mValues = val; + setProvided(flag_as_provided); + } + + param_value_t& add() + { + mValues.push_back(value_t()); + Param::setProvided(); + return mValues.back(); + } + + self_t& add(const value_t& item) + { + mValues.push_back(item); + setProvided(); + return *this; + } + + self_t& add(const typename named_value_t::name_t& name) + { + value_t value; + + // try to parse a per type named value + if (named_value_t::getValueFromName(name, value)) + { + add(value); + mValues.back().setValueName(name); + } + + return *this; + } + + // implicit conversion + operator const container_t&() const { return mValues; } + // explicit conversion + const container_t& operator()() const { return mValues; } + + typedef typename container_t::iterator iterator; + typedef typename container_t::const_iterator const_iterator; + iterator begin() { return mValues.begin(); } + iterator end() { return mValues.end(); } + const_iterator begin() const { return mValues.begin(); } + const_iterator end() const { return mValues.end(); } + bool empty() const { return mValues.empty(); } + size_t size() const { return mValues.size(); } + + size_t numValidElements() const + { + return mValues.size(); + } + + protected: + static bool mergeWith(Param& dst, const Param& src, bool overwrite) + { + const self_t& src_typed_param = static_cast(src); + self_t& dst_typed_param = static_cast(dst); + + if (overwrite) + { + std::copy(src_typed_param.begin(), src_typed_param.end(), std::back_inserter(dst_typed_param.mValues)); + } + else + { + container_t new_values(src_typed_param.mValues); + std::copy(dst_typed_param.begin(), dst_typed_param.end(), std::back_inserter(new_values)); + std::swap(dst_typed_param.mValues, new_values); + } + + if (src_typed_param.begin() != src_typed_param.end()) + { + dst_typed_param.setProvided(); + } + return true; + } + + container_t mValues; + size_t mMinCount, + mMaxCount; + + private: + void init( BlockDescriptor &block_descriptor, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count, const char* name ) + { + ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor( + block_descriptor.mCurrentBlockPtr->getHandleFromParam(this), + &mergeWith, + &deserializeParam, + &serializeParam, + validate_func, + &inspectParam, + min_count, max_count)); + block_descriptor.addParam(param_descriptor, name); + } + }; + + // list of block parameters + template + class TypedParam + : public Param + { + protected: + typedef TypedParam self_t; + typedef ParamValue::value_t> param_value_t; + typedef typename std::vector container_t; + typedef typename NAME_VALUE_LOOKUP::type_value_t named_value_t; + typedef container_t default_value_t; + typedef typename container_t::iterator iterator; + typedef typename container_t::const_iterator const_iterator; + public: + typedef typename param_value_t::value_t value_t; + + TypedParam(BlockDescriptor& block_descriptor, const char* name, const default_value_t& value, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count) + : Param(block_descriptor.mCurrentBlockPtr), + mMinCount(min_count), + mMaxCount(max_count) + { + std::copy(value.begin(), value.end(), back_inserter(mValues)); + + if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING)) + { + init(block_descriptor, validate_func, min_count, max_count, name); + } + } + + bool isProvided() const { return Param::anyProvided() && isValid(); } + + bool isValid() const + { + size_t num_elements = numValidElements(); + return mMinCount < num_elements && num_elements < mMaxCount; + } + + + static bool deserializeParam(Param& param, Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name) + { + Parser::name_stack_range_t new_name_stack_range(name_stack_range); + self_t& typed_param = static_cast(param); + bool new_value = false; + bool new_array_value = false; + + // pop first element if empty string + if (new_name_stack_range.first != new_name_stack_range.second && new_name_stack_range.first->first.empty()) + { + new_array_value = new_name_stack_range.first->second; + ++new_name_stack_range.first; + } + + if (new_name || new_array_value || typed_param.mValues.empty()) + { + new_value = true; + typed_param.mValues.push_back(value_t()); + } + param_value_t& value = typed_param.mValues.back(); + + if (new_name_stack_range.first == new_name_stack_range.second) + { // try to parse a known named value + std::string name; + + if(named_value_t::valueNamesExist() + && parser.readValue(name) + && named_value_t::getValueFromName(name, value.getValue())) + { + typed_param.mValues.back().setValueName(name); + typed_param.setProvided(); + if (new_array_value) + { + name_stack_range.first->second = false; + } + return true; + } + } + + // attempt to parse block... + if(value.deserializeBlock(parser, new_name_stack_range, new_name)) + { + typed_param.setProvided(); + if (new_array_value) + { + name_stack_range.first->second = false; + } + return true; + } + + + if (new_value) + { // failed to parse new value, pop it off + typed_param.mValues.pop_back(); + } + + return false; + } + + static bool serializeParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const Param* diff_param) + { + bool serialized = false; + const self_t& typed_param = static_cast(param); + LLPredicate::Value predicate; + + predicate.set(REQUIRED, typed_param.mMinCount > 0); + predicate.set(VALID, typed_param.isValid()); + predicate.set(PROVIDED, typed_param.anyProvided()); + predicate.set(EMPTY, typed_param.mValues.empty()); + + if (!predicate_rule.check(predicate)) return false; + + for (const_iterator it = typed_param.mValues.begin(), end_it = typed_param.mValues.end(); + it != end_it; + ++it) + { + name_stack.push_back(std::make_pair(std::string(), true)); + + std::string key = it->getValueName(); + if (!key.empty()) + { + serialized |= parser.writeValue(key, name_stack); + } + // Not parsed via named values, write out value directly + // NOTE: currently we don't do diffing of Multiples + else + { + serialized = it->serializeBlock(parser, name_stack, predicate_rule, NULL); + } + + name_stack.pop_back(); + } + + if (!serialized && predicate_rule.check(ll_make_predicate(EMPTY))) + { + serialized |= parser.writeValue(Flag(), name_stack); + } + + return serialized; + } + + static void inspectParam(const Param& param, Parser& parser, Parser::name_stack_t& name_stack, S32 min_count, S32 max_count) + { + const param_value_t& value_param = param_value_t(value_t()); + + // tell parser about our actual type + parser.inspectValue(name_stack, min_count, max_count, NULL); + // then tell it about string-based alternatives ("red", "blue", etc. for LLColor4) + if (named_value_t::getPossibleValues()) + { + parser.inspectValue(name_stack, min_count, max_count, named_value_t::getPossibleValues()); + } + + value_param.inspectBlock(parser, name_stack, min_count, max_count); + } + + void set(const container_t& val, bool flag_as_provided = true) + { + mValues = val; + setProvided(flag_as_provided); + } + + param_value_t& add() + { + mValues.push_back(value_t()); + setProvided(); + return mValues.back(); + } + + self_t& add(const value_t& item) + { + mValues.push_back(item); + setProvided(); + return *this; + } + + self_t& add(const typename named_value_t::name_t& name) + { + value_t value; + + // try to parse a per type named value + if (named_value_t::getValueFromName(name, value)) + { + add(value); + mValues.back().setValueName(name); + } + return *this; + } + + // implicit conversion + operator const container_t&() const { return mValues; } + // explicit conversion + const container_t& operator()() const { return mValues; } + + iterator begin() { return mValues.begin(); } + iterator end() { return mValues.end(); } + const_iterator begin() const { return mValues.begin(); } + const_iterator end() const { return mValues.end(); } + bool empty() const { return mValues.empty(); } + size_t size() const { return mValues.size(); } + + size_t numValidElements() const + { + size_t count = 0; + for (const_iterator it = mValues.begin(), end_it = mValues.end(); + it != end_it; + ++it) + { + if(it->isValid()) count++; + } + return count; + } + + protected: + + static bool mergeWith(Param& dst, const Param& src, bool overwrite) + { + const self_t& src_typed_param = static_cast(src); + self_t& dst_typed_param = static_cast(dst); + + if (overwrite) + { + std::copy(src_typed_param.begin(), src_typed_param.end(), std::back_inserter(dst_typed_param.mValues)); + } + else + { + container_t new_values(src_typed_param.mValues); + std::copy(dst_typed_param.begin(), dst_typed_param.end(), std::back_inserter(new_values)); + std::swap(dst_typed_param.mValues, new_values); + } + + if (src_typed_param.begin() != src_typed_param.end()) + { + dst_typed_param.setProvided(); + } + + return true; + } + + container_t mValues; + size_t mMinCount, + mMaxCount; + + private: + void init( BlockDescriptor &block_descriptor, ParamDescriptor::validation_func_t validate_func, S32 min_count, S32 max_count, const char* name ) + { + ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor( + block_descriptor.mCurrentBlockPtr->getHandleFromParam(this), + &mergeWith, + &deserializeParam, + &serializeParam, + validate_func, + &inspectParam, + min_count, max_count)); + block_descriptor.addParam(param_descriptor, name); + } + }; + + template + class ChoiceBlock : public BASE_BLOCK + { + typedef ChoiceBlock self_t; + typedef ChoiceBlock enclosing_block_t; + typedef BASE_BLOCK base_block_t; + + LOG_CLASS(self_t); + public: + // take all provided params from other and apply to self + bool overwriteFrom(const self_t& other) + { + return static_cast(this)->mergeBlock(getBlockDescriptor(), other, true); + } + + // take all provided params that are not already provided, and apply to self + bool fillFrom(const self_t& other) + { + return static_cast(this)->mergeBlock(getBlockDescriptor(), other, false); + } + + bool mergeBlockParam(bool source_provided, bool dest_provided, BlockDescriptor& block_data, const self_t& source, bool overwrite) + { + bool source_override = source_provided && (overwrite || !dest_provided); + + if (source_override || source.mCurChoice == mCurChoice) + { + return mergeBlock(block_data, source, overwrite); + } + return false; + } + + // merge with other block + bool mergeBlock(BlockDescriptor& block_data, const self_t& other, bool overwrite) + { + mCurChoice = other.mCurChoice; + return base_block_t::mergeBlock(getBlockDescriptor(), other, overwrite); + } + + // clear out old choice when param has changed + /*virtual*/ void paramChanged(const Param& changed_param, bool user_provided) + { + param_handle_t changed_param_handle = base_block_t::getHandleFromParam(&changed_param); + // if we have a new choice... + if (changed_param_handle != mCurChoice) + { + // clear provided flag on previous choice + Param* previous_choice = base_block_t::getParamFromHandle(mCurChoice); + if (previous_choice) + { + previous_choice->setProvided(false); + } + mCurChoice = changed_param_handle; + } + base_block_t::paramChanged(changed_param, user_provided); + } + + virtual const BlockDescriptor& mostDerivedBlockDescriptor() const { return getBlockDescriptor(); } + virtual BlockDescriptor& mostDerivedBlockDescriptor() { return getBlockDescriptor(); } + + protected: + ChoiceBlock() + : mCurChoice(0) + { + BaseBlock::init(getBlockDescriptor(), base_block_t::getBlockDescriptor(), sizeof(DERIVED_BLOCK)); + } + + // Alternatives are mutually exclusive wrt other Alternatives in the same block. + // One alternative in a block will always have isChosen() == true. + // At most one alternative in a block will have isProvided() == true. + template ::type_value_t > + class Alternative : public TypedParam + { + typedef TypedParam super_t; + typedef typename super_t::value_t value_t; + typedef typename super_t::default_value_t default_value_t; + + public: + friend class ChoiceBlock; + + using super_t::operator =; + + explicit Alternative(const char* name = "", const default_value_t& val = defaultValue()) + : super_t(DERIVED_BLOCK::getBlockDescriptor(), name, val, NULL, 0, 1), + mOriginalValue(val) + { + // assign initial choice to first declared option + DERIVED_BLOCK* blockp = ((DERIVED_BLOCK*)DERIVED_BLOCK::getBlockDescriptor().mCurrentBlockPtr); + if (LL_UNLIKELY(DERIVED_BLOCK::getBlockDescriptor().mInitializationState == BlockDescriptor::INITIALIZING)) + { + if(blockp->mCurChoice == 0) + { + blockp->mCurChoice = Param::enclosingBlock().getHandleFromParam(this); + } + } + } + + void choose() + { + static_cast(Param::enclosingBlock()).paramChanged(*this, true); + } + + void chooseAs(const value_t& val) + { + super_t::set(val); + } + + void operator =(const value_t& val) + { + super_t::set(val); + } + + void operator()(const value_t& val) + { + super_t::set(val); + } + + operator const value_t&() const + { + return (*this)(); + } + + const value_t& operator()() const + { + if (static_cast(Param::enclosingBlock()).getCurrentChoice() == this) + { + return super_t::getValue(); + } + return mOriginalValue; + } + + bool isChosen() const + { + return static_cast(Param::enclosingBlock()).getCurrentChoice() == this; + } + + private: + default_value_t mOriginalValue; + }; + + public: + static BlockDescriptor& getBlockDescriptor() + { + static BlockDescriptor sBlockDescriptor; + return sBlockDescriptor; + } + + private: + param_handle_t mCurChoice; + + const Param* getCurrentChoice() const + { + return base_block_t::getParamFromHandle(mCurChoice); + } + }; + + template + class Block + : public BASE_BLOCK + { + typedef Block self_t; + + protected: + typedef Block block_t; + + public: + typedef BASE_BLOCK base_block_t; + + // take all provided params from other and apply to self + bool overwriteFrom(const self_t& other) + { + return static_cast(this)->mergeBlock(getBlockDescriptor(), other, true); + } + + // take all provided params that are not already provided, and apply to self + bool fillFrom(const self_t& other) + { + return static_cast(this)->mergeBlock(getBlockDescriptor(), other, false); + } + + virtual const BlockDescriptor& mostDerivedBlockDescriptor() const { return getBlockDescriptor(); } + virtual BlockDescriptor& mostDerivedBlockDescriptor() { return getBlockDescriptor(); } + + protected: + Block() + { + //#pragma message("Parsing LLInitParam::Block") + BaseBlock::init(getBlockDescriptor(), BASE_BLOCK::getBlockDescriptor(), sizeof(DERIVED_BLOCK)); + } + + // + // Nested classes for declaring parameters + // + template ::type_value_t > + class Optional : public TypedParam + { + typedef TypedParam super_t; + typedef typename super_t::value_t value_t; + typedef typename super_t::default_value_t default_value_t; + + public: + using super_t::operator(); + using super_t::operator =; + + explicit Optional(const char* name = "", const default_value_t& val = defaultValue()) + : super_t(DERIVED_BLOCK::getBlockDescriptor(), name, val, NULL, 0, 1) + { + //#pragma message("Parsing LLInitParam::Block::Optional") + } + + Optional& operator =(const value_t& val) + { + super_t::set(val); + return *this; + } + + DERIVED_BLOCK& operator()(const value_t& val) + { + super_t::set(val); + return static_cast(Param::enclosingBlock()); + } + }; + + template ::type_value_t > + class Mandatory : public TypedParam + { + typedef TypedParam super_t; + typedef Mandatory self_t; + typedef typename super_t::value_t value_t; + typedef typename super_t::default_value_t default_value_t; + + public: + using super_t::operator(); + using super_t::operator =; + + // mandatory parameters require a name to be parseable + explicit Mandatory(const char* name = "", const default_value_t& val = defaultValue()) + : super_t(DERIVED_BLOCK::getBlockDescriptor(), name, val, &validate, 1, 1) + {} + + Mandatory& operator =(const value_t& val) + { + super_t::set(val); + return *this; + } + + DERIVED_BLOCK& operator()(const value_t& val) + { + super_t::set(val); + return static_cast(Param::enclosingBlock()); + } + + static bool validate(const Param* p) + { + // valid only if provided + return static_cast(p)->isProvided(); + } + + }; + + template ::type_value_t > + class Multiple : public TypedParam + { + typedef TypedParam super_t; + typedef Multiple self_t; + typedef typename super_t::container_t container_t; + typedef typename super_t::value_t value_t; + + public: + typedef typename super_t::iterator iterator; + typedef typename super_t::const_iterator const_iterator; + + using super_t::operator(); + using super_t::operator const container_t&; + + explicit Multiple(const char* name = "") + : super_t(DERIVED_BLOCK::getBlockDescriptor(), name, container_t(), &validate, RANGE::minCount, RANGE::maxCount) + {} + + Multiple& operator =(const container_t& val) + { + super_t::set(val); + return *this; + } + + DERIVED_BLOCK& operator()(const container_t& val) + { + super_t::set(val); + return static_cast(Param::enclosingBlock()); + } + + static bool validate(const Param* paramp) + { + size_t num_valid = ((super_t*)paramp)->numValidElements(); + return RANGE::minCount <= num_valid && num_valid <= RANGE::maxCount; + } + }; + + // can appear in data files, but will ignored during parsing + // cannot read or write in code + class Ignored : public Param + { + public: + explicit Ignored(const char* name) + : Param(DERIVED_BLOCK::getBlockDescriptor().mCurrentBlockPtr) + { + BlockDescriptor& block_descriptor = DERIVED_BLOCK::getBlockDescriptor(); + if (LL_UNLIKELY(block_descriptor.mInitializationState == BlockDescriptor::INITIALIZING)) + { + ParamDescriptorPtr param_descriptor = ParamDescriptorPtr(new ParamDescriptor( + block_descriptor.mCurrentBlockPtr->getHandleFromParam(this), + NULL, + &deserializeParam, + NULL, + NULL, + NULL, + 0, S32_MAX)); + block_descriptor.addParam(param_descriptor, name); + } + } + + static bool deserializeParam(Param& param, Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name) + { + if (name_stack_range.first == name_stack_range.second) + { + //std::string message = llformat("Deprecated value %s ignored", getName().c_str()); + //parser.parserWarning(message); + return true; + } + + return false; + } + }; + + // can appear in data files, or be written to in code, but data will be ignored + // cannot be read in code + class Deprecated : public Ignored + { + public: + explicit Deprecated(const char* name) : Ignored(name) {} + + // dummy writer interfaces + template + Deprecated& operator =(const T& val) + { + // do nothing + return *this; + } + + template + DERIVED_BLOCK& operator()(const T& val) + { + // do nothing + return static_cast(Param::enclosingBlock()); + } + + template + void set(const T& val, bool flag_as_provided = true) + { + // do nothing + } + }; + + public: + static BlockDescriptor& getBlockDescriptor() + { + static BlockDescriptor sBlockDescriptor; + return sBlockDescriptor; + } + + protected: + template + void changeDefault(TypedParam& param, + const typename TypedParam::value_t& value) + { + if (!param.isProvided()) + { + param.set(value, false); + } + } + + }; + + template + struct IsBlock, BLOCK_T >, void> + { + typedef IS_A_BLOCK value_t; + }; + + template + struct IsBlock, BLOCK_T >, void> + { + typedef NOT_BLOCK value_t; + }; + + template + struct IsBlock, typename IsBlock >::value_t >, BLOCK_IDENTIFIER> + { + typedef typename IsBlock::value_t value_t; + }; + + template + struct IsBlock, typename IsBlock >::value_t >, BLOCK_IDENTIFIER> + { + typedef typename IsBlock::value_t value_t; + }; + + + template + struct InnerMostType + { + typedef T value_t; + }; + + template + struct InnerMostType > + { + typedef typename InnerMostType::value_t value_t; + }; + + template + struct InnerMostType > + { + typedef typename InnerMostType::value_t value_t; + }; + + template + class ParamValue , BLOCK_T> + { + typedef ParamValue , BLOCK_T> self_t; + + public: + typedef typename InnerMostType::value_t value_t; + typedef T default_value_t; + + ParamValue() + : mValue() + {} + + ParamValue(const default_value_t& value) + : mValue(value) + {} + + void setValue(const value_t& val) + { + mValue.setValue(val); + } + + const value_t& getValue() const + { + return mValue.getValue(); + } + + value_t& getValue() + { + return mValue.getValue(); + } + + bool deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack_range, bool new_name) + { + if (new_name) + { + resetToDefault(); + } + return mValue.deserializeBlock(p, name_stack_range, new_name); + } + + bool serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const self_t* diff_block = NULL) const + { + const BaseBlock* base_block = diff_block + ? &(diff_block->mValue) + : NULL; + return mValue.serializeBlock(p, name_stack, predicate_rule, base_block); + } + + bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const + { + return mValue.inspectBlock(p, name_stack, min_count, max_count); + } + + bool mergeBlockParam(bool source_provided, bool dst_provided, BlockDescriptor& block_data, const self_t& source, bool overwrite) + { + if ((overwrite && source_provided) // new values coming in on top or... + || (!overwrite && !dst_provided)) // values being pushed under with nothing already there + { + // clear away what is there and take the new stuff as a whole + resetToDefault(); + return mValue.mergeBlock(block_data, source.getValue(), overwrite); + } + return mValue.mergeBlock(block_data, source.getValue(), overwrite); + } + + bool validateBlock(bool emit_errors = true) const + { + return mValue.validateBlock(emit_errors); + } + + bool isValid() const + { + return validateBlock(false); + } + + static BlockDescriptor& getBlockDescriptor() + { + return value_t::getBlockDescriptor(); + } + + + private: + void resetToDefault() + { + static T default_value; + mValue = default_value; + } + + T mValue; + }; + + template + class ParamValue , IS_A_BLOCK> + { + typedef ParamValue , IS_A_BLOCK> self_t; + + public: + typedef typename InnerMostType::value_t value_t; + typedef T default_value_t; + + ParamValue() + : mValue() + { + mCurParam = getBlockDescriptor().mAllParams.begin(); + } + + ParamValue(const default_value_t& value) + : mValue(value) + { + mCurParam = getBlockDescriptor().mAllParams.begin(); + } + + void setValue(const value_t& val) + { + mValue.setValue(val); + } + + const value_t& getValue() const + { + return mValue.getValue(); + } + + value_t& getValue() + { + return mValue.getValue(); + } + + bool deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack_range, bool new_name) + { + if (new_name) + { + mCurParam = getBlockDescriptor().mAllParams.begin(); + } + if (name_stack_range.first == name_stack_range.second + && mCurParam != getBlockDescriptor().mAllParams.end()) + { + // deserialize to mCurParam + ParamDescriptor& pd = *(*mCurParam); + ParamDescriptor::deserialize_func_t deserialize_func = pd.mDeserializeFunc; + Param* paramp = mValue.getParamFromHandle(pd.mParamHandle); + + if (deserialize_func + && paramp + && deserialize_func(*paramp, p, name_stack_range, new_name)) + { + ++mCurParam; + return true; + } + else + { + return false; + } + } + else + { + return mValue.deserializeBlock(p, name_stack_range, new_name); + } + } + + bool serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const self_t* diff_block = NULL) const + { + const BaseBlock* base_block = diff_block + ? &(diff_block->mValue) + : NULL; + return mValue.serializeBlock(p, name_stack, predicate_rule, base_block); + } + + bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const + { + return mValue.inspectBlock(p, name_stack, min_count, max_count); + } + + bool mergeBlockParam(bool source_provided, bool dst_provided, BlockDescriptor& block_data, const self_t& source, bool overwrite) + { + return mValue.mergeBlock(block_data, source.getValue(), overwrite); + } + + bool validateBlock(bool emit_errors = true) const + { + return mValue.validateBlock(emit_errors); + } + + bool isValid() const + { + return validateBlock(false); + } + + static BlockDescriptor& getBlockDescriptor() + { + return value_t::getBlockDescriptor(); + } + + private: + + BlockDescriptor::all_params_list_t::iterator mCurParam; + T mValue; + }; + + template + class ParamValue , NOT_BLOCK> + : public T + { + typedef ParamValue , NOT_BLOCK> self_t; + + public: + typedef typename InnerMostType::value_t value_t; + typedef T default_value_t; + + ParamValue() + : T() + {} + + ParamValue(const default_value_t& value) + : T(value.getValue()) + {} + + bool isValid() const { return true; } + }; + + template + class ParamValue , BLOCK_T> + { + typedef ParamValue , BLOCK_T> self_t; + + public: + typedef typename InnerMostType::value_t value_t; + typedef LazyValue default_value_t; + + ParamValue() + : mValue() + {} + + ParamValue(const default_value_t& other) + : mValue(other) + {} + + ParamValue(const T& value) + : mValue(value) + {} + + void setValue(const value_t& val) + { + mValue.set(val); + } + + const value_t& getValue() const + { + return mValue.get().getValue(); + } + + value_t& getValue() + { + return mValue.get().getValue(); + } + + bool deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack_range, bool new_name) + { + return mValue.get().deserializeBlock(p, name_stack_range, new_name); + } + + bool serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const self_t* diff_block = NULL) const + { + if (mValue.empty()) return false; + + const BaseBlock* base_block = (diff_block && !diff_block->mValue.empty()) + ? &(diff_block->mValue.get().getValue()) + : NULL; + return mValue.get().serializeBlock(p, name_stack, predicate_rule, base_block); + } + + bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const + { + return mValue.get().inspectBlock(p, name_stack, min_count, max_count); + } + + bool mergeBlockParam(bool source_provided, bool dst_provided, BlockDescriptor& block_data, const self_t& source, bool overwrite) + { + return source.mValue.empty() || mValue.get().mergeBlock(block_data, source.getValue(), overwrite); + } + + bool validateBlock(bool emit_errors = true) const + { + return mValue.empty() || mValue.get().validateBlock(emit_errors); + } + + bool isValid() const + { + return validateBlock(false); + } + + static BlockDescriptor& getBlockDescriptor() + { + return value_t::getBlockDescriptor(); + } + + private: + LazyValue mValue; + }; + + template + class ParamValue , BLOCK_T> + { + typedef ParamValue , BLOCK_T> self_t; + + public: + typedef typename InnerMostType::value_t value_t; + typedef LazyValue default_value_t; + + ParamValue() + : mValue() + {} + + ParamValue(const default_value_t& other) + : mValue(other) + {} + + ParamValue(const T& value) + : mValue(value) + {} + + void setValue(const value_t& val) + { + mValue.set(val); + } + + const value_t& getValue() const + { + return mValue.get().getValue(); + } + + value_t& getValue() + { + return mValue.get().getValue(); + } + + bool isValid() const + { + return true; + } + + private: + LazyValue mValue; + }; + + template <> + class ParamValue + : public BaseBlock + { + public: + typedef LLSD value_t; + typedef LLSD default_value_t; + + ParamValue() + {} + + ParamValue(const default_value_t& other) + : mValue(other) + {} + + void setValue(const value_t& val) { mValue = val; } + + const value_t& getValue() const { return mValue; } + LLSD& getValue() { return mValue; } + + // block param interface + LL_COMMON_API bool deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack_range, bool new_name); + LL_COMMON_API bool serializeBlock(Parser& p, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const BaseBlock* diff_block = NULL) const; + bool inspectBlock(Parser& p, Parser::name_stack_t name_stack = Parser::name_stack_t(), S32 min_count = 0, S32 max_count = S32_MAX) const + { + //TODO: implement LLSD params as schema type Any + return true; + } + + private: + static void serializeElement(Parser& p, const LLSD& sd, Parser::name_stack_t& name_stack); + + LLSD mValue; + }; + + template + class CustomParamValue + : public Block > + { + public: + typedef enum e_value_age + { + VALUE_NEEDS_UPDATE, // mValue needs to be refreshed from the block parameters + VALUE_AUTHORITATIVE, // mValue holds the authoritative value (which has been replicated to the block parameters via updateBlockFromValue) + BLOCK_AUTHORITATIVE // mValue is derived from the block parameters, which are authoritative + } EValueAge; + + typedef TypeValues derived_t; + typedef CustomParamValue self_t; + typedef Block > block_t; + typedef T default_value_t; + typedef T value_t; + typedef void baseblock_base_class_t; + + + CustomParamValue(const default_value_t& value = T()) + : mValue(value), + mValueAge(VALUE_AUTHORITATIVE) + {} + + bool deserializeBlock(Parser& parser, Parser::name_stack_range_t& name_stack_range, bool new_name) + { + derived_t& typed_param = static_cast(*this); + // try to parse direct value T + if (name_stack_range.first == name_stack_range.second) + { + if(parser.readValue(typed_param.mValue)) + { + typed_param.mValueAge = VALUE_AUTHORITATIVE; + typed_param.updateBlockFromValue(false); + + return true; + } + } + + // fall back on parsing block components for T + return typed_param.BaseBlock::deserializeBlock(parser, name_stack_range, new_name); + } + + bool serializeBlock(Parser& parser, Parser::name_stack_t& name_stack, const predicate_rule_t predicate_rule, const BaseBlock* diff_block = NULL) const + { + const derived_t& typed_param = static_cast(*this); + const derived_t* diff_param = static_cast(diff_block); + + //std::string key = typed_param.getValueName(); + + //// first try to write out name of name/value pair + //if (!key.empty()) + //{ + // if (!diff_param || !ParamCompare::equals(diff_param->getValueName(), key)) + // { + // return parser.writeValue(key, name_stack); + // } + //} + // then try to serialize value directly + if (!diff_param || !ParamCompare::equals(typed_param.getValue(), diff_param->getValue())) + { + + if (parser.writeValue(typed_param.getValue(), name_stack)) + { + return true; + } + else + { + //RN: *always* serialize provided components of BlockValue (don't pass diff_param on), + // since these tend to be viewed as the constructor arguments for the value T. It seems + // cleaner to treat the uniqueness of a BlockValue according to the generated value, and + // not the individual components. This way will not + // be exported as , since it was probably the intent of the user to + // be specific about the RGB color values. This also fixes an issue where we distinguish + // between rect.left not being provided and rect.left being explicitly set to 0 (same as default) + + if (typed_param.mValueAge == VALUE_AUTHORITATIVE) + { + // if the value is authoritative but the parser doesn't accept the value type + // go ahead and make a copy, and splat the value out to its component params + // and serialize those params + derived_t copy(typed_param); + copy.updateBlockFromValue(true); + return copy.block_t::serializeBlock(parser, name_stack, predicate_rule, NULL); + } + else + { + return block_t::serializeBlock(parser, name_stack, predicate_rule, NULL); + } + } + } + return false; + } + + bool validateBlock(bool emit_errors = true) const + { + if (mValueAge == VALUE_NEEDS_UPDATE) + { + if (block_t::validateBlock(emit_errors)) + { + // clear stale keyword associated with old value + mValueAge = BLOCK_AUTHORITATIVE; + static_cast(const_cast(this))->updateValueFromBlock(); + return true; + } + else + { + //block value incomplete, so not considered provided + // will attempt to revalidate on next call to isProvided() + return false; + } + } + else + { + // we have a valid value in hand + return true; + } + } + + // propagate change status up to enclosing block + /*virtual*/ void paramChanged(const Param& changed_param, bool user_provided) + { + BaseBlock::paramChanged(changed_param, user_provided); + if (user_provided) + { + // a parameter changed, so our value is out of date + mValueAge = VALUE_NEEDS_UPDATE; + } + } + + void setValue(const value_t& val) + { + // set param version number to be up to date, so we ignore block contents + mValueAge = VALUE_AUTHORITATIVE; + mValue = val; + static_cast(this)->updateBlockFromValue(false); + } + + const value_t& getValue() const + { + validateBlock(true); + return mValue; + } + + T& getValue() + { + validateBlock(true); + return mValue; + } + + protected: + + // use this from within updateValueFromBlock() to set the value without making it authoritative + void updateValue(const value_t& value) + { + mValue = value; + } + + bool mergeBlockParam(bool source_provided, bool dst_provided, BlockDescriptor& block_data, const BaseBlock& source, bool overwrite) + { + bool source_override = source_provided && (overwrite || !dst_provided); + + const derived_t& src_typed_param = static_cast(source); + + if (source_override && src_typed_param.mValueAge == VALUE_AUTHORITATIVE) + { + // copy value over + setValue(src_typed_param.getValue()); + return true; + } + // merge individual parameters into destination + if (mValueAge == VALUE_AUTHORITATIVE) + { + static_cast(this)->updateBlockFromValue(dst_provided); + } + return mergeBlock(block_data, source, overwrite); + } + + bool mergeBlock(BlockDescriptor& block_data, const BaseBlock& source, bool overwrite) + { + return block_t::mergeBlock(block_data, source, overwrite); + } + + private: + mutable T mValue; + mutable EValueAge mValueAge; + }; } diff --git a/indra/llcommon/llinstancetracker.cpp b/indra/llcommon/llinstancetracker.cpp index e7193b70b5..d1b02066bd 100644 --- a/indra/llcommon/llinstancetracker.cpp +++ b/indra/llcommon/llinstancetracker.cpp @@ -1,24 +1,24 @@ /** * @file lllinstancetracker.cpp - * + * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcommon/llinstancetracker.h b/indra/llcommon/llinstancetracker.h index 27422e1266..3232a0e219 100644 --- a/indra/llcommon/llinstancetracker.h +++ b/indra/llcommon/llinstancetracker.h @@ -1,4 +1,4 @@ -/** +/** * @file llinstancetracker.h * @brief LLInstanceTracker is a mixin class that automatically tracks object * instances with or without an associated key @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -99,11 +99,11 @@ public: return mSelf; } - static size_t instanceCount() - { - return LockStatic()->mMap.size(); + static size_t instanceCount() + { + return LockStatic()->mMap.size(); } - + // snapshot of std::pair> pairs, for // some SUBCLASS derived from T template @@ -243,7 +243,7 @@ public: } protected: - LLInstanceTracker(const KEY& key) + LLInstanceTracker(const KEY& key) { // We do not intend to manage the lifespan of this object with // shared_ptr, so give it a no-op deleter. We store shared_ptrs in our @@ -286,9 +286,9 @@ private: static std::string report(const char* key) { return report(std::string(key)); } // caller must instantiate LockStatic - void add_(LockStatic& lock, const KEY& key, const ptr_t& ptr) - { - mInstanceKey = key; + void add_(LockStatic& lock, const KEY& key, const ptr_t& ptr) + { + mInstanceKey = key; InstanceMap& map = lock->mMap; switch(KEY_COLLISION_BEHAVIOR) { @@ -373,7 +373,7 @@ public: { return mSelf; } - + static size_t instanceCount() { return LockStatic()->mSet.size(); diff --git a/indra/llcommon/llkeybind.cpp b/indra/llcommon/llkeybind.cpp index b89160cc55..e36c1d0a4c 100644 --- a/indra/llcommon/llkeybind.cpp +++ b/indra/llcommon/llkeybind.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llkeybind.cpp * @brief Information about key combinations. * * $LicenseInfo:firstyear=2019&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2019, 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$ */ @@ -207,7 +207,7 @@ bool LLKeyBind::operator!=(const LLKeyBind& rhs) bool LLKeyBind::isEmpty() const { - for (const LLKeyData& key_data : mData) + for (const LLKeyData& key_data : mData) { if (!key_data.isEmpty()) return false; } @@ -225,7 +225,7 @@ LLKeyBind::data_vector_t::const_iterator LLKeyBind::endNonEmpty() const LLSD LLKeyBind::asLLSD() const { LLSD data; - for (const LLKeyData& key_data : mData) + for (const LLKeyData& key_data : mData) { // append intermediate entries even if empty to not affect visual // representation @@ -242,7 +242,7 @@ bool LLKeyBind::canHandle(EMouseClickType mouse, KEY key, MASK mask) const return false; } - for (const LLKeyData& key_data : mData) + for (const LLKeyData& key_data : mData) { if (key_data.canHandle(mouse, key, mask)) { @@ -266,7 +266,7 @@ bool LLKeyBind::hasKeyData(EMouseClickType mouse, KEY key, MASK mask, bool ignor { if (mouse != CLICK_NONE || key != KEY_NONE) { - for (const LLKeyData& key_data : mData) + for (const LLKeyData& key_data : mData) { if (key_data.mKey == key && key_data.mMask == mask @@ -353,7 +353,7 @@ void LLKeyBind::replaceKeyData(const LLKeyData& data, U32 index) { // if both click and key are none (isEmpty()), we are inserting a placeholder, we don't want to reset anything // otherwise reset identical key - for (LLKeyData& key_data : mData) + for (LLKeyData& key_data : mData) { if (key_data.mKey == data.mKey && key_data.mMouse == data.mMouse diff --git a/indra/llcommon/llkeybind.h b/indra/llcommon/llkeybind.h index 488f509411..1bbb2fadb5 100644 --- a/indra/llcommon/llkeybind.h +++ b/indra/llcommon/llkeybind.h @@ -1,25 +1,25 @@ -/** +/** * @file llkeybind.h * @brief Information about key combinations. * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -54,7 +54,7 @@ public: KEY mKey; MASK mMask; // Either to expect exact match or ignore not expected masks as long as expected mask-bit is present - bool mIgnoreMasks; + bool mIgnoreMasks; }; // One function can bind to multiple Key options diff --git a/indra/llcommon/llkeythrottle.h b/indra/llcommon/llkeythrottle.h index 1f576cc19e..a5b5eaa946 100644 --- a/indra/llcommon/llkeythrottle.h +++ b/indra/llcommon/llkeythrottle.h @@ -1,24 +1,24 @@ -/** +/** * @file llkeythrottle.h * * $LicenseInfo:firstyear=2005&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -46,44 +46,44 @@ template class LLKeyThrottle; template class LLKeyThrottleImpl { - friend class LLKeyThrottle; + friend class LLKeyThrottle; protected: - struct Entry { - U32 count; - bool blocked; - - Entry() : count(0), blocked(false) { } - }; - - typedef std::map EntryMap; - - EntryMap* prevMap; - EntryMap* currMap; - - U32 countLimit; - // maximum number of keys allowed per interval - - U64 intervalLength; // each map covers this time period (usec or frame number) - U64 startTime; // start of the time period (usec or frame number) - // currMap started counting at this time - // prevMap covers the previous interval - - LLKeyThrottleImpl() : - prevMap(NULL), - currMap(NULL), - countLimit(0), - intervalLength(1), - startTime(0) - {} - - static U64 getTime() - { - return LLFrameTimer::getTotalTime(); - } - static U64 getFrame() // Return the current frame number - { - return (U64) LLFrameTimer::getFrameCount(); - } + struct Entry { + U32 count; + bool blocked; + + Entry() : count(0), blocked(false) { } + }; + + typedef std::map EntryMap; + + EntryMap* prevMap; + EntryMap* currMap; + + U32 countLimit; + // maximum number of keys allowed per interval + + U64 intervalLength; // each map covers this time period (usec or frame number) + U64 startTime; // start of the time period (usec or frame number) + // currMap started counting at this time + // prevMap covers the previous interval + + LLKeyThrottleImpl() : + prevMap(NULL), + currMap(NULL), + countLimit(0), + intervalLength(1), + startTime(0) + {} + + static U64 getTime() + { + return LLFrameTimer::getTotalTime(); + } + static U64 getFrame() // Return the current frame number + { + return (U64) LLFrameTimer::getFrameCount(); + } }; @@ -91,241 +91,241 @@ template< class T > class LLKeyThrottle { public: - // @param realtime = FALSE for frame-based throttle, TRUE for usec - // real-time throttle - LLKeyThrottle(U32 limit, F32 interval, BOOL realtime = TRUE) - : m(* new LLKeyThrottleImpl) - { - setParameters( limit, interval, realtime ); - } - - ~LLKeyThrottle() - { - delete m.prevMap; - delete m.currMap; - delete &m; - } - - enum State { - THROTTLE_OK, // rate not exceeded, let pass - THROTTLE_NEWLY_BLOCKED, // rate exceed for the first time - 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) - { - 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; - bool prevBlocked = false; - - typename LLKeyThrottleImpl::EntryMap::const_iterator prev = m.prevMap->find(id); - if (prev != m.prevMap->end()) - { - prevCount = prev->second.count; - prevBlocked = prev->second.blocked; - } - - typename LLKeyThrottleImpl::Entry& curr = (*m.currMap)[id]; - - bool wereBlocked = curr.blocked || prevBlocked; - - curr.count += weight; - - // 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); - - curr.blocked |= averageCount > m.countLimit; - - bool nowBlocked = curr.blocked || prevBlocked; - - if (!nowBlocked) - { - return THROTTLE_OK; - } - else if (!wereBlocked) - { - return THROTTLE_NEWLY_BLOCKED; - } - else - { - return THROTTLE_BLOCKED; - } - } - - // call to force throttle conditions for id - void throttleAction(const T& id) - { - noteAction(id); - typename LLKeyThrottleImpl::Entry& curr = (*m.currMap)[id]; - curr.count = llmax(m.countLimit, curr.count); - curr.blocked = true; - } - - // returns true if key is blocked - bool isThrottled(const T& id) const - { - if (m.currMap->empty() - && m.prevMap->empty()) - { - // most of the time we'll fall in here - return false; - } - - // NOTE, we ignore the case where id is in the map but the map is stale. - // You might think that we'd stop throttling things in such a case, - // however it may be that a god has disabled scripts in the region or - // estate --> we probably want to report the state of the id when the - // scripting engine was paused. - typename LLKeyThrottleImpl::EntryMap::const_iterator entry = m.currMap->find(id); - if (entry != m.currMap->end()) - { - return entry->second.blocked; - } - entry = m.prevMap->find(id); - if (entry != m.prevMap->end()) - { - return entry->second.blocked; - } - return false; - } - - // Get the throttling parameters - void getParameters( U32 & out_limit, F32 & out_interval, BOOL & out_realtime ) - { - out_limit = m.countLimit; - out_interval = m.intervalLength; - out_realtime = mIsRealtime; - } - - // Set the throttling behavior - void setParameters( U32 limit, F32 interval, BOOL realtime = TRUE ) - { - // limit is the maximum number of keys - // allowed per interval (in seconds or frames) - mIsRealtime = realtime; - m.countLimit = limit; - if ( mIsRealtime ) - { - m.intervalLength = (U64)(interval * USEC_PER_SEC); - m.startTime = LLKeyThrottleImpl::getTime(); - } - else - { - m.intervalLength = (U64)interval; - m.startTime = LLKeyThrottleImpl::getFrame(); - } - - if ( m.intervalLength == 0 ) - { // Don't allow zero intervals - m.intervalLength = 1; - } - - delete m.prevMap; - m.prevMap = new typename LLKeyThrottleImpl::EntryMap; - delete m.currMap; - m.currMap = new typename LLKeyThrottleImpl::EntryMap; - } + // @param realtime = FALSE for frame-based throttle, TRUE for usec + // real-time throttle + LLKeyThrottle(U32 limit, F32 interval, BOOL realtime = TRUE) + : m(* new LLKeyThrottleImpl) + { + setParameters( limit, interval, realtime ); + } + + ~LLKeyThrottle() + { + delete m.prevMap; + delete m.currMap; + delete &m; + } + + enum State { + THROTTLE_OK, // rate not exceeded, let pass + THROTTLE_NEWLY_BLOCKED, // rate exceed for the first time + 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) + { + 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; + bool prevBlocked = false; + + typename LLKeyThrottleImpl::EntryMap::const_iterator prev = m.prevMap->find(id); + if (prev != m.prevMap->end()) + { + prevCount = prev->second.count; + prevBlocked = prev->second.blocked; + } + + typename LLKeyThrottleImpl::Entry& curr = (*m.currMap)[id]; + + bool wereBlocked = curr.blocked || prevBlocked; + + curr.count += weight; + + // 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); + + curr.blocked |= averageCount > m.countLimit; + + bool nowBlocked = curr.blocked || prevBlocked; + + if (!nowBlocked) + { + return THROTTLE_OK; + } + else if (!wereBlocked) + { + return THROTTLE_NEWLY_BLOCKED; + } + else + { + return THROTTLE_BLOCKED; + } + } + + // call to force throttle conditions for id + void throttleAction(const T& id) + { + noteAction(id); + typename LLKeyThrottleImpl::Entry& curr = (*m.currMap)[id]; + curr.count = llmax(m.countLimit, curr.count); + curr.blocked = true; + } + + // returns true if key is blocked + bool isThrottled(const T& id) const + { + if (m.currMap->empty() + && m.prevMap->empty()) + { + // most of the time we'll fall in here + return false; + } + + // NOTE, we ignore the case where id is in the map but the map is stale. + // You might think that we'd stop throttling things in such a case, + // however it may be that a god has disabled scripts in the region or + // estate --> we probably want to report the state of the id when the + // scripting engine was paused. + typename LLKeyThrottleImpl::EntryMap::const_iterator entry = m.currMap->find(id); + if (entry != m.currMap->end()) + { + return entry->second.blocked; + } + entry = m.prevMap->find(id); + if (entry != m.prevMap->end()) + { + return entry->second.blocked; + } + return false; + } + + // Get the throttling parameters + void getParameters( U32 & out_limit, F32 & out_interval, BOOL & out_realtime ) + { + out_limit = m.countLimit; + out_interval = m.intervalLength; + out_realtime = mIsRealtime; + } + + // Set the throttling behavior + void setParameters( U32 limit, F32 interval, BOOL realtime = TRUE ) + { + // limit is the maximum number of keys + // allowed per interval (in seconds or frames) + mIsRealtime = realtime; + m.countLimit = limit; + if ( mIsRealtime ) + { + m.intervalLength = (U64)(interval * USEC_PER_SEC); + m.startTime = LLKeyThrottleImpl::getTime(); + } + else + { + m.intervalLength = (U64)interval; + m.startTime = LLKeyThrottleImpl::getFrame(); + } + + if ( m.intervalLength == 0 ) + { // Don't allow zero intervals + m.intervalLength = 1; + } + + delete m.prevMap; + m.prevMap = new typename LLKeyThrottleImpl::EntryMap; + delete m.currMap; + m.currMap = new typename LLKeyThrottleImpl::EntryMap; + } protected: - LLKeyThrottleImpl& m; - BOOL mIsRealtime; // TRUE to be time based (default), FALSE for frame based + LLKeyThrottleImpl& m; + BOOL mIsRealtime; // TRUE to be time based (default), FALSE for frame based }; #endif diff --git a/indra/llcommon/llkeyusetracker.h b/indra/llcommon/llkeyusetracker.h index 1fb222dd40..790c7b713b 100644 --- a/indra/llcommon/llkeyusetracker.h +++ b/indra/llcommon/llkeyusetracker.h @@ -1,25 +1,25 @@ -/** +/** * @file llkeyusetracker.h * @brief Declaration of the LLKeyUseTracker class. * * $LicenseInfo:firstyear=2003&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -40,176 +40,176 @@ template class KeyUseTrackerNodeImpl { public: - U64 mLastUse; - U32 mUseCount; - TKey mKey; - TData mData; - - KeyUseTrackerNodeImpl( TKey k, TData d ) : - mLastUse(0), - mUseCount(0), - mKey( k ), - mData( d ) - { - } + U64 mLastUse; + U32 mUseCount; + TKey mKey; + TData mData; + + KeyUseTrackerNodeImpl( TKey k, TData d ) : + mLastUse(0), + mUseCount(0), + mKey( k ), + mData( d ) + { + } }; template class LLKeyUseTracker { - typedef KeyUseTrackerNodeImpl TKeyUseTrackerNode; - typedef std::list TKeyList; - TKeyList mKeyList; - U64 mMemUsecs; - U64 mLastExpire; - U32 mMaxCount; - U32 mCount; - - static U64 getTime() - { - // This function operates on a frame basis, not instantaneous. - // We can rely on its output for determining first use in a - // frame. - return LLFrameTimer::getTotalTime(); - } - - void ageKeys() - { - U64 now = getTime(); - if( now == mLastExpire ) - { - return; - } - mLastExpire = now; - - while( !mKeyList.empty() && (now - mKeyList.front()->mLastUse > mMemUsecs ) ) - { - delete mKeyList.front(); - mKeyList.pop_front(); - mCount--; - } - } - - TKeyUseTrackerNode *findNode( TKey key ) - { - ageKeys(); - - typename TKeyList::iterator i; - for( i = mKeyList.begin(); i != mKeyList.end(); i++ ) - { - if( (*i)->mKey == key ) - return *i; - } - - return NULL; - } - - TKeyUseTrackerNode *removeNode( TKey key ) - { - TKeyUseTrackerNode *i; - i = findNode( key ); - if( i ) - { - mKeyList.remove( i ); - mCount--; - return i; - } - - return NULL; - } + typedef KeyUseTrackerNodeImpl TKeyUseTrackerNode; + typedef std::list TKeyList; + TKeyList mKeyList; + U64 mMemUsecs; + U64 mLastExpire; + U32 mMaxCount; + U32 mCount; + + static U64 getTime() + { + // This function operates on a frame basis, not instantaneous. + // We can rely on its output for determining first use in a + // frame. + return LLFrameTimer::getTotalTime(); + } + + void ageKeys() + { + U64 now = getTime(); + if( now == mLastExpire ) + { + return; + } + mLastExpire = now; + + while( !mKeyList.empty() && (now - mKeyList.front()->mLastUse > mMemUsecs ) ) + { + delete mKeyList.front(); + mKeyList.pop_front(); + mCount--; + } + } + + TKeyUseTrackerNode *findNode( TKey key ) + { + ageKeys(); + + typename TKeyList::iterator i; + for( i = mKeyList.begin(); i != mKeyList.end(); i++ ) + { + if( (*i)->mKey == key ) + return *i; + } + + return NULL; + } + + TKeyUseTrackerNode *removeNode( TKey key ) + { + TKeyUseTrackerNode *i; + i = findNode( key ); + if( i ) + { + mKeyList.remove( i ); + mCount--; + return i; + } + + return NULL; + } public: - LLKeyUseTracker( U32 memory_seconds, U32 max_count ) : - mLastExpire(0), - mMaxCount( max_count ), - mCount(0) - { - mMemUsecs = ((U64)memory_seconds) * 1000000; - } - - ~LLKeyUseTracker() - { - // Flush list - while( !mKeyList.empty() ) - { - delete mKeyList.front(); - mKeyList.pop_front(); - mCount--; - } - } - - void markUse( TKey key, TData data ) - { - TKeyUseTrackerNode *node = removeNode( key ); - if( !node ) - { - node = new TKeyUseTrackerNode(key, data); - } - else - { - // Update data - node->mData = data; - } - node->mLastUse = getTime(); - node->mUseCount++; - mKeyList.push_back( node ); - mCount++; - - // Too many items? Drop head - if( mCount > mMaxCount ) - { - delete mKeyList.front(); - mKeyList.pop_front(); - mCount--; - } - } - - void forgetKey( TKey key ) - { - TKeyUseTrackerNode *node = removeNode( key ); - if( node ) - { - delete node; - } - } - - U32 getUseCount( TKey key ) - { - TKeyUseTrackerNode *node = findNode( key ); - if( node ) - { - return node->mUseCount; - } - return 0; - } - - U64 getTimeSinceUse( TKey key ) - { - TKeyUseTrackerNode *node = findNode( key ); - if( node ) - { - U64 now = getTime(); - U64 delta = now - node->mLastUse; - return (U32)( delta / 1000000 ); - } - return 0; - } - - TData *getLastUseData( TKey key ) - { - TKeyUseTrackerNode *node = findNode( key ); - if( node ) - { - return &node->mData; - } - return NULL; - } - - U32 getKeyCount() - { - return mCount; - } + LLKeyUseTracker( U32 memory_seconds, U32 max_count ) : + mLastExpire(0), + mMaxCount( max_count ), + mCount(0) + { + mMemUsecs = ((U64)memory_seconds) * 1000000; + } + + ~LLKeyUseTracker() + { + // Flush list + while( !mKeyList.empty() ) + { + delete mKeyList.front(); + mKeyList.pop_front(); + mCount--; + } + } + + void markUse( TKey key, TData data ) + { + TKeyUseTrackerNode *node = removeNode( key ); + if( !node ) + { + node = new TKeyUseTrackerNode(key, data); + } + else + { + // Update data + node->mData = data; + } + node->mLastUse = getTime(); + node->mUseCount++; + mKeyList.push_back( node ); + mCount++; + + // Too many items? Drop head + if( mCount > mMaxCount ) + { + delete mKeyList.front(); + mKeyList.pop_front(); + mCount--; + } + } + + void forgetKey( TKey key ) + { + TKeyUseTrackerNode *node = removeNode( key ); + if( node ) + { + delete node; + } + } + + U32 getUseCount( TKey key ) + { + TKeyUseTrackerNode *node = findNode( key ); + if( node ) + { + return node->mUseCount; + } + return 0; + } + + U64 getTimeSinceUse( TKey key ) + { + TKeyUseTrackerNode *node = findNode( key ); + if( node ) + { + U64 now = getTime(); + U64 delta = now - node->mLastUse; + return (U32)( delta / 1000000 ); + } + return 0; + } + + TData *getLastUseData( TKey key ) + { + TKeyUseTrackerNode *node = findNode( key ); + if( node ) + { + return &node->mData; + } + return NULL; + } + + U32 getKeyCount() + { + return mCount; + } }; #endif diff --git a/indra/llcommon/llleap.cpp b/indra/llcommon/llleap.cpp index b2b1162f63..d0fb586459 100644 --- a/indra/llcommon/llleap.cpp +++ b/indra/llcommon/llleap.cpp @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2012-02-20 * @brief Implementation for llleap. - * + * * $LicenseInfo:firstyear=2012&license=viewerlgpl$ * Copyright (c) 2012, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/llleap.h b/indra/llcommon/llleap.h index 7cecdf2f8f..acf9edf418 100644 --- a/indra/llcommon/llleap.h +++ b/indra/llcommon/llleap.h @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2012-02-20 * @brief Class that implements "LLSD Event API Plugin" - * + * * $LicenseInfo:firstyear=2012&license=viewerlgpl$ * Copyright (c) 2012, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/llleaplistener.cpp b/indra/llcommon/llleaplistener.cpp index 471f52e91c..050d71c327 100644 --- a/indra/llcommon/llleaplistener.cpp +++ b/indra/llcommon/llleaplistener.cpp @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2012-03-16 * @brief Implementation for llleaplistener. - * + * * $LicenseInfo:firstyear=2012&license=viewerlgpl$ * Copyright (c) 2012, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/llleaplistener.h b/indra/llcommon/llleaplistener.h index 0ca5893657..cad4543d02 100644 --- a/indra/llcommon/llleaplistener.h +++ b/indra/llcommon/llleaplistener.h @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2012-03-16 * @brief LLEventAPI supporting LEAP plugins - * + * * $LicenseInfo:firstyear=2012&license=viewerlgpl$ * Copyright (c) 2012, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/llliveappconfig.cpp b/indra/llcommon/llliveappconfig.cpp index a9b1cdf4f6..559bfc443c 100644 --- a/indra/llcommon/llliveappconfig.cpp +++ b/indra/llcommon/llliveappconfig.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llliveappconfig.cpp * @brief Configuration information for an LLApp that overrides indra.xml * * $LicenseInfo:firstyear=2003&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -33,48 +33,48 @@ #include "llsdserialize.h" LLLiveAppConfig::LLLiveAppConfig( - const std::string& filename, - F32 refresh_period, - LLApp::OptionPriority priority) : - LLLiveFile(filename, refresh_period), - mPriority(priority) + const std::string& filename, + F32 refresh_period, + LLApp::OptionPriority priority) : + LLLiveFile(filename, refresh_period), + mPriority(priority) { } LLLiveAppConfig::~LLLiveAppConfig() { } -// virtual +// virtual bool LLLiveAppConfig::loadFile() { - LL_INFOS() << "LLLiveAppConfig::loadFile(): reading from " - << filename() << LL_ENDL; + LL_INFOS() << "LLLiveAppConfig::loadFile(): reading from " + << filename() << LL_ENDL; llifstream file(filename().c_str()); - LLSD config; + LLSD config; if (file.is_open()) { LLSDSerialize::fromXML(config, file); - if(!config.isMap()) - { - LL_WARNS() << "Live app config not an map in " << filename() - << " Ignoring the data." << LL_ENDL; - return false; - } - file.close(); + if(!config.isMap()) + { + LL_WARNS() << "Live app config not an map in " << filename() + << " Ignoring the data." << LL_ENDL; + return false; + } + file.close(); + } + else + { + LL_INFOS() << "Live file " << filename() << " does not exit." << LL_ENDL; } - else - { - LL_INFOS() << "Live file " << filename() << " does not exit." << LL_ENDL; - } - // *NOTE: we do not handle the else case here because we would not - // have attempted to load the file unless LLLiveFile had - // determined there was a reason to load it. This only happens - // when either the file has been updated or it is either suddenly - // in existence or has passed out of existence. Therefore, we want - // to set the config to an empty config, and return that it - // changed. + // *NOTE: we do not handle the else case here because we would not + // have attempted to load the file unless LLLiveFile had + // determined there was a reason to load it. This only happens + // when either the file has been updated or it is either suddenly + // in existence or has passed out of existence. Therefore, we want + // to set the config to an empty config, and return that it + // changed. - LLApp* app = LLApp::instance(); - if(app) app->setOptionData(mPriority, config); - return true; + LLApp* app = LLApp::instance(); + if(app) app->setOptionData(mPriority, config); + return true; } diff --git a/indra/llcommon/llliveappconfig.h b/indra/llcommon/llliveappconfig.h index 4fd7c26a07..0dea643d87 100644 --- a/indra/llcommon/llliveappconfig.h +++ b/indra/llcommon/llliveappconfig.h @@ -1,25 +1,25 @@ -/** +/** * @file llliveappconfig.h * @brief Configuration information for an LLApp that overrides indra.xml * * $LicenseInfo:firstyear=2003&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -43,27 +43,27 @@ class LL_COMMON_API LLLiveAppConfig : public LLLiveFile { public: - /** - * @brief Constructor - * - * @param filename. The name of the file for periodically checking - * configuration. - * @param refresh_period How often the internal timer should - * bother checking the filesystem. - * @param The application priority level of that configuration file. - */ - LLLiveAppConfig( - const std::string& filename, - F32 refresh_period, - LLApp::OptionPriority priority); + /** + * @brief Constructor + * + * @param filename. The name of the file for periodically checking + * configuration. + * @param refresh_period How often the internal timer should + * bother checking the filesystem. + * @param The application priority level of that configuration file. + */ + LLLiveAppConfig( + const std::string& filename, + F32 refresh_period, + LLApp::OptionPriority priority); - ~LLLiveAppConfig(); ///< Destructor + ~LLLiveAppConfig(); ///< Destructor protected: - /*virtual*/ bool loadFile(); + /*virtual*/ bool loadFile(); private: - LLApp::OptionPriority mPriority; + LLApp::OptionPriority mPriority; }; #endif diff --git a/indra/llcommon/lllivefile.cpp b/indra/llcommon/lllivefile.cpp index ea485c2d86..15651a6813 100644 --- a/indra/llcommon/lllivefile.cpp +++ b/indra/llcommon/lllivefile.cpp @@ -1,24 +1,24 @@ -/** +/** * @file lllivefile.cpp * * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -35,51 +35,51 @@ const F32 DEFAULT_CONFIG_FILE_REFRESH = 5.0f; class LLLiveFile::Impl { public: - Impl(const std::string& filename, const F32 refresh_period); - ~Impl(); - - bool check(); - void changed(); - - bool mForceCheck; - F32 mRefreshPeriod; - LLFrameTimer mRefreshTimer; - - std::string mFilename; - time_t mLastModTime; - time_t mLastStatTime; - bool mLastExists; - - LLEventTimer* mEventTimer; + Impl(const std::string& filename, const F32 refresh_period); + ~Impl(); + + bool check(); + void changed(); + + bool mForceCheck; + F32 mRefreshPeriod; + LLFrameTimer mRefreshTimer; + + std::string mFilename; + time_t mLastModTime; + time_t mLastStatTime; + bool mLastExists; + + LLEventTimer* mEventTimer; private: LOG_CLASS(LLLiveFile); }; LLLiveFile::Impl::Impl(const std::string& filename, const F32 refresh_period) - : - mForceCheck(true), - mRefreshPeriod(refresh_period), - mFilename(filename), - mLastModTime(0), - mLastStatTime(0), - mLastExists(false), - mEventTimer(NULL) + : + mForceCheck(true), + mRefreshPeriod(refresh_period), + mFilename(filename), + mLastModTime(0), + mLastStatTime(0), + mLastExists(false), + mEventTimer(NULL) { } LLLiveFile::Impl::~Impl() { - delete mEventTimer; + delete mEventTimer; } LLLiveFile::LLLiveFile(const std::string& filename, const F32 refresh_period) - : impl(* new Impl(filename, refresh_period)) + : impl(* new Impl(filename, refresh_period)) { } LLLiveFile::~LLLiveFile() { - delete &impl; + delete &impl; } @@ -88,8 +88,8 @@ bool LLLiveFile::Impl::check() bool detected_change = false; // Skip the check if not enough time has elapsed and we're not // forcing a check of the file - if (mForceCheck || mRefreshTimer.getElapsedTimeF32() >= mRefreshPeriod) - { + if (mForceCheck || mRefreshTimer.getElapsedTimeF32() >= mRefreshPeriod) + { mForceCheck = false; // force only forces one check mRefreshTimer.reset(); // don't check again until mRefreshPeriod has passed @@ -98,11 +98,11 @@ bool LLLiveFile::Impl::check() if (LLFile::stat(mFilename, &stat_data)) { // Couldn't stat the file, that means it doesn't exist or is - // broken somehow. + // broken somehow. if (mLastExists) { mLastExists = false; - detected_change = true; // no longer existing is a change! + detected_change = true; // no longer existing is a change! LL_DEBUGS() << "detected deleted file '" << mFilename << "'" << LL_ENDL; } } @@ -134,65 +134,65 @@ bool LLLiveFile::Impl::check() void LLLiveFile::Impl::changed() { - // we wanted to read this file, and we were successful. - mLastModTime = mLastStatTime; + // we wanted to read this file, and we were successful. + mLastModTime = mLastStatTime; } bool LLLiveFile::checkAndReload() { - bool changed = impl.check(); - if (changed) - { - if(loadFile()) - { - impl.changed(); - this->changed(); - } - else - { - changed = false; - } - } - return changed; + bool changed = impl.check(); + if (changed) + { + if(loadFile()) + { + impl.changed(); + this->changed(); + } + else + { + changed = false; + } + } + return changed; } std::string LLLiveFile::filename() const { - return impl.mFilename; + return impl.mFilename; } namespace { - class LiveFileEventTimer : public LLEventTimer - { - public: - LiveFileEventTimer(LLLiveFile& f, F32 refresh) - : LLEventTimer(refresh), mLiveFile(f) - { } - - BOOL tick() - { - mLiveFile.checkAndReload(); - return FALSE; - } - - private: - LLLiveFile& mLiveFile; - }; - + class LiveFileEventTimer : public LLEventTimer + { + public: + LiveFileEventTimer(LLLiveFile& f, F32 refresh) + : LLEventTimer(refresh), mLiveFile(f) + { } + + BOOL tick() + { + mLiveFile.checkAndReload(); + return FALSE; + } + + private: + LLLiveFile& mLiveFile; + }; + } void LLLiveFile::addToEventTimer() { - impl.mEventTimer = new LiveFileEventTimer(*this, impl.mRefreshPeriod); + impl.mEventTimer = new LiveFileEventTimer(*this, impl.mRefreshPeriod); } void LLLiveFile::setRefreshPeriod(F32 seconds) { - if (seconds < 0.f) - { - seconds = -seconds; - } - impl.mRefreshPeriod = seconds; + if (seconds < 0.f) + { + seconds = -seconds; + } + impl.mRefreshPeriod = seconds; } diff --git a/indra/llcommon/lllivefile.h b/indra/llcommon/lllivefile.h index 320aa4bc3e..305b205a68 100644 --- a/indra/llcommon/lllivefile.h +++ b/indra/llcommon/lllivefile.h @@ -1,25 +1,25 @@ -/** +/** * @file lllivefile.h * @brief Automatically reloads a file whenever it changes or is removed. * * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -33,63 +33,63 @@ extern const F32 DEFAULT_CONFIG_FILE_REFRESH; class LL_COMMON_API LLLiveFile { public: - LLLiveFile(const std::string& filename, const F32 refresh_period = 5.f); - virtual ~LLLiveFile(); + LLLiveFile(const std::string& filename, const F32 refresh_period = 5.f); + virtual ~LLLiveFile(); + + /** + * @brief Check to see if this live file should reload. + * + * Call this before using anything that was read & cached + * from the file. + * + * This method calls the loadFile() method if + * any of: + * file has a new modify time since the last check + * file used to exist and now does not + * file used to not exist but now does + * @return Returns true if the file was reloaded. + */ + bool checkAndReload(); - /** - * @brief Check to see if this live file should reload. - * - * Call this before using anything that was read & cached - * from the file. - * - * This method calls the loadFile() method if - * any of: - * file has a new modify time since the last check - * file used to exist and now does not - * file used to not exist but now does - * @return Returns true if the file was reloaded. - */ - bool checkAndReload(); - - std::string filename() const; + std::string filename() const; - /** - * @brief Add this live file to an automated recheck. - * - * Normally, just calling checkAndReload() is enough. In some - * cases though, you may need to let the live file periodically - * check itself. - */ - void addToEventTimer(); + /** + * @brief Add this live file to an automated recheck. + * + * Normally, just calling checkAndReload() is enough. In some + * cases though, you may need to let the live file periodically + * check itself. + */ + void addToEventTimer(); - void setRefreshPeriod(F32 seconds); + void setRefreshPeriod(F32 seconds); protected: - /** - * @breif Implement this to load your file if it changed. - * - * This method is called automatically by checkAndReload(), - * so though you must implement this in derived classes, you do - * not need to call it manually. - * @return Returns true if the file was successfully loaded. - */ - virtual bool loadFile() = 0; + /** + * @breif Implement this to load your file if it changed. + * + * This method is called automatically by checkAndReload(), + * so though you must implement this in derived classes, you do + * not need to call it manually. + * @return Returns true if the file was successfully loaded. + */ + virtual bool loadFile() = 0; - /** - * @brief Implement this method if you want to get a change callback. - * - * This virtual function will be called automatically at the end - * of checkAndReload() if a new configuration was - * loaded. This does not track differences between the current and - * newly loaded file, so any successful load event will trigger a - * changed() callback. Default is to do nothing. - */ - virtual void changed() {} + /** + * @brief Implement this method if you want to get a change callback. + * + * This virtual function will be called automatically at the end + * of checkAndReload() if a new configuration was + * loaded. This does not track differences between the current and + * newly loaded file, so any successful load event will trigger a + * changed() callback. Default is to do nothing. + */ + virtual void changed() {} private: - class Impl; - Impl& impl; + class Impl; + Impl& impl; }; #endif //LL_LLLIVEFILE_H diff --git a/indra/llcommon/llmainthreadtask.cpp b/indra/llcommon/llmainthreadtask.cpp index e0d70cacd8..eb26ded63f 100644 --- a/indra/llcommon/llmainthreadtask.cpp +++ b/indra/llcommon/llmainthreadtask.cpp @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2019-12-05 * @brief Implementation for llmainthreadtask. - * + * * $LicenseInfo:firstyear=2019&license=viewerlgpl$ * Copyright (c) 2019, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/llmainthreadtask.h b/indra/llcommon/llmainthreadtask.h index d509b687c0..28ad62830b 100644 --- a/indra/llcommon/llmainthreadtask.h +++ b/indra/llcommon/llmainthreadtask.h @@ -4,7 +4,7 @@ * @date 2019-12-04 * @brief LLMainThreadTask dispatches work to the main thread. When invoked on * the main thread, it performs the work inline. - * + * * $LicenseInfo:firstyear=2019&license=viewerlgpl$ * Copyright (c) 2019, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/llmake.h b/indra/llcommon/llmake.h index 02463d97ea..e575128be7 100644 --- a/indra/llcommon/llmake.h +++ b/indra/llcommon/llmake.h @@ -9,7 +9,7 @@ * make an instance with arguments of arbitrary type. llmake() * eliminates the need to declare a new helper function for every such * class template. - * + * * also relevant: * * Template argument deduction for class templates (C++17) diff --git a/indra/llcommon/llmd5.cpp b/indra/llcommon/llmd5.cpp index 0abe817f1d..f64f54c262 100644 --- a/indra/llcommon/llmd5.cpp +++ b/indra/llcommon/llmd5.cpp @@ -1,42 +1,42 @@ -/** +/** * @file llmd5.cpp * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ -// llMD5.CC - source code for the C++/object oriented translation and +// llMD5.CC - source code for the C++/object oriented translation and // modification of MD5. // // Adapted to Linden Lab by Frank Filipanits, 6/25/2002 // Fixed potential memory leak, James Cook, 6/27/2002 -// Translation and modification (c) 1995 by Mordechai T. Abzug +// Translation and modification (c) 1995 by Mordechai T. Abzug -// This translation/ modification is provided "as is," without express or +// This translation/ modification is provided "as is," without express or // implied warranty of any kind. -// The translator/ modifier does not claim (1) that MD5 will do what you think -// it does; (2) that this translation/ modification is accurate; or (3) that -// this software is "merchantible." (Language for this disclaimer partially +// The translator/ modifier does not claim (1) that MD5 will do what you think +// it does; (2) that this translation/ modification is accurate; or (3) that +// this software is "merchantible." (Language for this disclaimer partially // copied from the disclaimer below). /* based on: @@ -76,7 +76,7 @@ documentation and/or software. #include "llmd5.h" -#include // cerr +#include // cerr // how many bytes to grab at a time when checking files const int LLMD5::BLOCK_LEN = 4096; @@ -102,7 +102,7 @@ void LLMD5::update (const uint8_t *input, const size_t input_length) { size_t buffer_space; // how much space is left in buffer if (finalized){ // so we can't update! - std::cerr << "LLMD5::update: Can't update a finalized digest!" << std::endl; + std::cerr << "LLMD5::update: Can't update a finalized digest!" << std::endl; return; } @@ -116,21 +116,21 @@ void LLMD5::update (const uint8_t *input, const size_t input_length) { // now, transform each 64-byte piece of the input, bypassing the buffer if (input == NULL || input_length == 0){ - std::cerr << "LLMD5::update: Invalid input!" << std::endl; - return; + std::cerr << "LLMD5::update: Invalid input!" << std::endl; + return; } // Transform as many times as possible. if (input_length >= buffer_space) { // ie. we have enough to fill the buffer // fill the rest of the buffer and transform - memcpy( /* Flawfinder: ignore */ - buffer + buffer_index, - input, - buffer_space); + memcpy( /* Flawfinder: ignore */ + buffer + buffer_index, + input, + buffer_space); transform (buffer); - for (input_index = buffer_space; input_index + 63 < input_length; - input_index += 64) + for (input_index = buffer_space; input_index + 63 < input_length; + input_index += 64) transform (input+input_index); buffer_index = 0; // so we can buffer remaining @@ -140,7 +140,7 @@ void LLMD5::update (const uint8_t *input, const size_t input_length) { // and here we do the buffering: - memcpy(buffer+buffer_index, input+input_index, input_length-input_index); /* Flawfinder: ignore */ + memcpy(buffer+buffer_index, input+input_index, input_length-input_index); /* Flawfinder: ignore */ } @@ -150,7 +150,7 @@ void LLMD5::update (const uint8_t *input, const size_t input_length) { void LLMD5::update(FILE* file){ - unsigned char buffer[BLOCK_LEN]; /* Flawfinder: ignore */ + unsigned char buffer[BLOCK_LEN]; /* Flawfinder: ignore */ int len; while ( (len=(int)fread(buffer, 1, BLOCK_LEN, file)) ) @@ -165,11 +165,11 @@ void LLMD5::update(FILE* file){ void LLMD5::update(std::istream& stream){ - unsigned char buffer[BLOCK_LEN]; /* Flawfinder: ignore */ + unsigned char buffer[BLOCK_LEN]; /* Flawfinder: ignore */ int len; while (stream.good()){ - stream.read( (char*)buffer, BLOCK_LEN); /* Flawfinder: ignore */ // note that return value of read is unusable. + stream.read( (char*)buffer, BLOCK_LEN); /* Flawfinder: ignore */ // note that return value of read is unusable. len=(int)stream.gcount(); update(buffer, len); } @@ -178,7 +178,7 @@ void LLMD5::update(std::istream& stream){ void LLMD5::update(const std::string& s) { - update((unsigned char *)s.c_str(),s.length()); + update((unsigned char *)s.c_str(),s.length()); } // MD5 finalization. Ends an MD5 message-digest operation, writing the @@ -187,7 +187,7 @@ void LLMD5::update(const std::string& s) void LLMD5::finalize (){ - unsigned char bits[8]; /* Flawfinder: ignore */ + unsigned char bits[8]; /* Flawfinder: ignore */ size_t index, padLen; static uint8_t PADDING[64]={ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -245,60 +245,60 @@ LLMD5::LLMD5(std::istream& stream){ // Digest a string of the format ("%s:%i" % (s, number)) LLMD5::LLMD5(const unsigned char *string, const unsigned int number) { - const char *colon = ":"; - char tbuf[16]; /* Flawfinder: ignore */ - init(); - update(string, (U32)strlen((const char *) string)); /* Flawfinder: ignore */ - update((const unsigned char *) colon, (U32)strlen(colon)); /* Flawfinder: ignore */ - snprintf(tbuf, sizeof(tbuf), "%i", number); /* Flawfinder: ignore */ - update((const unsigned char *) tbuf, (U32)strlen(tbuf)); /* Flawfinder: ignore */ - finalize(); + const char *colon = ":"; + char tbuf[16]; /* Flawfinder: ignore */ + init(); + update(string, (U32)strlen((const char *) string)); /* Flawfinder: ignore */ + update((const unsigned char *) colon, (U32)strlen(colon)); /* Flawfinder: ignore */ + snprintf(tbuf, sizeof(tbuf), "%i", number); /* Flawfinder: ignore */ + update((const unsigned char *) tbuf, (U32)strlen(tbuf)); /* Flawfinder: ignore */ + finalize(); } // Digest a string LLMD5::LLMD5(const unsigned char *s) { - init(); - update(s, (U32)strlen((const char *) s)); /* Flawfinder: ignore */ - finalize(); + init(); + update(s, (U32)strlen((const char *) s)); /* Flawfinder: ignore */ + finalize(); } void LLMD5::raw_digest(unsigned char *s) const { - if (!finalized) - { - std::cerr << "LLMD5::raw_digest: Can't get digest if you haven't "<< - "finalized the digest!" << std::endl; - s[0] = '\0'; - return; - } - - memcpy(s, digest, 16); /* Flawfinder: ignore */ - return; + if (!finalized) + { + std::cerr << "LLMD5::raw_digest: Can't get digest if you haven't "<< + "finalized the digest!" << std::endl; + s[0] = '\0'; + return; + } + + memcpy(s, digest, 16); /* Flawfinder: ignore */ + return; } void LLMD5::hex_digest(char *s) const { - int i; + int i; - if (!finalized) - { - std::cerr << "LLMD5::hex_digest: Can't get digest if you haven't "<< - "finalized the digest!" < sAllocatedMemInKB) - { - sAvailPhysicalMemInKB = sMaxPhysicalMemInKB - sAllocatedMemInKB ; - } - else - { - sAvailPhysicalMemInKB = U32Kilobytes(0); - } + PROCESS_MEMORY_COUNTERS counters; + + if (!GetProcessMemoryInfo(GetCurrentProcess(), &counters, sizeof(counters))) + { + LL_WARNS() << "GetProcessMemoryInfo failed" << LL_ENDL; + return ; + } + + sAllocatedMemInKB = U32Kilobytes::convert(U64Bytes(counters.WorkingSetSize)); + sample(sAllocatedMem, sAllocatedMemInKB); + sAllocatedPageSizeInKB = U32Kilobytes::convert(U64Bytes(counters.PagefileUsage)); + sample(sVirtualMem, sAllocatedPageSizeInKB); + + U32Kilobytes avail_phys, avail_virtual; + LLMemoryInfo::getAvailableMemoryKB(avail_phys, avail_virtual) ; + sMaxPhysicalMemInKB = llmin(avail_phys + sAllocatedMemInKB, sMaxHeapSizeInKB); + + if(sMaxPhysicalMemInKB > sAllocatedMemInKB) + { + sAvailPhysicalMemInKB = sMaxPhysicalMemInKB - sAllocatedMemInKB ; + } + else + { + sAvailPhysicalMemInKB = U32Kilobytes(0); + } #elif defined(LL_DARWIN) task_vm_info info; @@ -156,13 +156,13 @@ void LLMemory::updateMemoryInfo() } #else - //not valid for other systems for now. - sAllocatedMemInKB = U64Bytes(LLMemory::getCurrentRSS()); - sMaxPhysicalMemInKB = U64Bytes(U32_MAX); - sAvailPhysicalMemInKB = U64Bytes(U32_MAX); + //not valid for other systems for now. + sAllocatedMemInKB = U64Bytes(LLMemory::getCurrentRSS()); + sMaxPhysicalMemInKB = U64Bytes(U32_MAX); + sAvailPhysicalMemInKB = U64Bytes(U32_MAX); #endif - return ; + return ; } // @@ -171,126 +171,126 @@ void LLMemory::updateMemoryInfo() //if success, it returns the address where the memory chunk can fit in; //otherwise it returns NULL. // -//static +//static void* LLMemory::tryToAlloc(void* address, U32 size) { #if LL_WINDOWS - address = VirtualAlloc(address, size, MEM_RESERVE | MEM_TOP_DOWN, PAGE_NOACCESS) ; - if(address) - { - if(!VirtualFree(address, 0, MEM_RELEASE)) - { - LL_ERRS() << "error happens when free some memory reservation." << LL_ENDL ; - } - } - return address ; + address = VirtualAlloc(address, size, MEM_RESERVE | MEM_TOP_DOWN, PAGE_NOACCESS) ; + if(address) + { + if(!VirtualFree(address, 0, MEM_RELEASE)) + { + LL_ERRS() << "error happens when free some memory reservation." << LL_ENDL ; + } + } + return address ; #else - return (void*)0x01 ; //skip checking + return (void*)0x01 ; //skip checking #endif } -//static +//static void LLMemory::logMemoryInfo(BOOL update) { - LL_PROFILE_ZONE_SCOPED - if(update) - { - updateMemoryInfo() ; - } - - LL_INFOS() << "Current allocated physical memory(KB): " << sAllocatedMemInKB << LL_ENDL ; - LL_INFOS() << "Current allocated page size (KB): " << sAllocatedPageSizeInKB << LL_ENDL ; - LL_INFOS() << "Current available physical memory(KB): " << sAvailPhysicalMemInKB << LL_ENDL ; - LL_INFOS() << "Current max usable memory(KB): " << sMaxPhysicalMemInKB << LL_ENDL ; + LL_PROFILE_ZONE_SCOPED + if(update) + { + updateMemoryInfo() ; + } + + LL_INFOS() << "Current allocated physical memory(KB): " << sAllocatedMemInKB << LL_ENDL ; + LL_INFOS() << "Current allocated page size (KB): " << sAllocatedPageSizeInKB << LL_ENDL ; + LL_INFOS() << "Current available physical memory(KB): " << sAvailPhysicalMemInKB << LL_ENDL ; + LL_INFOS() << "Current max usable memory(KB): " << sMaxPhysicalMemInKB << LL_ENDL ; } -//static -U32Kilobytes LLMemory::getAvailableMemKB() +//static +U32Kilobytes LLMemory::getAvailableMemKB() { - return sAvailPhysicalMemInKB ; + return sAvailPhysicalMemInKB ; } -//static -U32Kilobytes LLMemory::getMaxMemKB() +//static +U32Kilobytes LLMemory::getMaxMemKB() { - return sMaxPhysicalMemInKB ; + return sMaxPhysicalMemInKB ; } -//static -U32Kilobytes LLMemory::getAllocatedMemKB() +//static +U32Kilobytes LLMemory::getAllocatedMemKB() { - return sAllocatedMemInKB ; + return sAllocatedMemInKB ; } //---------------------------------------------------------------------------- #if defined(LL_WINDOWS) -//static +//static U64 LLMemory::getCurrentRSS() { - PROCESS_MEMORY_COUNTERS counters; + PROCESS_MEMORY_COUNTERS counters; - if (!GetProcessMemoryInfo(GetCurrentProcess(), &counters, sizeof(counters))) - { - LL_WARNS() << "GetProcessMemoryInfo failed" << LL_ENDL; - return 0; - } + if (!GetProcessMemoryInfo(GetCurrentProcess(), &counters, sizeof(counters))) + { + LL_WARNS() << "GetProcessMemoryInfo failed" << LL_ENDL; + return 0; + } - return counters.WorkingSetSize; + return counters.WorkingSetSize; } #elif defined(LL_DARWIN) -// if (sysctl(ctl, 2, &page_size, &size, NULL, 0) == -1) -// { -// LL_WARNS() << "Couldn't get page size" << LL_ENDL; -// return 0; -// } else { -// return page_size; -// } +// if (sysctl(ctl, 2, &page_size, &size, NULL, 0) == -1) +// { +// LL_WARNS() << "Couldn't get page size" << LL_ENDL; +// return 0; +// } else { +// return page_size; +// } // } U64 LLMemory::getCurrentRSS() { - U64 residentSize = 0; - mach_task_basic_info_data_t basicInfo; - mach_msg_type_number_t basicInfoCount = MACH_TASK_BASIC_INFO_COUNT; - if (task_info(mach_task_self(), MACH_TASK_BASIC_INFO, (task_info_t)&basicInfo, &basicInfoCount) == KERN_SUCCESS) - { + U64 residentSize = 0; + mach_task_basic_info_data_t basicInfo; + mach_msg_type_number_t basicInfoCount = MACH_TASK_BASIC_INFO_COUNT; + if (task_info(mach_task_self(), MACH_TASK_BASIC_INFO, (task_info_t)&basicInfo, &basicInfoCount) == KERN_SUCCESS) + { residentSize = basicInfo.resident_size; // 64-bit macos apps allocate 32 GB or more at startup, and this is reflected in virtual_size. // basicInfo.virtual_size is not what we want. - } - else - { - LL_WARNS() << "task_info failed" << LL_ENDL; - } + } + else + { + LL_WARNS() << "task_info failed" << LL_ENDL; + } - return residentSize; + return residentSize; } #elif defined(LL_LINUX) U64 LLMemory::getCurrentRSS() { - struct rusage usage; + struct rusage usage; - if (getrusage(RUSAGE_SELF, &usage) != 0) { - // Error handling code could be here - return 0; - } + if (getrusage(RUSAGE_SELF, &usage) != 0) { + // Error handling code could be here + return 0; + } - // ru_maxrss (since Linux 2.6.32) - // This is the maximum resident set size used (in kilobytes). - return usage.ru_maxrss * 1024; + // ru_maxrss (since Linux 2.6.32) + // This is the maximum resident set size used (in kilobytes). + return usage.ru_maxrss * 1024; } #else U64 LLMemory::getCurrentRSS() { - return 0; + return 0; } #endif @@ -302,53 +302,53 @@ U64 LLMemory::getCurrentRSS() #include struct mem_info { - std::map memory_info; - LLMutex mutex; + std::map memory_info; + LLMutex mutex; - static mem_info& get() { - static mem_info instance; - return instance; - } + static mem_info& get() { + static mem_info instance; + return instance; + } private: - mem_info(){} + mem_info(){} }; void* ll_aligned_malloc_fallback( size_t size, int align ) { - SYSTEM_INFO sysinfo; - GetSystemInfo(&sysinfo); - - unsigned int for_alloc = (size/sysinfo.dwPageSize + !!(size%sysinfo.dwPageSize)) * sysinfo.dwPageSize; - - void *p = VirtualAlloc(NULL, for_alloc+sysinfo.dwPageSize, MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE); - if(NULL == p) { - // call debugger - __asm int 3; - } - DWORD old; - BOOL Res = VirtualProtect((void*)((char*)p + for_alloc), sysinfo.dwPageSize, PAGE_NOACCESS, &old); - if(FALSE == Res) { - // call debugger - __asm int 3; - } - - void* ret = (void*)((char*)p + for_alloc-size); - - { - LLMutexLock lock(&mem_info::get().mutex); - mem_info::get().memory_info.insert(std::pair(ret, p)); - } - - - return ret; + SYSTEM_INFO sysinfo; + GetSystemInfo(&sysinfo); + + unsigned int for_alloc = (size/sysinfo.dwPageSize + !!(size%sysinfo.dwPageSize)) * sysinfo.dwPageSize; + + void *p = VirtualAlloc(NULL, for_alloc+sysinfo.dwPageSize, MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE); + if(NULL == p) { + // call debugger + __asm int 3; + } + DWORD old; + BOOL Res = VirtualProtect((void*)((char*)p + for_alloc), sysinfo.dwPageSize, PAGE_NOACCESS, &old); + if(FALSE == Res) { + // call debugger + __asm int 3; + } + + void* ret = (void*)((char*)p + for_alloc-size); + + { + LLMutexLock lock(&mem_info::get().mutex); + mem_info::get().memory_info.insert(std::pair(ret, p)); + } + + + return ret; } void ll_aligned_free_fallback( void* ptr ) { - LLMutexLock lock(&mem_info::get().mutex); - VirtualFree(mem_info::get().memory_info.find(ptr)->second, 0, MEM_RELEASE); - mem_info::get().memory_info.erase(ptr); + LLMutexLock lock(&mem_info::get().mutex); + VirtualFree(mem_info::get().memory_info.find(ptr)->second, 0, MEM_RELEASE); + mem_info::get().memory_info.erase(ptr); } #endif diff --git a/indra/llcommon/llmemory.h b/indra/llcommon/llmemory.h index ac6c969d70..313c380587 100644 --- a/indra/llcommon/llmemory.h +++ b/indra/llcommon/llmemory.h @@ -38,7 +38,7 @@ class LLMutex ; #if LL_WINDOWS && LL_DEBUG #define LL_CHECK_MEMORY llassert(_CrtCheckMemory()); #else -#define LL_CHECK_MEMORY +#define LL_CHECK_MEMORY #endif @@ -73,27 +73,27 @@ LL_COMMON_API void ll_assert_aligned_func(uintptr_t ptr,U32 alignment); #include -template T* LL_NEXT_ALIGNED_ADDRESS(T* address) -{ - return reinterpret_cast( - (uintptr_t(address) + 0xF) & ~0xF); +template T* LL_NEXT_ALIGNED_ADDRESS(T* address) +{ + return reinterpret_cast( + (uintptr_t(address) + 0xF) & ~0xF); } -template T* LL_NEXT_ALIGNED_ADDRESS_64(T* address) -{ - return reinterpret_cast( - (uintptr_t(address) + 0x3F) & ~0x3F); +template T* LL_NEXT_ALIGNED_ADDRESS_64(T* address) +{ + return reinterpret_cast( + (uintptr_t(address) + 0x3F) & ~0x3F); } #if LL_LINUX || LL_DARWIN -#define LL_ALIGN_PREFIX(x) -#define LL_ALIGN_POSTFIX(x) __attribute__((aligned(x))) +#define LL_ALIGN_PREFIX(x) +#define LL_ALIGN_POSTFIX(x) __attribute__((aligned(x))) #elif LL_WINDOWS -#define LL_ALIGN_PREFIX(x) __declspec(align(x)) -#define LL_ALIGN_POSTFIX(x) +#define LL_ALIGN_PREFIX(x) __declspec(align(x)) +#define LL_ALIGN_POSTFIX(x) #else #error "LL_ALIGN_PREFIX and LL_ALIGN_POSTFIX undefined" @@ -126,22 +126,22 @@ public: \ //------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------ - // for enable buffer overrun detection predefine LL_DEBUG_BUFFER_OVERRUN in current library - // change preprocessor code to: #if 1 && defined(LL_WINDOWS) + // for enable buffer overrun detection predefine LL_DEBUG_BUFFER_OVERRUN in current library + // change preprocessor code to: #if 1 && defined(LL_WINDOWS) #if 0 && defined(LL_WINDOWS) - void* ll_aligned_malloc_fallback( size_t size, int align ); - void ll_aligned_free_fallback( void* ptr ); + void* ll_aligned_malloc_fallback( size_t size, int align ); + void ll_aligned_free_fallback( void* ptr ); //------------------------------------------------------------------------------------------------ #else - inline void* ll_aligned_malloc_fallback( size_t size, int align ) - { + inline void* ll_aligned_malloc_fallback( size_t size, int align ) + { LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY; - #if defined(LL_WINDOWS) + #if defined(LL_WINDOWS) void* ret = _aligned_malloc(size, align); - #else + #else char* aligned = NULL; - void* mem = malloc( size + (align - 1) + sizeof(void*) ); + void* mem = malloc( size + (align - 1) + sizeof(void*) ); if (mem) { aligned = ((char*)mem) + sizeof(void*); @@ -149,25 +149,25 @@ public: \ ((void**)aligned)[-1] = mem; } - void* ret = aligned; - #endif + void* ret = aligned; + #endif LL_PROFILE_ALLOC(ret, size); return ret; - } + } - inline void ll_aligned_free_fallback( void* ptr ) - { + inline void ll_aligned_free_fallback( void* ptr ) + { LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY; LL_PROFILE_FREE(ptr); - #if defined(LL_WINDOWS) - _aligned_free(ptr); - #else - if (ptr) - { - free( ((void**)ptr)[-1] ); - } - #endif - } + #if defined(LL_WINDOWS) + _aligned_free(ptr); + #else + if (ptr) + { + free( ((void**)ptr)[-1] ); + } + #endif + } #endif //------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------ @@ -176,11 +176,11 @@ inline void* ll_aligned_malloc_16(size_t size) // returned hunk MUST be freed wi { LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY; #if defined(LL_WINDOWS) - void* ret = _aligned_malloc(size, 16); + void* ret = _aligned_malloc(size, 16); #elif defined(LL_DARWIN) - void* ret = malloc(size); // default osx malloc is 16 byte aligned. + void* ret = malloc(size); // default osx malloc is 16 byte aligned. #else - void *ret; + void *ret; if (0 != posix_memalign(&ret, 16, size)) return nullptr; #endif @@ -193,11 +193,11 @@ inline void ll_aligned_free_16(void *p) LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY; LL_PROFILE_FREE(p); #if defined(LL_WINDOWS) - _aligned_free(p); + _aligned_free(p); #elif defined(LL_DARWIN) - return free(p); + return free(p); #else - free(p); // posix_memalign() is compatible with heap deallocator + free(p); // posix_memalign() is compatible with heap deallocator #endif } @@ -206,21 +206,21 @@ inline void* ll_aligned_realloc_16(void* ptr, size_t size, size_t old_size) // r LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY; LL_PROFILE_FREE(ptr); #if defined(LL_WINDOWS) - void* ret = _aligned_realloc(ptr, size, 16); + void* ret = _aligned_realloc(ptr, size, 16); #elif defined(LL_DARWIN) - void* ret = realloc(ptr,size); // default osx malloc is 16 byte aligned. + void* ret = realloc(ptr,size); // default osx malloc is 16 byte aligned. #else - //FIXME: memcpy is SLOW - void* ret = ll_aligned_malloc_16(size); - if (ptr) - { - if (ret) - { - // Only copy the size of the smallest memory block to avoid memory corruption. - memcpy(ret, ptr, llmin(old_size, size)); - } - ll_aligned_free_16(ptr); - } + //FIXME: memcpy is SLOW + void* ret = ll_aligned_malloc_16(size); + if (ptr) + { + if (ret) + { + // Only copy the size of the smallest memory block to avoid memory corruption. + memcpy(ret, ptr, llmin(old_size, size)); + } + ll_aligned_free_16(ptr); + } #endif LL_PROFILE_ALLOC(ptr, size); return ret; @@ -230,11 +230,11 @@ inline void* ll_aligned_malloc_32(size_t size) // returned hunk MUST be freed wi { LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY; #if defined(LL_WINDOWS) - void* ret = _aligned_malloc(size, 32); + void* ret = _aligned_malloc(size, 32); #elif defined(LL_DARWIN) - void* ret = ll_aligned_malloc_fallback( size, 32 ); + void* ret = ll_aligned_malloc_fallback( size, 32 ); #else - void *ret; + void *ret; if (0 != posix_memalign(&ret, 32, size)) return nullptr; #endif @@ -247,11 +247,11 @@ inline void ll_aligned_free_32(void *p) LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY; LL_PROFILE_FREE(p); #if defined(LL_WINDOWS) - _aligned_free(p); + _aligned_free(p); #elif defined(LL_DARWIN) - ll_aligned_free_fallback( p ); + ll_aligned_free_fallback( p ); #else - free(p); // posix_memalign() is compatible with heap deallocator + free(p); // posix_memalign() is compatible with heap deallocator #endif } @@ -261,23 +261,23 @@ LL_FORCE_INLINE void* ll_aligned_malloc(size_t size) { LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY; void* ret; - if (LL_DEFAULT_HEAP_ALIGN % ALIGNMENT == 0) - { - ret = malloc(size); + if (LL_DEFAULT_HEAP_ALIGN % ALIGNMENT == 0) + { + ret = malloc(size); LL_PROFILE_ALLOC(ret, size); - } - else if (ALIGNMENT == 16) - { - ret = ll_aligned_malloc_16(size); - } - else if (ALIGNMENT == 32) - { - ret = ll_aligned_malloc_32(size); - } - else - { - ret = ll_aligned_malloc_fallback(size, ALIGNMENT); - } + } + else if (ALIGNMENT == 16) + { + ret = ll_aligned_malloc_16(size); + } + else if (ALIGNMENT == 32) + { + ret = ll_aligned_malloc_32(size); + } + else + { + ret = ll_aligned_malloc_fallback(size, ALIGNMENT); + } return ret; } @@ -285,96 +285,96 @@ template LL_FORCE_INLINE void ll_aligned_free(void* ptr) { LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY; - if (ALIGNMENT == LL_DEFAULT_HEAP_ALIGN) - { + if (ALIGNMENT == LL_DEFAULT_HEAP_ALIGN) + { LL_PROFILE_FREE(ptr); - free(ptr); - } - else if (ALIGNMENT == 16) - { - ll_aligned_free_16(ptr); - } - else if (ALIGNMENT == 32) - { - return ll_aligned_free_32(ptr); - } - else - { - return ll_aligned_free_fallback(ptr); - } + free(ptr); + } + else if (ALIGNMENT == 16) + { + ll_aligned_free_16(ptr); + } + else if (ALIGNMENT == 32) + { + return ll_aligned_free_32(ptr); + } + else + { + return ll_aligned_free_fallback(ptr); + } } -// Copy words 16-byte blocks from src to dst. Source and destination MUST NOT OVERLAP. +// Copy words 16-byte blocks from src to dst. Source and destination MUST NOT OVERLAP. // Source and dest must be 16-byte aligned and size must be multiple of 16. // inline void ll_memcpy_nonaliased_aligned_16(char* __restrict dst, const char* __restrict src, size_t bytes) { LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY; - assert(src != NULL); - assert(dst != NULL); - assert(bytes > 0); - assert((bytes % sizeof(F32))== 0); - ll_assert_aligned(src,16); - ll_assert_aligned(dst,16); - - assert((src < dst) ? ((src + bytes) <= dst) : ((dst + bytes) <= src)); - assert(bytes%16==0); - - char* end = dst + bytes; - - if (bytes > 64) - { - - // Find start of 64b aligned area within block - // - void* begin_64 = LL_NEXT_ALIGNED_ADDRESS_64(dst); - - //at least 64 bytes before the end of the destination, switch to 16 byte copies - void* end_64 = end-64; - - // Prefetch the head of the 64b area now - // - _mm_prefetch((char*)begin_64, _MM_HINT_NTA); - _mm_prefetch((char*)begin_64 + 64, _MM_HINT_NTA); - _mm_prefetch((char*)begin_64 + 128, _MM_HINT_NTA); - _mm_prefetch((char*)begin_64 + 192, _MM_HINT_NTA); - - // Copy 16b chunks until we're 64b aligned - // - while (dst < begin_64) - { - - _mm_store_ps((F32*)dst, _mm_load_ps((F32*)src)); - dst += 16; - src += 16; - } - - // Copy 64b chunks up to your tail - // - // might be good to shmoo the 512b prefetch offset - // (characterize performance for various values) - // - while (dst < end_64) - { - _mm_prefetch((char*)src + 512, _MM_HINT_NTA); - _mm_prefetch((char*)dst + 512, _MM_HINT_NTA); - _mm_store_ps((F32*)dst, _mm_load_ps((F32*)src)); - _mm_store_ps((F32*)(dst + 16), _mm_load_ps((F32*)(src + 16))); - _mm_store_ps((F32*)(dst + 32), _mm_load_ps((F32*)(src + 32))); - _mm_store_ps((F32*)(dst + 48), _mm_load_ps((F32*)(src + 48))); - dst += 64; - src += 64; - } - } - - // Copy remainder 16b tail chunks (or ALL 16b chunks for sub-64b copies) - // - while (dst < end) - { - _mm_store_ps((F32*)dst, _mm_load_ps((F32*)src)); - dst += 16; - src += 16; - } + assert(src != NULL); + assert(dst != NULL); + assert(bytes > 0); + assert((bytes % sizeof(F32))== 0); + ll_assert_aligned(src,16); + ll_assert_aligned(dst,16); + + assert((src < dst) ? ((src + bytes) <= dst) : ((dst + bytes) <= src)); + assert(bytes%16==0); + + char* end = dst + bytes; + + if (bytes > 64) + { + + // Find start of 64b aligned area within block + // + void* begin_64 = LL_NEXT_ALIGNED_ADDRESS_64(dst); + + //at least 64 bytes before the end of the destination, switch to 16 byte copies + void* end_64 = end-64; + + // Prefetch the head of the 64b area now + // + _mm_prefetch((char*)begin_64, _MM_HINT_NTA); + _mm_prefetch((char*)begin_64 + 64, _MM_HINT_NTA); + _mm_prefetch((char*)begin_64 + 128, _MM_HINT_NTA); + _mm_prefetch((char*)begin_64 + 192, _MM_HINT_NTA); + + // Copy 16b chunks until we're 64b aligned + // + while (dst < begin_64) + { + + _mm_store_ps((F32*)dst, _mm_load_ps((F32*)src)); + dst += 16; + src += 16; + } + + // Copy 64b chunks up to your tail + // + // might be good to shmoo the 512b prefetch offset + // (characterize performance for various values) + // + while (dst < end_64) + { + _mm_prefetch((char*)src + 512, _MM_HINT_NTA); + _mm_prefetch((char*)dst + 512, _MM_HINT_NTA); + _mm_store_ps((F32*)dst, _mm_load_ps((F32*)src)); + _mm_store_ps((F32*)(dst + 16), _mm_load_ps((F32*)(src + 16))); + _mm_store_ps((F32*)(dst + 32), _mm_load_ps((F32*)(src + 32))); + _mm_store_ps((F32*)(dst + 48), _mm_load_ps((F32*)(src + 48))); + dst += 64; + src += 64; + } + } + + // Copy remainder 16b tail chunks (or ALL 16b chunks for sub-64b copies) + // + while (dst < end) + { + _mm_store_ps((F32*)dst, _mm_load_ps((F32*)src)); + dst += 16; + src += 16; + } } #ifndef __DEBUG_PRIVATE_MEM__ @@ -384,24 +384,24 @@ inline void ll_memcpy_nonaliased_aligned_16(char* __restrict dst, const char* __ class LL_COMMON_API LLMemory { public: - // Return the resident set size of the current process, in bytes. - // Return value is zero if not known. - static U64 getCurrentRSS(); - static void* tryToAlloc(void* address, U32 size); - static void initMaxHeapSizeGB(F32Gigabytes max_heap_size); - static void updateMemoryInfo() ; - static void logMemoryInfo(BOOL update = FALSE); - - static U32Kilobytes getAvailableMemKB() ; - static U32Kilobytes getMaxMemKB() ; - static U32Kilobytes getAllocatedMemKB() ; + // Return the resident set size of the current process, in bytes. + // Return value is zero if not known. + static U64 getCurrentRSS(); + static void* tryToAlloc(void* address, U32 size); + static void initMaxHeapSizeGB(F32Gigabytes max_heap_size); + static void updateMemoryInfo() ; + static void logMemoryInfo(BOOL update = FALSE); + + static U32Kilobytes getAvailableMemKB() ; + static U32Kilobytes getMaxMemKB() ; + static U32Kilobytes getAllocatedMemKB() ; private: - static U32Kilobytes sAvailPhysicalMemInKB ; - static U32Kilobytes sMaxPhysicalMemInKB ; - static U32Kilobytes sAllocatedMemInKB; - static U32Kilobytes sAllocatedPageSizeInKB ; + static U32Kilobytes sAvailPhysicalMemInKB ; + static U32Kilobytes sMaxPhysicalMemInKB ; + static U32Kilobytes sAllocatedMemInKB; + static U32Kilobytes sAllocatedPageSizeInKB ; - static U32Kilobytes sMaxHeapSizeInKB; + static U32Kilobytes sMaxHeapSizeInKB; }; // LLRefCount moved to llrefcount.h diff --git a/indra/llcommon/llmemorystream.cpp b/indra/llcommon/llmemorystream.cpp index 707ac8fd0f..b3acc8c7d3 100644 --- a/indra/llcommon/llmemorystream.cpp +++ b/indra/llcommon/llmemorystream.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llmemorystream.cpp * @author Phoenix * @date 2005-06-03 @@ -7,21 +7,21 @@ * $LicenseInfo:firstyear=2005&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -31,7 +31,7 @@ LLMemoryStreamBuf::LLMemoryStreamBuf(const U8* start, S32 length) { - reset(start, length); + reset(start, length); } LLMemoryStreamBuf::~LLMemoryStreamBuf() @@ -40,26 +40,26 @@ LLMemoryStreamBuf::~LLMemoryStreamBuf() void LLMemoryStreamBuf::reset(const U8* start, S32 length) { - setg((char*)start, (char*)start, (char*)start + length); + setg((char*)start, (char*)start, (char*)start + length); } int LLMemoryStreamBuf::underflow() { - //LL_DEBUGS() << "LLMemoryStreamBuf::underflow()" << LL_ENDL; - if(gptr() < egptr()) - { - return *gptr(); - } - return EOF; + //LL_DEBUGS() << "LLMemoryStreamBuf::underflow()" << LL_ENDL; + if(gptr() < egptr()) + { + return *gptr(); + } + return EOF; } -/** +/** * @class LLMemoryStreamBuf */ LLMemoryStream::LLMemoryStream(const U8* start, S32 length) : - std::istream(&mStreamBuf), - mStreamBuf(start, length) + std::istream(&mStreamBuf), + mStreamBuf(start, length) { } diff --git a/indra/llcommon/llmemorystream.h b/indra/llcommon/llmemorystream.h index e28f012192..6024bc5d37 100644 --- a/indra/llcommon/llmemorystream.h +++ b/indra/llcommon/llmemorystream.h @@ -1,4 +1,4 @@ -/** +/** * @file llmemorystream.h * @author Phoenix * @date 2005-06-03 @@ -7,21 +7,21 @@ * $LicenseInfo:firstyear=2005&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -29,7 +29,7 @@ #ifndef LL_LLMEMORYSTREAM_H #define LL_LLMEMORYSTREAM_H -/** +/** * This is a simple but effective optimization when you want to treat * a chunk of memory as an istream. I wrote this to avoid turing a * buffer into a string, and then throwing the string into an @@ -38,7 +38,7 @@ #include -/** +/** * @class LLMemoryStreamBuf * @brief This implements a wrapper around a piece of memory for istreams * @@ -49,18 +49,18 @@ class LL_COMMON_API LLMemoryStreamBuf : public std::streambuf { public: - LLMemoryStreamBuf(const U8* start, S32 length); - ~LLMemoryStreamBuf(); + LLMemoryStreamBuf(const U8* start, S32 length); + ~LLMemoryStreamBuf(); - void reset(const U8* start, S32 length); + void reset(const U8* start, S32 length); protected: - int underflow(); - //std::streamsize xsgetn(char* dest, std::streamsize n); + int underflow(); + //std::streamsize xsgetn(char* dest, std::streamsize n); }; -/** +/** * @class LLMemoryStream * @brief This implements a wrapper around a piece of memory for istreams * @@ -71,11 +71,11 @@ protected: class LL_COMMON_API LLMemoryStream : public std::istream { public: - LLMemoryStream(const U8* start, S32 length); - ~LLMemoryStream(); + LLMemoryStream(const U8* start, S32 length); + ~LLMemoryStream(); protected: - LLMemoryStreamBuf mStreamBuf; + LLMemoryStreamBuf mStreamBuf; }; #endif // LL_LLMEMORYSTREAM_H diff --git a/indra/llcommon/llmetricperformancetester.cpp b/indra/llcommon/llmetricperformancetester.cpp index ab509b46eb..e05c2558f6 100644 --- a/indra/llcommon/llmetricperformancetester.cpp +++ b/indra/llcommon/llmetricperformancetester.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llmetricperformancetester.cpp * @brief LLMetricPerformanceTesterBasic and LLMetricPerformanceTesterWithSession classes implementation * * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -39,129 +39,129 @@ LLMetricPerformanceTesterBasic::name_tester_map_t LLMetricPerformanceTesterBasic::sTesterMap ; -/*static*/ -void LLMetricPerformanceTesterBasic::cleanupClass() +/*static*/ +void LLMetricPerformanceTesterBasic::cleanupClass() { - for (name_tester_map_t::value_type& pair : sTesterMap) - { - delete pair.second; - } - sTesterMap.clear() ; + for (name_tester_map_t::value_type& pair : sTesterMap) + { + delete pair.second; + } + sTesterMap.clear() ; } -/*static*/ -BOOL LLMetricPerformanceTesterBasic::addTester(LLMetricPerformanceTesterBasic* tester) +/*static*/ +BOOL LLMetricPerformanceTesterBasic::addTester(LLMetricPerformanceTesterBasic* tester) { - llassert_always(tester != NULL); - std::string name = tester->getTesterName() ; - if (getTester(name)) - { - LL_ERRS() << "Tester name is already used by some other tester : " << name << LL_ENDL ; - return FALSE; - } - - sTesterMap.insert(std::make_pair(name, tester)); - return TRUE; + llassert_always(tester != NULL); + std::string name = tester->getTesterName() ; + if (getTester(name)) + { + LL_ERRS() << "Tester name is already used by some other tester : " << name << LL_ENDL ; + return FALSE; + } + + sTesterMap.insert(std::make_pair(name, tester)); + return TRUE; } -/*static*/ +/*static*/ void LLMetricPerformanceTesterBasic::deleteTester(std::string name) { - name_tester_map_t::iterator tester = sTesterMap.find(name); - if (tester != sTesterMap.end()) - { - delete tester->second; - sTesterMap.erase(tester); - } + name_tester_map_t::iterator tester = sTesterMap.find(name); + if (tester != sTesterMap.end()) + { + delete tester->second; + sTesterMap.erase(tester); + } } -/*static*/ -LLMetricPerformanceTesterBasic* LLMetricPerformanceTesterBasic::getTester(std::string name) +/*static*/ +LLMetricPerformanceTesterBasic* LLMetricPerformanceTesterBasic::getTester(std::string name) { - // Check for the requested metric name - name_tester_map_t::iterator found_it = sTesterMap.find(name) ; - if (found_it != sTesterMap.end()) - { - return found_it->second ; - } - return NULL ; + // Check for the requested metric name + name_tester_map_t::iterator found_it = sTesterMap.find(name) ; + if (found_it != sTesterMap.end()) + { + return found_it->second ; + } + return NULL ; } -/*static*/ +/*static*/ // Return TRUE if this metric is requested or if the general default "catch all" metric is requested BOOL LLMetricPerformanceTesterBasic::isMetricLogRequested(std::string name) { - return (LLTrace::BlockTimer::sMetricLog && ((LLTrace::BlockTimer::sLogName == name) || (LLTrace::BlockTimer::sLogName == DEFAULT_METRIC_NAME))); + return (LLTrace::BlockTimer::sMetricLog && ((LLTrace::BlockTimer::sLogName == name) || (LLTrace::BlockTimer::sLogName == DEFAULT_METRIC_NAME))); } -/*static*/ +/*static*/ LLSD LLMetricPerformanceTesterBasic::analyzeMetricPerformanceLog(std::istream& is) { - LLSD ret; - LLSD cur; - - while (!is.eof() && LLSDParser::PARSE_FAILURE != LLSDSerialize::fromXML(cur, is)) - { - for (LLSD::map_iterator iter = cur.beginMap(); iter != cur.endMap(); ++iter) - { - std::string label = iter->first; - - LLMetricPerformanceTesterBasic* tester = LLMetricPerformanceTesterBasic::getTester(iter->second["Name"].asString()) ; - if(tester) - { - ret[label]["Name"] = iter->second["Name"] ; - - auto num_of_metrics = tester->getNumberOfMetrics() ; - for(size_t index = 0 ; index < num_of_metrics ; index++) - { - ret[label][ tester->getMetricName(index) ] = iter->second[ tester->getMetricName(index) ] ; - } - } - } - } - - return ret; + LLSD ret; + LLSD cur; + + while (!is.eof() && LLSDParser::PARSE_FAILURE != LLSDSerialize::fromXML(cur, is)) + { + for (LLSD::map_iterator iter = cur.beginMap(); iter != cur.endMap(); ++iter) + { + std::string label = iter->first; + + LLMetricPerformanceTesterBasic* tester = LLMetricPerformanceTesterBasic::getTester(iter->second["Name"].asString()) ; + if(tester) + { + ret[label]["Name"] = iter->second["Name"] ; + + auto num_of_metrics = tester->getNumberOfMetrics() ; + for(size_t index = 0 ; index < num_of_metrics ; index++) + { + ret[label][ tester->getMetricName(index) ] = iter->second[ tester->getMetricName(index) ] ; + } + } + } + } + + return ret; } -/*static*/ +/*static*/ void LLMetricPerformanceTesterBasic::doAnalysisMetrics(std::string baseline, std::string target, std::string output) { - if(!LLMetricPerformanceTesterBasic::hasMetricPerformanceTesters()) - { - return ; - } - - // Open baseline and current target, exit if one is inexistent - llifstream base_is(baseline.c_str()); - llifstream target_is(target.c_str()); - if (!base_is.is_open() || !target_is.is_open()) - { - LL_WARNS() << "'-analyzeperformance' error : baseline or current target file inexistent" << LL_ENDL; - base_is.close(); - target_is.close(); - return; - } - - //analyze baseline - LLSD base = analyzeMetricPerformanceLog(base_is); - base_is.close(); - - //analyze current - LLSD current = analyzeMetricPerformanceLog(target_is); - target_is.close(); - - //output comparision - llofstream os(output.c_str()); - - os << "Label, Metric, Base(B), Target(T), Diff(T-B), Percentage(100*T/B)\n"; - for (LLMetricPerformanceTesterBasic::name_tester_map_t::value_type& pair : LLMetricPerformanceTesterBasic::sTesterMap) - { - LLMetricPerformanceTesterBasic* tester = ((LLMetricPerformanceTesterBasic*)pair.second); - tester->analyzePerformance(&os, &base, ¤t) ; - } - - os.flush(); - os.close(); + if(!LLMetricPerformanceTesterBasic::hasMetricPerformanceTesters()) + { + return ; + } + + // Open baseline and current target, exit if one is inexistent + llifstream base_is(baseline.c_str()); + llifstream target_is(target.c_str()); + if (!base_is.is_open() || !target_is.is_open()) + { + LL_WARNS() << "'-analyzeperformance' error : baseline or current target file inexistent" << LL_ENDL; + base_is.close(); + target_is.close(); + return; + } + + //analyze baseline + LLSD base = analyzeMetricPerformanceLog(base_is); + base_is.close(); + + //analyze current + LLSD current = analyzeMetricPerformanceLog(target_is); + target_is.close(); + + //output comparision + llofstream os(output.c_str()); + + os << "Label, Metric, Base(B), Target(T), Diff(T-B), Percentage(100*T/B)\n"; + for (LLMetricPerformanceTesterBasic::name_tester_map_t::value_type& pair : LLMetricPerformanceTesterBasic::sTesterMap) + { + LLMetricPerformanceTesterBasic* tester = ((LLMetricPerformanceTesterBasic*)pair.second); + tester->analyzePerformance(&os, &base, ¤t) ; + } + + os.flush(); + os.close(); } @@ -169,157 +169,157 @@ void LLMetricPerformanceTesterBasic::doAnalysisMetrics(std::string baseline, std // LLMetricPerformanceTesterBasic : Tester instance methods //---------------------------------------------------------------------------------------------- -LLMetricPerformanceTesterBasic::LLMetricPerformanceTesterBasic(std::string name) : - mName(name), - mCount(0) +LLMetricPerformanceTesterBasic::LLMetricPerformanceTesterBasic(std::string name) : + mName(name), + mCount(0) { - if (mName == std::string()) - { - LL_ERRS() << "LLMetricPerformanceTesterBasic construction invalid : Empty name passed to constructor" << LL_ENDL ; - } + if (mName == std::string()) + { + LL_ERRS() << "LLMetricPerformanceTesterBasic construction invalid : Empty name passed to constructor" << LL_ENDL ; + } - mValidInstance = LLMetricPerformanceTesterBasic::addTester(this) ; + mValidInstance = LLMetricPerformanceTesterBasic::addTester(this) ; } -LLMetricPerformanceTesterBasic::~LLMetricPerformanceTesterBasic() +LLMetricPerformanceTesterBasic::~LLMetricPerformanceTesterBasic() { } -void LLMetricPerformanceTesterBasic::preOutputTestResults(LLSD* sd) +void LLMetricPerformanceTesterBasic::preOutputTestResults(LLSD* sd) { - incrementCurrentCount() ; + incrementCurrentCount() ; } void LLMetricPerformanceTesterBasic::postOutputTestResults(LLSD* sd) { - LLTrace::BlockTimer::pushLog(*sd); + LLTrace::BlockTimer::pushLog(*sd); } -void LLMetricPerformanceTesterBasic::outputTestResults() +void LLMetricPerformanceTesterBasic::outputTestResults() { - LLSD sd; + LLSD sd; - preOutputTestResults(&sd) ; - outputTestRecord(&sd) ; - postOutputTestResults(&sd) ; + preOutputTestResults(&sd) ; + outputTestRecord(&sd) ; + postOutputTestResults(&sd) ; } void LLMetricPerformanceTesterBasic::addMetric(std::string str) { - mMetricStrings.push_back(str) ; + mMetricStrings.push_back(str) ; } -/*virtual*/ -void LLMetricPerformanceTesterBasic::analyzePerformance(llofstream* os, LLSD* base, LLSD* current) +/*virtual*/ +void LLMetricPerformanceTesterBasic::analyzePerformance(llofstream* os, LLSD* base, LLSD* current) { - resetCurrentCount() ; - - std::string current_label = getCurrentLabelName(); - BOOL in_base = (*base).has(current_label) ; - BOOL in_current = (*current).has(current_label) ; - - while(in_base || in_current) - { - LLSD::String label = current_label ; - - if(in_base && in_current) - { - *os << llformat("%s\n", label.c_str()) ; - - for(U32 index = 0 ; index < mMetricStrings.size() ; index++) - { - switch((*current)[label][ mMetricStrings[index] ].type()) - { - case LLSD::TypeInteger: - compareTestResults(os, mMetricStrings[index], - (S32)((*base)[label][ mMetricStrings[index] ].asInteger()), (S32)((*current)[label][ mMetricStrings[index] ].asInteger())) ; - break ; - case LLSD::TypeReal: - compareTestResults(os, mMetricStrings[index], - (F32)((*base)[label][ mMetricStrings[index] ].asReal()), (F32)((*current)[label][ mMetricStrings[index] ].asReal())) ; - break; - default: - LL_ERRS() << "unsupported metric " << mMetricStrings[index] << " LLSD type: " << (S32)(*current)[label][ mMetricStrings[index] ].type() << LL_ENDL ; - } - } - } - - incrementCurrentCount(); - current_label = getCurrentLabelName(); - in_base = (*base).has(current_label) ; - in_current = (*current).has(current_label) ; - } + resetCurrentCount() ; + + std::string current_label = getCurrentLabelName(); + BOOL in_base = (*base).has(current_label) ; + BOOL in_current = (*current).has(current_label) ; + + while(in_base || in_current) + { + LLSD::String label = current_label ; + + if(in_base && in_current) + { + *os << llformat("%s\n", label.c_str()) ; + + for(U32 index = 0 ; index < mMetricStrings.size() ; index++) + { + switch((*current)[label][ mMetricStrings[index] ].type()) + { + case LLSD::TypeInteger: + compareTestResults(os, mMetricStrings[index], + (S32)((*base)[label][ mMetricStrings[index] ].asInteger()), (S32)((*current)[label][ mMetricStrings[index] ].asInteger())) ; + break ; + case LLSD::TypeReal: + compareTestResults(os, mMetricStrings[index], + (F32)((*base)[label][ mMetricStrings[index] ].asReal()), (F32)((*current)[label][ mMetricStrings[index] ].asReal())) ; + break; + default: + LL_ERRS() << "unsupported metric " << mMetricStrings[index] << " LLSD type: " << (S32)(*current)[label][ mMetricStrings[index] ].type() << LL_ENDL ; + } + } + } + + incrementCurrentCount(); + current_label = getCurrentLabelName(); + in_base = (*base).has(current_label) ; + in_current = (*current).has(current_label) ; + } } -/*virtual*/ -void LLMetricPerformanceTesterBasic::compareTestResults(llofstream* os, std::string metric_string, S32 v_base, S32 v_current) +/*virtual*/ +void LLMetricPerformanceTesterBasic::compareTestResults(llofstream* os, std::string metric_string, S32 v_base, S32 v_current) { - *os << llformat(" ,%s, %d, %d, %d, %.4f\n", metric_string.c_str(), v_base, v_current, - v_current - v_base, (v_base != 0) ? 100.f * v_current / v_base : 0) ; + *os << llformat(" ,%s, %d, %d, %d, %.4f\n", metric_string.c_str(), v_base, v_current, + v_current - v_base, (v_base != 0) ? 100.f * v_current / v_base : 0) ; } -/*virtual*/ -void LLMetricPerformanceTesterBasic::compareTestResults(llofstream* os, std::string metric_string, F32 v_base, F32 v_current) +/*virtual*/ +void LLMetricPerformanceTesterBasic::compareTestResults(llofstream* os, std::string metric_string, F32 v_base, F32 v_current) { - *os << llformat(" ,%s, %.4f, %.4f, %.4f, %.4f\n", metric_string.c_str(), v_base, v_current, - v_current - v_base, (fabs(v_base) > 0.0001f) ? 100.f * v_current / v_base : 0.f ) ; + *os << llformat(" ,%s, %.4f, %.4f, %.4f, %.4f\n", metric_string.c_str(), v_base, v_current, + v_current - v_base, (fabs(v_base) > 0.0001f) ? 100.f * v_current / v_base : 0.f ) ; } //---------------------------------------------------------------------------------------------- // LLMetricPerformanceTesterWithSession //---------------------------------------------------------------------------------------------- -LLMetricPerformanceTesterWithSession::LLMetricPerformanceTesterWithSession(std::string name) : - LLMetricPerformanceTesterBasic(name), - mBaseSessionp(NULL), - mCurrentSessionp(NULL) +LLMetricPerformanceTesterWithSession::LLMetricPerformanceTesterWithSession(std::string name) : + LLMetricPerformanceTesterBasic(name), + mBaseSessionp(NULL), + mCurrentSessionp(NULL) { } LLMetricPerformanceTesterWithSession::~LLMetricPerformanceTesterWithSession() { - if (mBaseSessionp) - { - delete mBaseSessionp ; - mBaseSessionp = NULL ; - } - if (mCurrentSessionp) - { - delete mCurrentSessionp ; - mCurrentSessionp = NULL ; - } + if (mBaseSessionp) + { + delete mBaseSessionp ; + mBaseSessionp = NULL ; + } + if (mCurrentSessionp) + { + delete mCurrentSessionp ; + mCurrentSessionp = NULL ; + } } -/*virtual*/ -void LLMetricPerformanceTesterWithSession::analyzePerformance(llofstream* os, LLSD* base, LLSD* current) +/*virtual*/ +void LLMetricPerformanceTesterWithSession::analyzePerformance(llofstream* os, LLSD* base, LLSD* current) { - // Load the base session - resetCurrentCount() ; - mBaseSessionp = loadTestSession(base) ; - - // Load the current session - resetCurrentCount() ; - mCurrentSessionp = loadTestSession(current) ; - - if (!mBaseSessionp || !mCurrentSessionp) - { - LL_ERRS() << "Error loading test sessions." << LL_ENDL ; - } - - // Compare - compareTestSessions(os) ; - - // Release memory - if (mBaseSessionp) - { - delete mBaseSessionp ; - mBaseSessionp = NULL ; - } - if (mCurrentSessionp) - { - delete mCurrentSessionp ; - mCurrentSessionp = NULL ; - } + // Load the base session + resetCurrentCount() ; + mBaseSessionp = loadTestSession(base) ; + + // Load the current session + resetCurrentCount() ; + mCurrentSessionp = loadTestSession(current) ; + + if (!mBaseSessionp || !mCurrentSessionp) + { + LL_ERRS() << "Error loading test sessions." << LL_ENDL ; + } + + // Compare + compareTestSessions(os) ; + + // Release memory + if (mBaseSessionp) + { + delete mBaseSessionp ; + mBaseSessionp = NULL ; + } + if (mCurrentSessionp) + { + delete mCurrentSessionp ; + mCurrentSessionp = NULL ; + } } @@ -327,7 +327,7 @@ void LLMetricPerformanceTesterWithSession::analyzePerformance(llofstream* os, LL // LLTestSession //---------------------------------------------------------------------------------------------- -LLMetricPerformanceTesterWithSession::LLTestSession::~LLTestSession() +LLMetricPerformanceTesterWithSession::LLTestSession::~LLTestSession() { } diff --git a/indra/llcommon/llmetricperformancetester.h b/indra/llcommon/llmetricperformancetester.h index 6561a78f03..15c564f2ca 100644 --- a/indra/llcommon/llmetricperformancetester.h +++ b/indra/llcommon/llmetricperformancetester.h @@ -1,31 +1,31 @@ -/** - * @file llmetricperformancetester.h +/** + * @file llmetricperformancetester.h * @brief LLMetricPerformanceTesterBasic and LLMetricPerformanceTesterWithSession classes definition * * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ -#ifndef LL_METRICPERFORMANCETESTER_H -#define LL_METRICPERFORMANCETESTER_H +#ifndef LL_METRICPERFORMANCETESTER_H +#define LL_METRICPERFORMANCETESTER_H char const* const DEFAULT_METRIC_NAME = "metric"; @@ -36,179 +36,179 @@ char const* const DEFAULT_METRIC_NAME = "metric"; class LL_COMMON_API LLMetricPerformanceTesterBasic { public: - /** - * @brief Creates a basic tester instance. - * @param[in] name - Unique string identifying this tester instance. - */ - LLMetricPerformanceTesterBasic(std::string name); - virtual ~LLMetricPerformanceTesterBasic(); - - /** - * @return Returns true if the instance has been added to the tester map. - * Need to be tested after creation of a tester instance so to know if the tester is correctly handled. - * A tester might not be added to the map if another tester with the same name already exists. - */ - BOOL isValid() const { return mValidInstance; } - - /** - * @brief Write a set of test results to the log LLSD. - */ - void outputTestResults() ; - - /** - * @brief Compare the test results. - * By default, compares the test results against the baseline one by one, item by item, - * in the increasing order of the LLSD record counter, starting from the first one. - */ - virtual void analyzePerformance(llofstream* os, LLSD* base, LLSD* current) ; - - static void doAnalysisMetrics(std::string baseline, std::string target, std::string output) ; - - /** - * @return Returns the number of the test metrics in this tester instance. - */ - auto getNumberOfMetrics() const { return mMetricStrings.size() ;} - /** - * @return Returns the metric name at index - * @param[in] index - Index on the list of metrics managed by this tester instance. - */ - std::string getMetricName(size_t index) const { return mMetricStrings[index] ;} + /** + * @brief Creates a basic tester instance. + * @param[in] name - Unique string identifying this tester instance. + */ + LLMetricPerformanceTesterBasic(std::string name); + virtual ~LLMetricPerformanceTesterBasic(); + + /** + * @return Returns true if the instance has been added to the tester map. + * Need to be tested after creation of a tester instance so to know if the tester is correctly handled. + * A tester might not be added to the map if another tester with the same name already exists. + */ + BOOL isValid() const { return mValidInstance; } + + /** + * @brief Write a set of test results to the log LLSD. + */ + void outputTestResults() ; + + /** + * @brief Compare the test results. + * By default, compares the test results against the baseline one by one, item by item, + * in the increasing order of the LLSD record counter, starting from the first one. + */ + virtual void analyzePerformance(llofstream* os, LLSD* base, LLSD* current) ; + + static void doAnalysisMetrics(std::string baseline, std::string target, std::string output) ; + + /** + * @return Returns the number of the test metrics in this tester instance. + */ + auto getNumberOfMetrics() const { return mMetricStrings.size() ;} + /** + * @return Returns the metric name at index + * @param[in] index - Index on the list of metrics managed by this tester instance. + */ + std::string getMetricName(size_t index) const { return mMetricStrings[index] ;} protected: - /** - * @return Returns the name of this tester instance. - */ - std::string getTesterName() const { return mName ;} - - /** - * @brief Insert a new metric to be managed by this tester instance. - * @param[in] str - Unique string identifying the new metric. - */ - void addMetric(std::string str) ; - - /** - * @brief Compare test results, provided in 2 flavors: compare integers and compare floats. - * @param[out] os - Formatted output string holding the compared values. - * @param[in] metric_string - Name of the metric. - * @param[in] v_base - Base value of the metric. - * @param[in] v_current - Current value of the metric. - */ - virtual void compareTestResults(llofstream* os, std::string metric_string, S32 v_base, S32 v_current) ; - virtual void compareTestResults(llofstream* os, std::string metric_string, F32 v_base, F32 v_current) ; - - /** - * @brief Reset internal record count. Count starts with 1. - */ - void resetCurrentCount() { mCount = 1; } - /** - * @brief Increment internal record count. - */ - void incrementCurrentCount() { mCount++; } - /** - * @return Returns the label to be used for the current count. It's "TesterName"-"Count". - */ - std::string getCurrentLabelName() const { return llformat("%s-%d", mName.c_str(), mCount) ;} - - /** - * @brief Write a test record to the LLSD. Implementers need to overload this method. - * @param[out] sd - The LLSD record to store metric data into. - */ - virtual void outputTestRecord(LLSD* sd) = 0 ; + /** + * @return Returns the name of this tester instance. + */ + std::string getTesterName() const { return mName ;} + + /** + * @brief Insert a new metric to be managed by this tester instance. + * @param[in] str - Unique string identifying the new metric. + */ + void addMetric(std::string str) ; + + /** + * @brief Compare test results, provided in 2 flavors: compare integers and compare floats. + * @param[out] os - Formatted output string holding the compared values. + * @param[in] metric_string - Name of the metric. + * @param[in] v_base - Base value of the metric. + * @param[in] v_current - Current value of the metric. + */ + virtual void compareTestResults(llofstream* os, std::string metric_string, S32 v_base, S32 v_current) ; + virtual void compareTestResults(llofstream* os, std::string metric_string, F32 v_base, F32 v_current) ; + + /** + * @brief Reset internal record count. Count starts with 1. + */ + void resetCurrentCount() { mCount = 1; } + /** + * @brief Increment internal record count. + */ + void incrementCurrentCount() { mCount++; } + /** + * @return Returns the label to be used for the current count. It's "TesterName"-"Count". + */ + std::string getCurrentLabelName() const { return llformat("%s-%d", mName.c_str(), mCount) ;} + + /** + * @brief Write a test record to the LLSD. Implementers need to overload this method. + * @param[out] sd - The LLSD record to store metric data into. + */ + virtual void outputTestRecord(LLSD* sd) = 0 ; private: - void preOutputTestResults(LLSD* sd) ; - void postOutputTestResults(LLSD* sd) ; - static LLSD analyzeMetricPerformanceLog(std::istream& is) ; + void preOutputTestResults(LLSD* sd) ; + void postOutputTestResults(LLSD* sd) ; + static LLSD analyzeMetricPerformanceLog(std::istream& is) ; - std::string mName ; // Name of this tester instance - S32 mCount ; // Current record count - BOOL mValidInstance; // TRUE if the instance is managed by the map - std::vector< std::string > mMetricStrings ; // Metrics strings + std::string mName ; // Name of this tester instance + S32 mCount ; // Current record count + BOOL mValidInstance; // TRUE if the instance is managed by the map + std::vector< std::string > mMetricStrings ; // Metrics strings // Static members managing the collection of testers -public: - // Map of all the tester instances in use - typedef std::map< std::string, LLMetricPerformanceTesterBasic* > name_tester_map_t; - static name_tester_map_t sTesterMap ; - - /** - * @return Returns a pointer to the tester - * @param[in] name - Name of the tester instance queried. - */ - static LLMetricPerformanceTesterBasic* getTester(std::string name) ; - - /** - * @return Delete the named tester from the list - * @param[in] name - Name of the tester instance to delete. - */ - static void deleteTester(std::string name); - - /** - * @return Returns TRUE if that metric *or* the default catch all metric has been requested to be logged - * @param[in] name - Name of the tester queried. - */ - static BOOL isMetricLogRequested(std::string name); - - /** - * @return Returns TRUE if there's a tester defined, FALSE otherwise. - */ - static BOOL hasMetricPerformanceTesters() { return !sTesterMap.empty() ;} - /** - * @brief Delete all testers and reset the tester map - */ - static void cleanupClass() ; +public: + // Map of all the tester instances in use + typedef std::map< std::string, LLMetricPerformanceTesterBasic* > name_tester_map_t; + static name_tester_map_t sTesterMap ; + + /** + * @return Returns a pointer to the tester + * @param[in] name - Name of the tester instance queried. + */ + static LLMetricPerformanceTesterBasic* getTester(std::string name) ; + + /** + * @return Delete the named tester from the list + * @param[in] name - Name of the tester instance to delete. + */ + static void deleteTester(std::string name); + + /** + * @return Returns TRUE if that metric *or* the default catch all metric has been requested to be logged + * @param[in] name - Name of the tester queried. + */ + static BOOL isMetricLogRequested(std::string name); + + /** + * @return Returns TRUE if there's a tester defined, FALSE otherwise. + */ + static BOOL hasMetricPerformanceTesters() { return !sTesterMap.empty() ;} + /** + * @brief Delete all testers and reset the tester map + */ + static void cleanupClass() ; private: - // Add a tester to the map. Returns false if adding fails. - static BOOL addTester(LLMetricPerformanceTesterBasic* tester) ; + // Add a tester to the map. Returns false if adding fails. + static BOOL addTester(LLMetricPerformanceTesterBasic* tester) ; }; /** * @class LLMetricPerformanceTesterWithSession - * @brief Performance Metric Class with custom session + * @brief Performance Metric Class with custom session */ class LL_COMMON_API LLMetricPerformanceTesterWithSession : public LLMetricPerformanceTesterBasic { public: - /** - * @param[in] name - Unique string identifying this tester instance. - */ - LLMetricPerformanceTesterWithSession(std::string name); - virtual ~LLMetricPerformanceTesterWithSession(); - - /** - * @brief Compare the test results. - * This will be loading the base and current sessions and compare them using the virtual - * abstract methods loadTestSession() and compareTestSessions() - */ - virtual void analyzePerformance(llofstream* os, LLSD* base, LLSD* current) ; + /** + * @param[in] name - Unique string identifying this tester instance. + */ + LLMetricPerformanceTesterWithSession(std::string name); + virtual ~LLMetricPerformanceTesterWithSession(); + + /** + * @brief Compare the test results. + * This will be loading the base and current sessions and compare them using the virtual + * abstract methods loadTestSession() and compareTestSessions() + */ + virtual void analyzePerformance(llofstream* os, LLSD* base, LLSD* current) ; protected: - /** - * @class LLMetricPerformanceTesterWithSession::LLTestSession - * @brief Defines an interface for the two abstract virtual functions loadTestSession() and compareTestSessions() - */ - class LL_COMMON_API LLTestSession - { - public: - virtual ~LLTestSession() ; - }; - - /** - * @brief Convert an LLSD log into a test session. - * @param[in] log - The LLSD record - * @return Returns the record as a test session - */ - virtual LLMetricPerformanceTesterWithSession::LLTestSession* loadTestSession(LLSD* log) = 0; - - /** - * @brief Compare the base session and the target session. Assumes base and current sessions have been loaded. - * @param[out] os - The comparison result as a standard stream - */ - virtual void compareTestSessions(llofstream* os) = 0; - - LLTestSession* mBaseSessionp; - LLTestSession* mCurrentSessionp; + /** + * @class LLMetricPerformanceTesterWithSession::LLTestSession + * @brief Defines an interface for the two abstract virtual functions loadTestSession() and compareTestSessions() + */ + class LL_COMMON_API LLTestSession + { + public: + virtual ~LLTestSession() ; + }; + + /** + * @brief Convert an LLSD log into a test session. + * @param[in] log - The LLSD record + * @return Returns the record as a test session + */ + virtual LLMetricPerformanceTesterWithSession::LLTestSession* loadTestSession(LLSD* log) = 0; + + /** + * @brief Compare the base session and the target session. Assumes base and current sessions have been loaded. + * @param[out] os - The comparison result as a standard stream + */ + virtual void compareTestSessions(llofstream* os) = 0; + + LLTestSession* mBaseSessionp; + LLTestSession* mCurrentSessionp; }; #endif diff --git a/indra/llcommon/llmetrics.cpp b/indra/llcommon/llmetrics.cpp index d40afe5160..7c37b18bab 100644 --- a/indra/llcommon/llmetrics.cpp +++ b/indra/llcommon/llmetrics.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llmetrics.cpp * @author Kelly * @date 2007-05-25 @@ -7,21 +7,21 @@ * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -36,128 +36,128 @@ class LLMetricsImpl { public: - LLMetricsImpl() { } - ~LLMetricsImpl(); - - void recordEvent(const std::string& location, const std::string& mesg, bool success); - void printTotals(LLSD metadata); - void recordEventDetails(const std::string& location, - const std::string& mesg, - bool success, - LLSD stats); + LLMetricsImpl() { } + ~LLMetricsImpl(); + + void recordEvent(const std::string& location, const std::string& mesg, bool success); + void printTotals(LLSD metadata); + void recordEventDetails(const std::string& location, + const std::string& mesg, + bool success, + LLSD stats); private: - LLFrameTimer mLastPrintTimer; - LLSD mMetricsMap; + LLFrameTimer mLastPrintTimer; + LLSD mMetricsMap; }; LLMetricsImpl::~LLMetricsImpl() { } -void LLMetricsImpl::recordEventDetails(const std::string& location, - const std::string& mesg, - bool success, - LLSD stats) +void LLMetricsImpl::recordEventDetails(const std::string& location, + const std::string& mesg, + bool success, + LLSD stats) { - recordEvent(location,mesg,success); + recordEvent(location,mesg,success); - LLSD metrics = LLSD::emptyMap(); - metrics["location"] = location; - metrics["stats"] = stats; - - LL_INFOS() << "LLMETRICS: " << (LLSDNotationStreamer(metrics)) << LL_ENDL; + LLSD metrics = LLSD::emptyMap(); + metrics["location"] = location; + metrics["stats"] = stats; + + LL_INFOS() << "LLMETRICS: " << (LLSDNotationStreamer(metrics)) << LL_ENDL; } // Store this: // [ {'location_1':{'mesg_1':{'success':i10, 'fail':i0}, -// 'mesg_2':{'success':i10, 'fail':i0}}, +// 'mesg_2':{'success':i10, 'fail':i0}}, // {'location_2',{'mesg_3':{'success':i10, 'fail':i0}} ] void LLMetricsImpl::recordEvent(const std::string& location, const std::string& mesg, bool success) { - LLSD& stats = mMetricsMap[location][mesg]; - if (success) - { - stats["success"] = stats["success"].asInteger() + 1; - } - else - { - stats["fail"] = stats["fail"].asInteger() + 1; - } + LLSD& stats = mMetricsMap[location][mesg]; + if (success) + { + stats["success"] = stats["success"].asInteger() + 1; + } + else + { + stats["fail"] = stats["fail"].asInteger() + 1; + } } // Print this: // { 'meta': -// { 'elapsed_time':r3600.000 } +// { 'elapsed_time':r3600.000 } // 'stats': -// [ {'location':'location_1', 'mesg':'mesg_1', 'success':i10, 'fail':i0}, -// {'location':'location_1', 'mesg':'mesg_2', 'success':i10, 'fail':i0}, -// {'location':'location_2', 'mesg':'mesg_3', 'success':i10, 'fail':i0} ] } +// [ {'location':'location_1', 'mesg':'mesg_1', 'success':i10, 'fail':i0}, +// {'location':'location_1', 'mesg':'mesg_2', 'success':i10, 'fail':i0}, +// {'location':'location_2', 'mesg':'mesg_3', 'success':i10, 'fail':i0} ] } void LLMetricsImpl::printTotals(LLSD metadata) { - F32 elapsed_time = mLastPrintTimer.getElapsedTimeAndResetF32(); - metadata["elapsed_time"] = elapsed_time; - - LLSD out_sd = LLSD::emptyMap(); - out_sd["meta"] = metadata; - - LLSD stats = LLSD::emptyArray(); - - LLSD::map_const_iterator loc_it = mMetricsMap.beginMap(); - LLSD::map_const_iterator loc_end = mMetricsMap.endMap(); - for ( ; loc_it != loc_end; ++loc_it) - { - const std::string& location = (*loc_it).first; - - const LLSD& loc_map = (*loc_it).second; - LLSD::map_const_iterator mesg_it = loc_map.beginMap(); - LLSD::map_const_iterator mesg_end = loc_map.endMap(); - for ( ; mesg_it != mesg_end; ++mesg_it) - { - const std::string& mesg = (*mesg_it).first; - const LLSD& mesg_map = (*mesg_it).second; - - LLSD entry = LLSD::emptyMap(); - entry["location"] = location; - entry["mesg"] = mesg; - entry["success"] = mesg_map["success"]; - entry["fail"] = mesg_map["fail"]; - - stats.append(entry); - } - } - - out_sd["stats"] = stats; - - LL_INFOS() << "LLMETRICS: AGGREGATE: " << LLSDOStreamer(out_sd) << LL_ENDL; + F32 elapsed_time = mLastPrintTimer.getElapsedTimeAndResetF32(); + metadata["elapsed_time"] = elapsed_time; + + LLSD out_sd = LLSD::emptyMap(); + out_sd["meta"] = metadata; + + LLSD stats = LLSD::emptyArray(); + + LLSD::map_const_iterator loc_it = mMetricsMap.beginMap(); + LLSD::map_const_iterator loc_end = mMetricsMap.endMap(); + for ( ; loc_it != loc_end; ++loc_it) + { + const std::string& location = (*loc_it).first; + + const LLSD& loc_map = (*loc_it).second; + LLSD::map_const_iterator mesg_it = loc_map.beginMap(); + LLSD::map_const_iterator mesg_end = loc_map.endMap(); + for ( ; mesg_it != mesg_end; ++mesg_it) + { + const std::string& mesg = (*mesg_it).first; + const LLSD& mesg_map = (*mesg_it).second; + + LLSD entry = LLSD::emptyMap(); + entry["location"] = location; + entry["mesg"] = mesg; + entry["success"] = mesg_map["success"]; + entry["fail"] = mesg_map["fail"]; + + stats.append(entry); + } + } + + out_sd["stats"] = stats; + + LL_INFOS() << "LLMETRICS: AGGREGATE: " << LLSDOStreamer(out_sd) << LL_ENDL; } LLMetrics::LLMetrics() { - mImpl = new LLMetricsImpl(); + mImpl = new LLMetricsImpl(); } LLMetrics::~LLMetrics() { - delete mImpl; - mImpl = NULL; + delete mImpl; + mImpl = NULL; } void LLMetrics::recordEvent(const std::string& location, const std::string& mesg, bool success) { - if (mImpl) mImpl->recordEvent(location,mesg,success); + if (mImpl) mImpl->recordEvent(location,mesg,success); } void LLMetrics::printTotals(LLSD meta) { - if (mImpl) mImpl->printTotals(meta); + if (mImpl) mImpl->printTotals(meta); } -void LLMetrics::recordEventDetails(const std::string& location, - const std::string& mesg, - bool success, - LLSD stats) +void LLMetrics::recordEventDetails(const std::string& location, + const std::string& mesg, + bool success, + LLSD stats) { - if (mImpl) mImpl->recordEventDetails(location,mesg,success,stats); + if (mImpl) mImpl->recordEventDetails(location,mesg,success,stats); } diff --git a/indra/llcommon/llmetrics.h b/indra/llcommon/llmetrics.h index 85a6986049..a6df49fc6a 100644 --- a/indra/llcommon/llmetrics.h +++ b/indra/llcommon/llmetrics.h @@ -7,21 +7,21 @@ * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -35,25 +35,25 @@ class LLSD; class LL_COMMON_API LLMetrics { public: - LLMetrics(); - virtual ~LLMetrics(); + LLMetrics(); + virtual ~LLMetrics(); - // Adds this event to aggregate totals and records details to syslog (LL_INFOS()) - virtual void recordEventDetails(const std::string& location, - const std::string& mesg, - bool success, - LLSD stats); + // Adds this event to aggregate totals and records details to syslog (LL_INFOS()) + virtual void recordEventDetails(const std::string& location, + const std::string& mesg, + bool success, + LLSD stats); - // Adds this event to aggregate totals - virtual void recordEvent(const std::string& location, const std::string& mesg, bool success); + // Adds this event to aggregate totals + virtual void recordEvent(const std::string& location, const std::string& mesg, bool success); - // Prints aggregate totals and resets the counts. - virtual void printTotals(LLSD meta); + // Prints aggregate totals and resets the counts. + virtual void printTotals(LLSD meta); private: - - LLMetricsImpl* mImpl; + + LLMetricsImpl* mImpl; }; #endif diff --git a/indra/llcommon/llmortician.cpp b/indra/llcommon/llmortician.cpp index b6ad40c2af..00d4a32553 100644 --- a/indra/llcommon/llmortician.cpp +++ b/indra/llcommon/llmortician.cpp @@ -1,24 +1,24 @@ -/** +/** * @file llmortician.cpp * * $LicenseInfo:firstyear=2005&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -32,9 +32,9 @@ std::list LLMortician::sGraveyard; BOOL LLMortician::sDestroyImmediate = FALSE; -LLMortician::~LLMortician() +LLMortician::~LLMortician() { - sGraveyard.remove(this); + sGraveyard.remove(this); } size_t LLMortician::logClass(std::stringstream &str) @@ -73,34 +73,34 @@ size_t LLMortician::logClass(std::stringstream &str) return size; } -void LLMortician::updateClass() +void LLMortician::updateClass() { - while (!sGraveyard.empty()) - { - LLMortician* dead = sGraveyard.front(); - delete dead; - } + while (!sGraveyard.empty()) + { + LLMortician* dead = sGraveyard.front(); + delete dead; + } } -void LLMortician::die() +void LLMortician::die() { - // It is valid to call die() more than once on something that hasn't died yet - if (sDestroyImmediate) - { - // *NOTE: This is a hack to ensure destruction order on shutdown (relative to non-mortician controlled classes). - mIsDead = TRUE; - delete this; - return; - } - else if (!mIsDead) - { - mIsDead = TRUE; - sGraveyard.push_back(this); - } + // It is valid to call die() more than once on something that hasn't died yet + if (sDestroyImmediate) + { + // *NOTE: This is a hack to ensure destruction order on shutdown (relative to non-mortician controlled classes). + mIsDead = TRUE; + delete this; + return; + } + else if (!mIsDead) + { + mIsDead = TRUE; + sGraveyard.push_back(this); + } } // static void LLMortician::setZealous(BOOL b) { - sDestroyImmediate = b; + sDestroyImmediate = b; } diff --git a/indra/llcommon/llmortician.h b/indra/llcommon/llmortician.h index f92c5a11db..6dca4da0c9 100644 --- a/indra/llcommon/llmortician.h +++ b/indra/llcommon/llmortician.h @@ -1,25 +1,25 @@ -/** +/** * @file llmortician.h * @brief Base class for delayed deletions. * * $LicenseInfo:firstyear=2005&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -30,26 +30,26 @@ #include "stdtypes.h" #include -class LL_COMMON_API LLMortician +class LL_COMMON_API LLMortician { public: - LLMortician() { mIsDead = FALSE; } - static auto graveyardCount() { return sGraveyard.size(); }; - static size_t logClass(std::stringstream &str); - static void updateClass(); - virtual ~LLMortician(); - void die(); - BOOL isDead() { return mIsDead; } + LLMortician() { mIsDead = FALSE; } + static auto graveyardCount() { return sGraveyard.size(); }; + static size_t logClass(std::stringstream &str); + static void updateClass(); + virtual ~LLMortician(); + void die(); + BOOL isDead() { return mIsDead; } - // sets destroy immediate true - static void setZealous(BOOL b); + // sets destroy immediate true + static void setZealous(BOOL b); private: - static BOOL sDestroyImmediate; + static BOOL sDestroyImmediate; - BOOL mIsDead; + BOOL mIsDead; - static std::list sGraveyard; + static std::list sGraveyard; }; #endif diff --git a/indra/llcommon/llmutex.cpp b/indra/llcommon/llmutex.cpp index 0273dd5970..db14abb1fe 100644 --- a/indra/llcommon/llmutex.cpp +++ b/indra/llcommon/llmutex.cpp @@ -1,24 +1,24 @@ -/** +/** * @file llmutex.cpp * * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -45,100 +45,100 @@ LLMutex::~LLMutex() void LLMutex::lock() { LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD - if(isSelfLocked()) - { //redundant lock - mCount++; - return; - } - - mMutex.lock(); - + if(isSelfLocked()) + { //redundant lock + mCount++; + return; + } + + mMutex.lock(); + #if MUTEX_DEBUG - // Have to have the lock before we can access the debug info - auto id = LLThread::currentID(); - if (mIsLocked[id] != FALSE) - LL_ERRS() << "Already locked in Thread: " << id << LL_ENDL; - mIsLocked[id] = TRUE; + // Have to have the lock before we can access the debug info + auto id = LLThread::currentID(); + if (mIsLocked[id] != FALSE) + LL_ERRS() << "Already locked in Thread: " << id << LL_ENDL; + mIsLocked[id] = TRUE; #endif - mLockingThread = LLThread::currentID(); + mLockingThread = LLThread::currentID(); } void LLMutex::unlock() { LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD - if (mCount > 0) - { //not the root unlock - mCount--; - return; - } - + if (mCount > 0) + { //not the root unlock + mCount--; + return; + } + #if MUTEX_DEBUG - // Access the debug info while we have the lock - auto id = LLThread::currentID(); - if (mIsLocked[id] != TRUE) - LL_ERRS() << "Not locked in Thread: " << id << LL_ENDL; - mIsLocked[id] = FALSE; + // Access the debug info while we have the lock + auto id = LLThread::currentID(); + if (mIsLocked[id] != TRUE) + LL_ERRS() << "Not locked in Thread: " << id << LL_ENDL; + mIsLocked[id] = FALSE; #endif - mLockingThread = LLThread::id_t(); - mMutex.unlock(); + mLockingThread = LLThread::id_t(); + mMutex.unlock(); } bool LLMutex::isLocked() { LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD - if (!mMutex.try_lock()) - { - return true; - } - else - { - mMutex.unlock(); - return false; - } + if (!mMutex.try_lock()) + { + return true; + } + else + { + mMutex.unlock(); + return false; + } } bool LLMutex::isSelfLocked() { - return mLockingThread == LLThread::currentID(); + return mLockingThread == LLThread::currentID(); } LLThread::id_t LLMutex::lockingThread() const { - return mLockingThread; + return mLockingThread; } bool LLMutex::trylock() { LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD - if(isSelfLocked()) - { //redundant lock - mCount++; - return true; - } - - if (!mMutex.try_lock()) - { - return false; - } - + if(isSelfLocked()) + { //redundant lock + mCount++; + return true; + } + + if (!mMutex.try_lock()) + { + return false; + } + #if MUTEX_DEBUG - // Have to have the lock before we can access the debug info - auto id = LLThread::currentID(); - if (mIsLocked[id] != FALSE) - LL_ERRS() << "Already locked in Thread: " << id << LL_ENDL; - mIsLocked[id] = TRUE; + // Have to have the lock before we can access the debug info + auto id = LLThread::currentID(); + if (mIsLocked[id] != FALSE) + LL_ERRS() << "Already locked in Thread: " << id << LL_ENDL; + mIsLocked[id] = TRUE; #endif - mLockingThread = LLThread::currentID(); - return true; + mLockingThread = LLThread::currentID(); + return true; } //============================================================================ LLCondition::LLCondition() : - LLMutex() + LLMutex() { } @@ -151,20 +151,20 @@ LLCondition::~LLCondition() void LLCondition::wait() { LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD - std::unique_lock< std::mutex > lock(mMutex); - mCond.wait(lock); + std::unique_lock< std::mutex > lock(mMutex); + mCond.wait(lock); } void LLCondition::signal() { LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD - mCond.notify_one(); + mCond.notify_one(); } void LLCondition::broadcast() { LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD - mCond.notify_all(); + mCond.notify_all(); } @@ -210,30 +210,30 @@ LLMutexTrylock::~LLMutexTrylock() LLScopedLock::LLScopedLock(std::mutex* mutex) : mMutex(mutex) { LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD - if(mutex) - { - mutex->lock(); - mLocked = true; - } - else - { - mLocked = false; - } + if(mutex) + { + mutex->lock(); + mLocked = true; + } + else + { + mLocked = false; + } } LLScopedLock::~LLScopedLock() { - unlock(); + unlock(); } void LLScopedLock::unlock() { LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD - if(mLocked) - { - mMutex->unlock(); - mLocked = false; - } + if(mLocked) + { + mMutex->unlock(); + mLocked = false; + } } //============================================================================ diff --git a/indra/llcommon/llmutex.h b/indra/llcommon/llmutex.h index 0d70da6178..9a888f1220 100644 --- a/indra/llcommon/llmutex.h +++ b/indra/llcommon/llmutex.h @@ -1,25 +1,25 @@ -/** +/** * @file llmutex.h * @brief Base classes for mutex and condition handling. * * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2012, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -46,23 +46,23 @@ class LL_COMMON_API LLMutex { public: - LLMutex(); - virtual ~LLMutex(); - - void lock(); // blocks - bool trylock(); // non-blocking, returns true if lock held. - void unlock(); // undefined behavior when called on mutex not being held - bool isLocked(); // non-blocking, but does do a lock/unlock so not free - bool isSelfLocked(); //return true if locked in a same thread - LLThread::id_t lockingThread() const; //get ID of locking thread + LLMutex(); + virtual ~LLMutex(); + + void lock(); // blocks + bool trylock(); // non-blocking, returns true if lock held. + void unlock(); // undefined behavior when called on mutex not being held + bool isLocked(); // non-blocking, but does do a lock/unlock so not free + bool isSelfLocked(); //return true if locked in a same thread + LLThread::id_t lockingThread() const; //get ID of locking thread protected: - std::mutex mMutex; - mutable U32 mCount; - mutable LLThread::id_t mLockingThread; - + std::mutex mMutex; + mutable U32 mCount; + mutable LLThread::id_t mLockingThread; + #if MUTEX_DEBUG - std::unordered_map mIsLocked; + std::unordered_map mIsLocked; #endif }; @@ -70,34 +70,34 @@ protected: class LL_COMMON_API LLCondition : public LLMutex { public: - LLCondition(); - ~LLCondition(); - - void wait(); // blocks - void signal(); - void broadcast(); - + LLCondition(); + ~LLCondition(); + + void wait(); // blocks + void signal(); + void broadcast(); + protected: - std::condition_variable mCond; + std::condition_variable mCond; }; class LLMutexLock { public: - LLMutexLock(LLMutex* mutex) - { - mMutex = mutex; - - if(mMutex) - mMutex->lock(); - } - ~LLMutexLock() - { - if(mMutex) - mMutex->unlock(); - } + LLMutexLock(LLMutex* mutex) + { + mMutex = mutex; + + if(mMutex) + mMutex->lock(); + } + ~LLMutexLock() + { + if(mMutex) + mMutex->unlock(); + } private: - LLMutex* mMutex; + LLMutex* mMutex; }; //============================================================================ @@ -113,18 +113,18 @@ private: class LLMutexTrylock { public: - LLMutexTrylock(LLMutex* mutex); - LLMutexTrylock(LLMutex* mutex, U32 aTries, U32 delay_ms = 10); - ~LLMutexTrylock(); - - bool isLocked() const - { - return mLocked; - } - + LLMutexTrylock(LLMutex* mutex); + LLMutexTrylock(LLMutex* mutex, U32 aTries, U32 delay_ms = 10); + ~LLMutexTrylock(); + + bool isLocked() const + { + return mLocked; + } + private: - LLMutex* mMutex; - bool mLocked; + LLMutex* mMutex; + bool mLocked; }; /** diff --git a/indra/llcommon/llnametable.h b/indra/llcommon/llnametable.h index 2c8e71263e..b3a9df8fc3 100644 --- a/indra/llcommon/llnametable.h +++ b/indra/llcommon/llnametable.h @@ -1,25 +1,25 @@ -/** +/** * @file llnametable.h * @brief LLNameTable class is a table to associate pointers with string names * * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -35,69 +35,69 @@ template class LLNameTable { public: - LLNameTable() - : mNameMap() - { - } + LLNameTable() + : mNameMap() + { + } - ~LLNameTable() - { - } + ~LLNameTable() + { + } - void addEntry(const std::string& name, DATA data) - { - addEntry(name.c_str(), data); - } + void addEntry(const std::string& name, DATA data) + { + addEntry(name.c_str(), data); + } - void addEntry(const char *name, DATA data) - { - char *tablename = gStringTable.addString(name); - mNameMap[tablename] = data; - } + void addEntry(const char *name, DATA data) + { + char *tablename = gStringTable.addString(name); + mNameMap[tablename] = data; + } - BOOL checkName(const std::string& name) const - { - return checkName(name.c_str()); - } + BOOL checkName(const std::string& name) const + { + return checkName(name.c_str()); + } - // "logically const" even though it modifies the global nametable - BOOL checkName(const char *name) const - { - char *tablename = gStringTable.addString(name); - return mNameMap.count(tablename) ? TRUE : FALSE; - } + // "logically const" even though it modifies the global nametable + BOOL checkName(const char *name) const + { + char *tablename = gStringTable.addString(name); + return mNameMap.count(tablename) ? TRUE : FALSE; + } - DATA resolveName(const std::string& name) const - { - return resolveName(name.c_str()); - } + DATA resolveName(const std::string& name) const + { + return resolveName(name.c_str()); + } - // "logically const" even though it modifies the global nametable - DATA resolveName(const char *name) const - { - char *tablename = gStringTable.addString(name); - const_iter_t iter = mNameMap.find(tablename); - if (iter != mNameMap.end()) - return iter->second; - else - return 0; - } + // "logically const" even though it modifies the global nametable + DATA resolveName(const char *name) const + { + char *tablename = gStringTable.addString(name); + const_iter_t iter = mNameMap.find(tablename); + if (iter != mNameMap.end()) + return iter->second; + else + return 0; + } - // O(N)! (currently only used in one place... (newsim/llstate.cpp)) - const char *resolveData(const DATA &data) const - { - for (const name_map_t::value_type& pair : mNameMap) - { - if (pair.second == data) - return pair.first; - } - return NULL; - } + // O(N)! (currently only used in one place... (newsim/llstate.cpp)) + const char *resolveData(const DATA &data) const + { + for (const name_map_t::value_type& pair : mNameMap) + { + if (pair.second == data) + return pair.first; + } + return NULL; + } - typedef std::map name_map_t; - typedef typename std::map::iterator iter_t; - typedef typename std::map::const_iterator const_iter_t; - name_map_t mNameMap; + typedef std::map name_map_t; + typedef typename std::map::iterator iter_t; + typedef typename std::map::const_iterator const_iter_t; + name_map_t mNameMap; }; #endif diff --git a/indra/llcommon/llpointer.h b/indra/llcommon/llpointer.h index 64aceddf32..f5916f9d58 100644 --- a/indra/llcommon/llpointer.h +++ b/indra/llcommon/llpointer.h @@ -1,32 +1,32 @@ -/** +/** * @file llpointer.h * @brief A reference-counted pointer for objects derived from LLRefCount * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ #ifndef LLPOINTER_H #define LLPOINTER_H -#include "llerror.h" // *TODO: consider eliminating this +#include "llerror.h" // *TODO: consider eliminating this #include "llmutex.h" //---------------------------------------------------------------------------- @@ -46,299 +46,299 @@ template class LLPointer { public: - LLPointer() : - mPointer(NULL) - { - } - - LLPointer(Type* ptr) : - mPointer(ptr) - { - ref(); - } - - LLPointer(const LLPointer& ptr) : - mPointer(ptr.mPointer) - { - ref(); - } - - // Support conversion up the type hierarchy. See Item 45 in Effective C++, 3rd Ed. - template - LLPointer(const LLPointer& ptr) : - mPointer(ptr.get()) - { - ref(); - } - - ~LLPointer() - { - unref(); - } - - Type* get() const { return mPointer; } - const Type* operator->() const { return mPointer; } - Type* operator->() { return mPointer; } - const Type& operator*() const { return *mPointer; } - Type& operator*() { return *mPointer; } - - operator BOOL() const { return (mPointer != NULL); } - operator bool() const { return (mPointer != NULL); } - bool operator!() const { return (mPointer == NULL); } - bool isNull() const { return (mPointer == NULL); } - bool notNull() const { return (mPointer != NULL); } - - operator Type*() const { return mPointer; } - bool operator !=(Type* ptr) const { return (mPointer != ptr); } - bool operator ==(Type* ptr) const { return (mPointer == ptr); } - bool operator ==(const LLPointer& ptr) const { return (mPointer == ptr.mPointer); } - bool operator < (const LLPointer& ptr) const { return (mPointer < ptr.mPointer); } - bool operator > (const LLPointer& ptr) const { return (mPointer > ptr.mPointer); } - - LLPointer& operator =(Type* ptr) - { - assign(ptr); - return *this; - } - - LLPointer& operator =(const LLPointer& ptr) - { - assign(ptr); - return *this; - } - - // support assignment up the type hierarchy. See Item 45 in Effective C++, 3rd Ed. - template - LLPointer& operator =(const LLPointer& ptr) - { - assign(ptr.get()); - return *this; - } - - // Just exchange the pointers, which will not change the reference counts. - static void swap(LLPointer& a, LLPointer& b) - { - Type* temp = a.mPointer; - a.mPointer = b.mPointer; - b.mPointer = temp; - } + LLPointer() : + mPointer(NULL) + { + } + + LLPointer(Type* ptr) : + mPointer(ptr) + { + ref(); + } + + LLPointer(const LLPointer& ptr) : + mPointer(ptr.mPointer) + { + ref(); + } + + // Support conversion up the type hierarchy. See Item 45 in Effective C++, 3rd Ed. + template + LLPointer(const LLPointer& ptr) : + mPointer(ptr.get()) + { + ref(); + } + + ~LLPointer() + { + unref(); + } + + Type* get() const { return mPointer; } + const Type* operator->() const { return mPointer; } + Type* operator->() { return mPointer; } + const Type& operator*() const { return *mPointer; } + Type& operator*() { return *mPointer; } + + operator BOOL() const { return (mPointer != NULL); } + operator bool() const { return (mPointer != NULL); } + bool operator!() const { return (mPointer == NULL); } + bool isNull() const { return (mPointer == NULL); } + bool notNull() const { return (mPointer != NULL); } + + operator Type*() const { return mPointer; } + bool operator !=(Type* ptr) const { return (mPointer != ptr); } + bool operator ==(Type* ptr) const { return (mPointer == ptr); } + bool operator ==(const LLPointer& ptr) const { return (mPointer == ptr.mPointer); } + bool operator < (const LLPointer& ptr) const { return (mPointer < ptr.mPointer); } + bool operator > (const LLPointer& ptr) const { return (mPointer > ptr.mPointer); } + + LLPointer& operator =(Type* ptr) + { + assign(ptr); + return *this; + } + + LLPointer& operator =(const LLPointer& ptr) + { + assign(ptr); + return *this; + } + + // support assignment up the type hierarchy. See Item 45 in Effective C++, 3rd Ed. + template + LLPointer& operator =(const LLPointer& ptr) + { + assign(ptr.get()); + return *this; + } + + // Just exchange the pointers, which will not change the reference counts. + static void swap(LLPointer& a, LLPointer& b) + { + Type* temp = a.mPointer; + a.mPointer = b.mPointer; + b.mPointer = temp; + } protected: #ifdef LL_LIBRARY_INCLUDE - void ref(); - void unref(); + void ref(); + void unref(); #else - void ref() - { - if (mPointer) - { - mPointer->ref(); - } - } - - void unref() - { - if (mPointer) - { - Type *temp = mPointer; - mPointer = NULL; - temp->unref(); - if (mPointer != NULL) - { - LL_WARNS() << "Unreference did assignment to non-NULL because of destructor" << LL_ENDL; - unref(); - } - } - } + void ref() + { + if (mPointer) + { + mPointer->ref(); + } + } + + void unref() + { + if (mPointer) + { + Type *temp = mPointer; + mPointer = NULL; + temp->unref(); + if (mPointer != NULL) + { + LL_WARNS() << "Unreference did assignment to non-NULL because of destructor" << LL_ENDL; + unref(); + } + } + } #endif // LL_LIBRARY_INCLUDE - void assign(const LLPointer& ptr) - { - if (mPointer != ptr.mPointer) - { - unref(); - mPointer = ptr.mPointer; - ref(); - } - } + void assign(const LLPointer& ptr) + { + if (mPointer != ptr.mPointer) + { + unref(); + mPointer = ptr.mPointer; + ref(); + } + } protected: - Type* mPointer; + Type* mPointer; }; template class LLConstPointer { public: - LLConstPointer() : - mPointer(NULL) - { - } - - LLConstPointer(const Type* ptr) : - mPointer(ptr) - { - ref(); - } - - LLConstPointer(const LLConstPointer& ptr) : - mPointer(ptr.mPointer) - { - ref(); - } - - // support conversion up the type hierarchy. See Item 45 in Effective C++, 3rd Ed. - template - LLConstPointer(const LLConstPointer& ptr) : - mPointer(ptr.get()) - { - ref(); - } - - ~LLConstPointer() - { - unref(); - } - - const Type* get() const { return mPointer; } - const Type* operator->() const { return mPointer; } - const Type& operator*() const { return *mPointer; } - - operator BOOL() const { return (mPointer != NULL); } - operator bool() const { return (mPointer != NULL); } - bool operator!() const { return (mPointer == NULL); } - bool isNull() const { return (mPointer == NULL); } - bool notNull() const { return (mPointer != NULL); } - - operator const Type*() const { return mPointer; } - bool operator !=(const Type* ptr) const { return (mPointer != ptr); } - bool operator ==(const Type* ptr) const { return (mPointer == ptr); } - bool operator ==(const LLConstPointer& ptr) const { return (mPointer == ptr.mPointer); } - bool operator < (const LLConstPointer& ptr) const { return (mPointer < ptr.mPointer); } - bool operator > (const LLConstPointer& ptr) const { return (mPointer > ptr.mPointer); } - - LLConstPointer& operator =(const Type* ptr) - { - if( mPointer != ptr ) - { - unref(); - mPointer = ptr; - ref(); - } - - return *this; - } - - LLConstPointer& operator =(const LLConstPointer& ptr) - { - if( mPointer != ptr.mPointer ) - { - unref(); - mPointer = ptr.mPointer; - ref(); - } - return *this; - } - - // support assignment up the type hierarchy. See Item 45 in Effective C++, 3rd Ed. - template - LLConstPointer& operator =(const LLConstPointer& ptr) - { - if( mPointer != ptr.get() ) - { - unref(); - mPointer = ptr.get(); - ref(); - } - return *this; - } - - // Just exchange the pointers, which will not change the reference counts. - static void swap(LLConstPointer& a, LLConstPointer& b) - { - const Type* temp = a.mPointer; - a.mPointer = b.mPointer; - b.mPointer = temp; - } + LLConstPointer() : + mPointer(NULL) + { + } + + LLConstPointer(const Type* ptr) : + mPointer(ptr) + { + ref(); + } + + LLConstPointer(const LLConstPointer& ptr) : + mPointer(ptr.mPointer) + { + ref(); + } + + // support conversion up the type hierarchy. See Item 45 in Effective C++, 3rd Ed. + template + LLConstPointer(const LLConstPointer& ptr) : + mPointer(ptr.get()) + { + ref(); + } + + ~LLConstPointer() + { + unref(); + } + + const Type* get() const { return mPointer; } + const Type* operator->() const { return mPointer; } + const Type& operator*() const { return *mPointer; } + + operator BOOL() const { return (mPointer != NULL); } + operator bool() const { return (mPointer != NULL); } + bool operator!() const { return (mPointer == NULL); } + bool isNull() const { return (mPointer == NULL); } + bool notNull() const { return (mPointer != NULL); } + + operator const Type*() const { return mPointer; } + bool operator !=(const Type* ptr) const { return (mPointer != ptr); } + bool operator ==(const Type* ptr) const { return (mPointer == ptr); } + bool operator ==(const LLConstPointer& ptr) const { return (mPointer == ptr.mPointer); } + bool operator < (const LLConstPointer& ptr) const { return (mPointer < ptr.mPointer); } + bool operator > (const LLConstPointer& ptr) const { return (mPointer > ptr.mPointer); } + + LLConstPointer& operator =(const Type* ptr) + { + if( mPointer != ptr ) + { + unref(); + mPointer = ptr; + ref(); + } + + return *this; + } + + LLConstPointer& operator =(const LLConstPointer& ptr) + { + if( mPointer != ptr.mPointer ) + { + unref(); + mPointer = ptr.mPointer; + ref(); + } + return *this; + } + + // support assignment up the type hierarchy. See Item 45 in Effective C++, 3rd Ed. + template + LLConstPointer& operator =(const LLConstPointer& ptr) + { + if( mPointer != ptr.get() ) + { + unref(); + mPointer = ptr.get(); + ref(); + } + return *this; + } + + // Just exchange the pointers, which will not change the reference counts. + static void swap(LLConstPointer& a, LLConstPointer& b) + { + const Type* temp = a.mPointer; + a.mPointer = b.mPointer; + b.mPointer = temp; + } protected: #ifdef LL_LIBRARY_INCLUDE - void ref(); - void unref(); + void ref(); + void unref(); #else // LL_LIBRARY_INCLUDE - void ref() - { - if (mPointer) - { - mPointer->ref(); - } - } - - void unref() - { - if (mPointer) - { - const Type *temp = mPointer; - mPointer = NULL; - temp->unref(); - if (mPointer != NULL) - { - LL_WARNS() << "Unreference did assignment to non-NULL because of destructor" << LL_ENDL; - unref(); - } - } - } + void ref() + { + if (mPointer) + { + mPointer->ref(); + } + } + + void unref() + { + if (mPointer) + { + const Type *temp = mPointer; + mPointer = NULL; + temp->unref(); + if (mPointer != NULL) + { + LL_WARNS() << "Unreference did assignment to non-NULL because of destructor" << LL_ENDL; + unref(); + } + } + } #endif // LL_LIBRARY_INCLUDE protected: - const Type* mPointer; + const Type* mPointer; }; template class LLCopyOnWritePointer : public LLPointer { public: - typedef LLCopyOnWritePointer self_t; - typedef LLPointer pointer_t; - - LLCopyOnWritePointer() - : mStayUnique(false) - {} - - LLCopyOnWritePointer(Type* ptr) - : LLPointer(ptr), - mStayUnique(false) - {} - - LLCopyOnWritePointer(LLPointer& ptr) - : LLPointer(ptr), - mStayUnique(false) - { - if (ptr.mForceUnique) - { - makeUnique(); - } - } - - Type* write() - { - makeUnique(); - return pointer_t::mPointer; - } - - void makeUnique() - { - if (pointer_t::notNull() && pointer_t::mPointer->getNumRefs() > 1) - { - *(pointer_t* )(this) = new Type(*pointer_t::mPointer); - } - } - - const Type* operator->() const { return pointer_t::mPointer; } - const Type& operator*() const { return *pointer_t::mPointer; } - - void setStayUnique(bool stay) { makeUnique(); mStayUnique = stay; } + typedef LLCopyOnWritePointer self_t; + typedef LLPointer pointer_t; + + LLCopyOnWritePointer() + : mStayUnique(false) + {} + + LLCopyOnWritePointer(Type* ptr) + : LLPointer(ptr), + mStayUnique(false) + {} + + LLCopyOnWritePointer(LLPointer& ptr) + : LLPointer(ptr), + mStayUnique(false) + { + if (ptr.mForceUnique) + { + makeUnique(); + } + } + + Type* write() + { + makeUnique(); + return pointer_t::mPointer; + } + + void makeUnique() + { + if (pointer_t::notNull() && pointer_t::mPointer->getNumRefs() > 1) + { + *(pointer_t* )(this) = new Type(*pointer_t::mPointer); + } + } + + const Type* operator->() const { return pointer_t::mPointer; } + const Type& operator*() const { return *pointer_t::mPointer; } + + void setStayUnique(bool stay) { makeUnique(); mStayUnique = stay; } private: - bool mStayUnique; + bool mStayUnique; }; diff --git a/indra/llcommon/llpredicate.cpp b/indra/llcommon/llpredicate.cpp index 1278948e24..fe80b77b63 100644 --- a/indra/llcommon/llpredicate.cpp +++ b/indra/llcommon/llpredicate.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llpredicate.cpp * @brief abstraction for filtering objects by predicates, with arbitrary boolean expressions * * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * 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$ */ @@ -29,13 +29,13 @@ namespace LLPredicate { - const U32 cPredicateFlagsFromEnum[5] = - { - 0xAAAAaaaa, // 10101010101010101010101010101010 - 0xCCCCcccc, // 11001100110011001100110011001100 - 0xF0F0F0F0, // 11110000111100001111000011110000 - 0xFF00FF00, // 11111111000000001111111100000000 - 0xFFFF0000 // 11111111111111110000000000000000 - }; + const U32 cPredicateFlagsFromEnum[5] = + { + 0xAAAAaaaa, // 10101010101010101010101010101010 + 0xCCCCcccc, // 11001100110011001100110011001100 + 0xF0F0F0F0, // 11110000111100001111000011110000 + 0xFF00FF00, // 11111111000000001111111100000000 + 0xFFFF0000 // 11111111111111110000000000000000 + }; } diff --git a/indra/llcommon/llpredicate.h b/indra/llcommon/llpredicate.h index e6c56a5711..7c6874d279 100644 --- a/indra/llcommon/llpredicate.h +++ b/indra/llcommon/llpredicate.h @@ -1,25 +1,25 @@ -/** +/** * @file llpredicate.h * @brief abstraction for filtering objects by predicates, with arbitrary boolean expressions * * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -31,179 +31,179 @@ namespace LLPredicate { - template class Rule; - - extern const U32 cPredicateFlagsFromEnum[5]; - - template - class Value - { - public: - typedef U32 predicate_flag_t; - static const S32 cMaxEnum = 5; - - Value(ENUM e, bool predicate_value = true) - : mPredicateFlags(predicate_value ? cPredicateFlagsFromEnum[e] : ~cPredicateFlagsFromEnum[e]) - { - llassert(0 <= e && e < cMaxEnum); - } - - Value() - : mPredicateFlags(0xFFFFffff) - {} - - Value operator!() const - { - Value new_value; - new_value.mPredicateFlags = ~mPredicateFlags; - return new_value; - } - - Value operator &&(const Value other) const - { - Value new_value; - new_value.mPredicateFlags = mPredicateFlags & other.mPredicateFlags; - return new_value; - } - - Value operator ||(const Value other) const - { - Value new_value; - new_value.mPredicateFlags = mPredicateFlags | other.mPredicateFlags; - return new_value; - } - - void set(ENUM e, bool value = true) - { - llassert(0 <= e && e < cMaxEnum); - predicate_flag_t flags_to_modify; - predicate_flag_t mask = cPredicateFlagsFromEnum[e]; - if (value) - { // add predicate "e" to flags that don't contain it already - flags_to_modify = (mPredicateFlags & ~mask); - // clear flags not containing e - mPredicateFlags &= mask; - // add back flags shifted to contain e - mPredicateFlags |= flags_to_modify << (0x1 << e); - } - else - { // remove predicate "e" from flags that contain it - flags_to_modify = (mPredicateFlags & mask); - // clear flags containing e - mPredicateFlags &= ~mask; - // add back flags shifted to not contain e - mPredicateFlags |= flags_to_modify >> (0x1 << e); - } - } - - void forget(ENUM e) - { - set(e, true); - U32 flags_with_predicate = mPredicateFlags; - set(e, false); - // ambiguous value is result of adding and removing predicate at the same time! - mPredicateFlags |= flags_with_predicate; - } - - bool allSet() const - { - return mPredicateFlags == ~0; - } - - bool noneSet() const - { - return mPredicateFlags == 0; - } - - bool someSet() const - { - return mPredicateFlags != 0; - } - - private: - predicate_flag_t mPredicateFlags; - }; - - template - class Rule - { - public: - Rule(ENUM value) - : mRule(value) - {} - - Rule(const Value other) - : mRule(other) - {} - - Rule() - {} - - void require(ENUM e, bool match) - { - mRule.set(e, match); - } - - void allow(ENUM e) - { - mRule.forget(e); - } - - bool check(const Value value) const - { - return (mRule && value).someSet(); - } - - bool requires(const Value value) const - { - return (mRule && value).someSet() && (!mRule && value).noneSet(); - } - - bool isAmbivalent(const Value value) const - { - return (mRule && value).someSet() && (!mRule && value).someSet(); - } - - bool acceptsAll() const - { - return mRule.allSet(); - } - - bool acceptsNone() const - { - return mRule.noneSet(); - } - - Rule operator!() const - { - Rule new_rule; - new_rule.mRule = !mRule; - return new_rule; - } - - Rule operator &&(const Rule other) const - { - Rule new_rule; - new_rule.mRule = mRule && other.mRule; - return new_rule; - } - - Rule operator ||(const Rule other) const - { - Rule new_rule; - new_rule.mRule = mRule || other.mRule; - return new_rule; - } - - private: - Value mRule; - }; + template class Rule; + + extern const U32 cPredicateFlagsFromEnum[5]; + + template + class Value + { + public: + typedef U32 predicate_flag_t; + static const S32 cMaxEnum = 5; + + Value(ENUM e, bool predicate_value = true) + : mPredicateFlags(predicate_value ? cPredicateFlagsFromEnum[e] : ~cPredicateFlagsFromEnum[e]) + { + llassert(0 <= e && e < cMaxEnum); + } + + Value() + : mPredicateFlags(0xFFFFffff) + {} + + Value operator!() const + { + Value new_value; + new_value.mPredicateFlags = ~mPredicateFlags; + return new_value; + } + + Value operator &&(const Value other) const + { + Value new_value; + new_value.mPredicateFlags = mPredicateFlags & other.mPredicateFlags; + return new_value; + } + + Value operator ||(const Value other) const + { + Value new_value; + new_value.mPredicateFlags = mPredicateFlags | other.mPredicateFlags; + return new_value; + } + + void set(ENUM e, bool value = true) + { + llassert(0 <= e && e < cMaxEnum); + predicate_flag_t flags_to_modify; + predicate_flag_t mask = cPredicateFlagsFromEnum[e]; + if (value) + { // add predicate "e" to flags that don't contain it already + flags_to_modify = (mPredicateFlags & ~mask); + // clear flags not containing e + mPredicateFlags &= mask; + // add back flags shifted to contain e + mPredicateFlags |= flags_to_modify << (0x1 << e); + } + else + { // remove predicate "e" from flags that contain it + flags_to_modify = (mPredicateFlags & mask); + // clear flags containing e + mPredicateFlags &= ~mask; + // add back flags shifted to not contain e + mPredicateFlags |= flags_to_modify >> (0x1 << e); + } + } + + void forget(ENUM e) + { + set(e, true); + U32 flags_with_predicate = mPredicateFlags; + set(e, false); + // ambiguous value is result of adding and removing predicate at the same time! + mPredicateFlags |= flags_with_predicate; + } + + bool allSet() const + { + return mPredicateFlags == ~0; + } + + bool noneSet() const + { + return mPredicateFlags == 0; + } + + bool someSet() const + { + return mPredicateFlags != 0; + } + + private: + predicate_flag_t mPredicateFlags; + }; + + template + class Rule + { + public: + Rule(ENUM value) + : mRule(value) + {} + + Rule(const Value other) + : mRule(other) + {} + + Rule() + {} + + void require(ENUM e, bool match) + { + mRule.set(e, match); + } + + void allow(ENUM e) + { + mRule.forget(e); + } + + bool check(const Value value) const + { + return (mRule && value).someSet(); + } + + bool requires(const Value value) const + { + return (mRule && value).someSet() && (!mRule && value).noneSet(); + } + + bool isAmbivalent(const Value value) const + { + return (mRule && value).someSet() && (!mRule && value).someSet(); + } + + bool acceptsAll() const + { + return mRule.allSet(); + } + + bool acceptsNone() const + { + return mRule.noneSet(); + } + + Rule operator!() const + { + Rule new_rule; + new_rule.mRule = !mRule; + return new_rule; + } + + Rule operator &&(const Rule other) const + { + Rule new_rule; + new_rule.mRule = mRule && other.mRule; + return new_rule; + } + + Rule operator ||(const Rule other) const + { + Rule new_rule; + new_rule.mRule = mRule || other.mRule; + return new_rule; + } + + private: + Value mRule; + }; } template LLPredicate::Value ll_make_predicate(ENUM e, bool predicate_value = true) { - return LLPredicate::Value(e, predicate_value); + return LLPredicate::Value(e, predicate_value); } diff --git a/indra/llcommon/llpreprocessor.h b/indra/llcommon/llpreprocessor.h index dc586b0008..a54408a852 100644 --- a/indra/llcommon/llpreprocessor.h +++ b/indra/llcommon/llpreprocessor.h @@ -1,4 +1,4 @@ -/** +/** * @file llpreprocessor.h * @brief This file should be included in all Linden Lab files and * should only contain special preprocessor directives @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -32,7 +32,7 @@ #ifdef LL_LINUX #define __ENABLE_WSTRING #include -#endif // LL_LINUX +#endif // LL_LINUX #if (defined(LL_WINDOWS) || (defined(LL_LINUX) && (__BYTE_ORDER == __LITTLE_ENDIAN)) || (defined(LL_DARWIN) && defined(__LITTLE_ENDIAN__))) #define LL_LITTLE_ENDIAN 1 @@ -64,31 +64,31 @@ // Figure out differences between compilers #if defined(__GNUC__) - #define GCC_VERSION (__GNUC__ * 10000 \ - + __GNUC_MINOR__ * 100 \ - + __GNUC_PATCHLEVEL__) - #ifndef LL_GNUC - #define LL_GNUC 1 - #endif + #define GCC_VERSION (__GNUC__ * 10000 \ + + __GNUC_MINOR__ * 100 \ + + __GNUC_PATCHLEVEL__) + #ifndef LL_GNUC + #define LL_GNUC 1 + #endif #elif defined(__MSVC_VER__) || defined(_MSC_VER) - #ifndef LL_MSVC - #define LL_MSVC 1 - #endif - #if _MSC_VER < 1400 - #define LL_MSVC7 //Visual C++ 2003 or earlier - #endif + #ifndef LL_MSVC + #define LL_MSVC 1 + #endif + #if _MSC_VER < 1400 + #define LL_MSVC7 //Visual C++ 2003 or earlier + #endif #endif // Deal with minor differences on Unixy OSes. #if LL_DARWIN || LL_LINUX - // Different name, same functionality. - #define stricmp strcasecmp - #define strnicmp strncasecmp + // Different name, same functionality. + #define stricmp strcasecmp + #define strnicmp strncasecmp - // Not sure why this is different, but... - #ifndef MAX_PATH - #define MAX_PATH PATH_MAX - #endif // not MAX_PATH + // Not sure why this is different, but... + #ifndef MAX_PATH + #define MAX_PATH PATH_MAX + #endif // not MAX_PATH #endif @@ -117,33 +117,33 @@ #ifndef XML_STATIC #define XML_STATIC #endif -#endif // LL_WINDOWS +#endif // LL_WINDOWS // Deal with VC6 problems #if LL_MSVC -#pragma warning( 3 : 4701 ) // "local variable used without being initialized" Treat this as level 3, not level 4. -#pragma warning( 3 : 4702 ) // "unreachable code" Treat this as level 3, not level 4. -#pragma warning( 3 : 4189 ) // "local variable initialized but not referenced" Treat this as level 3, not level 4. -//#pragma warning( 3 : 4018 ) // "signed/unsigned mismatch" Treat this as level 3, not level 4. -#pragma warning( 3 : 4263 ) // 'function' : member function does not override any base class virtual member function -#pragma warning( 3 : 4264 ) // "'virtual_function' : no override available for virtual member function from base 'class'; function is hidden" -#pragma warning( 3 : 4265 ) // "class has virtual functions, but destructor is not virtual" -#pragma warning( 3 : 4266 ) // 'function' : no override available for virtual member function from base 'type'; function is hidden -#pragma warning (disable : 4180) // qualifier applied to function type has no meaning; ignored -//#pragma warning( disable : 4284 ) // silly MS warning deep inside their include file +#pragma warning( 3 : 4701 ) // "local variable used without being initialized" Treat this as level 3, not level 4. +#pragma warning( 3 : 4702 ) // "unreachable code" Treat this as level 3, not level 4. +#pragma warning( 3 : 4189 ) // "local variable initialized but not referenced" Treat this as level 3, not level 4. +//#pragma warning( 3 : 4018 ) // "signed/unsigned mismatch" Treat this as level 3, not level 4. +#pragma warning( 3 : 4263 ) // 'function' : member function does not override any base class virtual member function +#pragma warning( 3 : 4264 ) // "'virtual_function' : no override available for virtual member function from base 'class'; function is hidden" +#pragma warning( 3 : 4265 ) // "class has virtual functions, but destructor is not virtual" +#pragma warning( 3 : 4266 ) // 'function' : no override available for virtual member function from base 'type'; function is hidden +#pragma warning (disable : 4180) // qualifier applied to function type has no meaning; ignored +//#pragma warning( disable : 4284 ) // silly MS warning deep inside their include file #if ADDRESS_SIZE == 64 // That one is all over the place for x64 builds. #pragma warning( disable : 4267 ) // 'var' : conversion from 'size_t' to 'type', possible loss of data) #endif -#pragma warning( disable : 4503 ) // 'decorated name length exceeded, name was truncated'. Does not seem to affect compilation. -#pragma warning( disable : 4800 ) // 'BOOL' : forcing value to bool 'true' or 'false' (performance warning) -#pragma warning( disable : 4996 ) // warning: deprecated +#pragma warning( disable : 4503 ) // 'decorated name length exceeded, name was truncated'. Does not seem to affect compilation. +#pragma warning( disable : 4800 ) // 'BOOL' : forcing value to bool 'true' or 'false' (performance warning) +#pragma warning( disable : 4996 ) // warning: deprecated // Linker optimization with "extern template" generates these warnings -#pragma warning( disable : 4231 ) // nonstandard extension used : 'extern' before template explicit instantiation +#pragma warning( disable : 4231 ) // nonstandard extension used : 'extern' before template explicit instantiation #pragma warning( disable : 4506 ) // no definition for inline function // level 4 warnings that we need to disable: @@ -156,9 +156,9 @@ #pragma warning (disable : 4251) // member needs to have dll-interface to be used by clients of class #pragma warning (disable : 4275) // non dll-interface class used as base for dll-interface class -#pragma warning (disable : 4018) // '<' : signed/unsigned mismatch +#pragma warning (disable : 4018) // '<' : signed/unsigned mismatch -#endif // LL_MSVC +#endif // LL_MSVC #if LL_WINDOWS #define LL_DLLEXPORT __declspec(dllexport) @@ -232,4 +232,4 @@ #define LL_PRETTY_FUNCTION __PRETTY_FUNCTION__ #endif -#endif // not LL_LINDEN_PREPROCESSOR_H +#endif // not LL_LINDEN_PREPROCESSOR_H diff --git a/indra/llcommon/llpriqueuemap.h b/indra/llcommon/llpriqueuemap.h index 030e2e0f21..79934d094b 100644 --- a/indra/llcommon/llpriqueuemap.h +++ b/indra/llcommon/llpriqueuemap.h @@ -1,25 +1,25 @@ -/** +/** * @file llpriqueuemap.h * @brief Priority queue implementation * * $LicenseInfo:firstyear=2003&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -39,107 +39,107 @@ template class LLPQMKey { public: - LLPQMKey(const F32 priority, DATA data) : mPriority(priority), mData(data) - { - } - - bool operator<(const LLPQMKey &b) const - { - if (mPriority > b.mPriority) - { - return TRUE; - } - if (mPriority < b.mPriority) - { - return FALSE; - } - if (mData > b.mData) - { - return TRUE; - } - return FALSE; - } - - F32 mPriority; - DATA mData; + LLPQMKey(const F32 priority, DATA data) : mPriority(priority), mData(data) + { + } + + bool operator<(const LLPQMKey &b) const + { + if (mPriority > b.mPriority) + { + return TRUE; + } + if (mPriority < b.mPriority) + { + return FALSE; + } + if (mData > b.mData) + { + return TRUE; + } + return FALSE; + } + + F32 mPriority; + DATA mData; }; template class LLPriQueueMap { public: - typedef typename std::map, DATA_TYPE>::iterator pqm_iter; - typedef std::pair, DATA_TYPE> pqm_pair; - typedef void (*set_pri_fn)(DATA_TYPE &data, const F32 priority); - typedef F32 (*get_pri_fn)(DATA_TYPE &data); + typedef typename std::map, DATA_TYPE>::iterator pqm_iter; + typedef std::pair, DATA_TYPE> pqm_pair; + typedef void (*set_pri_fn)(DATA_TYPE &data, const F32 priority); + typedef F32 (*get_pri_fn)(DATA_TYPE &data); - LLPriQueueMap(set_pri_fn set_pri, get_pri_fn get_pri) : mSetPriority(set_pri), mGetPriority(get_pri) - { - } + LLPriQueueMap(set_pri_fn set_pri, get_pri_fn get_pri) : mSetPriority(set_pri), mGetPriority(get_pri) + { + } - void push(const F32 priority, DATA_TYPE data) - { + void push(const F32 priority, DATA_TYPE data) + { #ifdef _DEBUG - pqm_iter iter = mMap.find(LLPQMKey(priority, data)); - if (iter != mMap.end()) - { - LL_ERRS() << "Pushing already existing data onto queue!" << LL_ENDL; - } + pqm_iter iter = mMap.find(LLPQMKey(priority, data)); + if (iter != mMap.end()) + { + LL_ERRS() << "Pushing already existing data onto queue!" << LL_ENDL; + } #endif - mMap.insert(pqm_pair(LLPQMKey(priority, data), data)); - } - - BOOL pop(DATA_TYPE *datap) - { - pqm_iter iter; - iter = mMap.begin(); - if (iter == mMap.end()) - { - return FALSE; - } - *datap = (*(iter)).second; - mMap.erase(iter); - - return TRUE; - } - - void reprioritize(const F32 new_priority, DATA_TYPE data) - { - pqm_iter iter; - F32 cur_priority = mGetPriority(data); - LLPQMKey cur_key(cur_priority, data); - iter = mMap.find(cur_key); - if (iter == mMap.end()) - { - LL_WARNS() << "Data not on priority queue!" << LL_ENDL; - // OK, try iterating through all of the data and seeing if we just screwed up the priority - // somehow. - for (pqm_pair pair : mMap) - { - if (pair.second == data) - { - LL_ERRS() << "Data on priority queue but priority not matched!" << LL_ENDL; - } - } - return; - } - - mMap.erase(iter); - mSetPriority(data, new_priority); - push(new_priority, data); - } - - S32 getLength() const - { - return (S32)mMap.size(); - } - - // Hack: public for use by the transfer manager, ugh. - std::map, DATA_TYPE> mMap; + mMap.insert(pqm_pair(LLPQMKey(priority, data), data)); + } + + BOOL pop(DATA_TYPE *datap) + { + pqm_iter iter; + iter = mMap.begin(); + if (iter == mMap.end()) + { + return FALSE; + } + *datap = (*(iter)).second; + mMap.erase(iter); + + return TRUE; + } + + void reprioritize(const F32 new_priority, DATA_TYPE data) + { + pqm_iter iter; + F32 cur_priority = mGetPriority(data); + LLPQMKey cur_key(cur_priority, data); + iter = mMap.find(cur_key); + if (iter == mMap.end()) + { + LL_WARNS() << "Data not on priority queue!" << LL_ENDL; + // OK, try iterating through all of the data and seeing if we just screwed up the priority + // somehow. + for (pqm_pair pair : mMap) + { + if (pair.second == data) + { + LL_ERRS() << "Data on priority queue but priority not matched!" << LL_ENDL; + } + } + return; + } + + mMap.erase(iter); + mSetPriority(data, new_priority); + push(new_priority, data); + } + + S32 getLength() const + { + return (S32)mMap.size(); + } + + // Hack: public for use by the transfer manager, ugh. + std::map, DATA_TYPE> mMap; protected: - void (*mSetPriority)(DATA_TYPE &data, const F32 priority); - F32 (*mGetPriority)(DATA_TYPE &data); + void (*mSetPriority)(DATA_TYPE &data, const F32 priority); + F32 (*mGetPriority)(DATA_TYPE &data); }; #endif // LL_LLPRIQUEUEMAP_H diff --git a/indra/llcommon/llprocess.cpp b/indra/llcommon/llprocess.cpp index 0d6a147da3..2208b33b94 100644 --- a/indra/llcommon/llprocess.cpp +++ b/indra/llcommon/llprocess.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llprocess.cpp * @brief Utility class for launching, terminating, and tracking the state of processes. * * $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$ */ @@ -57,9 +57,9 @@ static std::string getDesc(const LLProcess::Params& params); static std::string whichfile(LLProcess::FILESLOT index) { - if (index < LL_ARRAY_SIZE(whichfile_)) - return whichfile_[index]; - return STRINGIZE("file slot " << index); + if (index < LL_ARRAY_SIZE(whichfile_)) + return whichfile_[index]; + return STRINGIZE("file slot " << index); } /** @@ -69,64 +69,64 @@ static std::string whichfile(LLProcess::FILESLOT index) */ class LLProcessListener { - LOG_CLASS(LLProcessListener); + LOG_CLASS(LLProcessListener); public: - LLProcessListener(): - mCount(0) - {} - - void addPoll(const LLProcess&) - { - // Unconditionally increment mCount. If it was zero before - // incrementing, listen on "mainloop". - if (mCount++ == 0) - { - LL_DEBUGS("LLProcess") << "listening on \"mainloop\"" << LL_ENDL; - mConnection = LLEventPumps::instance().obtain("mainloop") - .listen("LLProcessListener", boost::bind(&LLProcessListener::tick, this, _1)); - } - } - - void dropPoll(const LLProcess&) - { - // Unconditionally decrement mCount. If it's zero after decrementing, - // stop listening on "mainloop". - if (--mCount == 0) - { - LL_DEBUGS("LLProcess") << "disconnecting from \"mainloop\"" << LL_ENDL; - mConnection.disconnect(); - } - } + LLProcessListener(): + mCount(0) + {} + + void addPoll(const LLProcess&) + { + // Unconditionally increment mCount. If it was zero before + // incrementing, listen on "mainloop". + if (mCount++ == 0) + { + LL_DEBUGS("LLProcess") << "listening on \"mainloop\"" << LL_ENDL; + mConnection = LLEventPumps::instance().obtain("mainloop") + .listen("LLProcessListener", boost::bind(&LLProcessListener::tick, this, _1)); + } + } + + void dropPoll(const LLProcess&) + { + // Unconditionally decrement mCount. If it's zero after decrementing, + // stop listening on "mainloop". + if (--mCount == 0) + { + LL_DEBUGS("LLProcess") << "disconnecting from \"mainloop\"" << LL_ENDL; + mConnection.disconnect(); + } + } private: - /// called once per frame by the "mainloop" LLEventPump - bool tick(const LLSD&) - { - // Tell APR to sense whether each registered LLProcess is still - // running and call handle_status() appropriately. We should be able - // to get the same info from an apr_proc_wait(APR_NOWAIT) call; but at - // least in APR 1.4.2, testing suggests that even with APR_NOWAIT, - // apr_proc_wait() blocks the caller. We can't have that in the - // viewer. Hence the callback rigmarole. (Once we update APR, it's - // probably worth testing again.) Also -- although there's an - // apr_proc_other_child_refresh() call, i.e. get that information for - // one specific child, it accepts an 'apr_other_child_rec_t*' that's - // mentioned NOWHERE else in the documentation or header files! I - // would use the specific call in LLProcess::getStatus() if I knew - // how. As it is, each call to apr_proc_other_child_refresh_all() will - // call callbacks for ALL still-running child processes. That's why we - // centralize such calls, using "mainloop" to ensure it happens once - // per frame, and refcounting running LLProcess objects to remain - // registered only while needed. - LL_DEBUGS("LLProcess") << "calling apr_proc_other_child_refresh_all()" << LL_ENDL; - apr_proc_other_child_refresh_all(APR_OC_REASON_RUNNING); - return false; - } - - /// If this object is destroyed before mCount goes to zero, stop - /// listening on "mainloop" anyway. - LLTempBoundListener mConnection; - unsigned mCount; + /// called once per frame by the "mainloop" LLEventPump + bool tick(const LLSD&) + { + // Tell APR to sense whether each registered LLProcess is still + // running and call handle_status() appropriately. We should be able + // to get the same info from an apr_proc_wait(APR_NOWAIT) call; but at + // least in APR 1.4.2, testing suggests that even with APR_NOWAIT, + // apr_proc_wait() blocks the caller. We can't have that in the + // viewer. Hence the callback rigmarole. (Once we update APR, it's + // probably worth testing again.) Also -- although there's an + // apr_proc_other_child_refresh() call, i.e. get that information for + // one specific child, it accepts an 'apr_other_child_rec_t*' that's + // mentioned NOWHERE else in the documentation or header files! I + // would use the specific call in LLProcess::getStatus() if I knew + // how. As it is, each call to apr_proc_other_child_refresh_all() will + // call callbacks for ALL still-running child processes. That's why we + // centralize such calls, using "mainloop" to ensure it happens once + // per frame, and refcounting running LLProcess objects to remain + // registered only while needed. + LL_DEBUGS("LLProcess") << "calling apr_proc_other_child_refresh_all()" << LL_ENDL; + apr_proc_other_child_refresh_all(APR_OC_REASON_RUNNING); + return false; + } + + /// If this object is destroyed before mCount goes to zero, stop + /// listening on "mainloop" anyway. + LLTempBoundListener mConnection; + unsigned mCount; }; static LLProcessListener sProcessListener; @@ -135,141 +135,141 @@ static LLProcessListener sProcessListener; *****************************************************************************/ LLProcess::BasePipe::~BasePipe() {} const LLProcess::BasePipe::size_type - // use funky syntax to call max() to avoid blighted max() macros - LLProcess::BasePipe::npos((std::numeric_limits::max)()); + // use funky syntax to call max() to avoid blighted max() macros + LLProcess::BasePipe::npos((std::numeric_limits::max)()); class WritePipeImpl: public LLProcess::WritePipe { - LOG_CLASS(WritePipeImpl); + LOG_CLASS(WritePipeImpl); public: - WritePipeImpl(const std::string& desc, apr_file_t* pipe): - mDesc(desc), - mPipe(pipe), - // Essential to initialize our std::ostream with our special streambuf! - mStream(&mStreambuf) - { - mConnection = LLEventPumps::instance().obtain("mainloop") - .listen(LLEventPump::inventName("WritePipe"), - boost::bind(&WritePipeImpl::tick, this, _1)); + WritePipeImpl(const std::string& desc, apr_file_t* pipe): + mDesc(desc), + mPipe(pipe), + // Essential to initialize our std::ostream with our special streambuf! + mStream(&mStreambuf) + { + mConnection = LLEventPumps::instance().obtain("mainloop") + .listen(LLEventPump::inventName("WritePipe"), + boost::bind(&WritePipeImpl::tick, this, _1)); #if ! LL_WINDOWS - // We can't count on every child process reading everything we try to - // write to it. And if the child terminates with WritePipe data still - // pending, unless we explicitly suppress it, Posix will hit us with - // SIGPIPE. That would terminate the viewer, boom. "Ignoring" it means - // APR gets the correct errno, passes it back to us, we log it, etc. - signal(SIGPIPE, SIG_IGN); + // We can't count on every child process reading everything we try to + // write to it. And if the child terminates with WritePipe data still + // pending, unless we explicitly suppress it, Posix will hit us with + // SIGPIPE. That would terminate the viewer, boom. "Ignoring" it means + // APR gets the correct errno, passes it back to us, we log it, etc. + signal(SIGPIPE, SIG_IGN); #endif - } - - virtual std::ostream& get_ostream() { return mStream; } - virtual size_type size() const { return mStreambuf.size(); } - - bool tick(const LLSD&) - { - typedef boost::asio::streambuf::const_buffers_type const_buffer_sequence; - // If there's anything to send, try to send it. - std::size_t total(mStreambuf.size()), consumed(0); - if (total) - { - const_buffer_sequence bufs = mStreambuf.data(); - // In general, our streambuf might contain a number of different - // physical buffers; iterate over those. - bool keepwriting = true; - for (const_buffer_sequence::const_iterator bufi(bufs.begin()), bufend(bufs.end()); - bufi != bufend && keepwriting; ++bufi) - { - // http://www.boost.org/doc/libs/1_49_0_beta1/doc/html/boost_asio/reference/buffer.html#boost_asio.reference.buffer.accessing_buffer_contents - // Although apr_file_write() accepts const void*, we - // manipulate const char* so we can increment the pointer. - const char* remainptr = boost::asio::buffer_cast(*bufi); - std::size_t remainlen = boost::asio::buffer_size(*bufi); - while (remainlen) - { - // Tackle the current buffer in discrete chunks. On - // Windows, we've observed strange failures when trying to - // write big lengths (~1 MB) in a single operation. Even a - // 32K chunk seems too large. At some point along the way - // apr_file_write() returns 11 (Resource temporarily - // unavailable, i.e. EAGAIN) and says it wrote 0 bytes -- - // even though it did write the chunk! Our next write - // attempt retries with the same chunk, resulting in the - // chunk being duplicated at the child end. Using smaller - // chunks is empirically more reliable. - std::size_t towrite((std::min)(remainlen, std::size_t(4*1024))); - apr_size_t written(towrite); - apr_status_t err = apr_file_write(mPipe, remainptr, &written); - // EAGAIN is exactly what we want from a nonblocking pipe. - // Rather than waiting for data, it should return immediately. - if (! (err == APR_SUCCESS || APR_STATUS_IS_EAGAIN(err))) - { - LL_WARNS("LLProcess") << "apr_file_write(" << towrite << ") on " << mDesc - << " got " << err << ":" << LL_ENDL; - ll_apr_warn_status(err); - } - - // 'written' is modified to reflect the number of bytes actually - // written. Make sure we consume those later. (Don't consume them - // now, that would invalidate the buffer iterator sequence!) - consumed += written; - // don't forget to advance to next chunk of current buffer - remainptr += written; - remainlen -= written; - - char msgbuf[512]; - LL_DEBUGS("LLProcess") << "wrote " << written << " of " << towrite - << " bytes to " << mDesc - << " (original " << total << ")," - << " code " << err << ": " - << apr_strerror(err, msgbuf, sizeof(msgbuf)) - << LL_ENDL; - - // The parent end of this pipe is nonblocking. If we weren't able - // to write everything we wanted, don't keep banging on it -- that - // won't change until the child reads some. Wait for next tick(). - if (written < towrite) - { - keepwriting = false; // break outer loop over buffers too - break; - } - } // next chunk of current buffer - } // next buffer - // In all, we managed to write 'consumed' bytes. Remove them from the - // streambuf so we don't keep trying to send them. This could be - // anywhere from 0 up to mStreambuf.size(); anything we haven't yet - // sent, we'll try again later. - mStreambuf.consume(consumed); - } - - return false; - } + } + + virtual std::ostream& get_ostream() { return mStream; } + virtual size_type size() const { return mStreambuf.size(); } + + bool tick(const LLSD&) + { + typedef boost::asio::streambuf::const_buffers_type const_buffer_sequence; + // If there's anything to send, try to send it. + std::size_t total(mStreambuf.size()), consumed(0); + if (total) + { + const_buffer_sequence bufs = mStreambuf.data(); + // In general, our streambuf might contain a number of different + // physical buffers; iterate over those. + bool keepwriting = true; + for (const_buffer_sequence::const_iterator bufi(bufs.begin()), bufend(bufs.end()); + bufi != bufend && keepwriting; ++bufi) + { + // http://www.boost.org/doc/libs/1_49_0_beta1/doc/html/boost_asio/reference/buffer.html#boost_asio.reference.buffer.accessing_buffer_contents + // Although apr_file_write() accepts const void*, we + // manipulate const char* so we can increment the pointer. + const char* remainptr = boost::asio::buffer_cast(*bufi); + std::size_t remainlen = boost::asio::buffer_size(*bufi); + while (remainlen) + { + // Tackle the current buffer in discrete chunks. On + // Windows, we've observed strange failures when trying to + // write big lengths (~1 MB) in a single operation. Even a + // 32K chunk seems too large. At some point along the way + // apr_file_write() returns 11 (Resource temporarily + // unavailable, i.e. EAGAIN) and says it wrote 0 bytes -- + // even though it did write the chunk! Our next write + // attempt retries with the same chunk, resulting in the + // chunk being duplicated at the child end. Using smaller + // chunks is empirically more reliable. + std::size_t towrite((std::min)(remainlen, std::size_t(4*1024))); + apr_size_t written(towrite); + apr_status_t err = apr_file_write(mPipe, remainptr, &written); + // EAGAIN is exactly what we want from a nonblocking pipe. + // Rather than waiting for data, it should return immediately. + if (! (err == APR_SUCCESS || APR_STATUS_IS_EAGAIN(err))) + { + LL_WARNS("LLProcess") << "apr_file_write(" << towrite << ") on " << mDesc + << " got " << err << ":" << LL_ENDL; + ll_apr_warn_status(err); + } + + // 'written' is modified to reflect the number of bytes actually + // written. Make sure we consume those later. (Don't consume them + // now, that would invalidate the buffer iterator sequence!) + consumed += written; + // don't forget to advance to next chunk of current buffer + remainptr += written; + remainlen -= written; + + char msgbuf[512]; + LL_DEBUGS("LLProcess") << "wrote " << written << " of " << towrite + << " bytes to " << mDesc + << " (original " << total << ")," + << " code " << err << ": " + << apr_strerror(err, msgbuf, sizeof(msgbuf)) + << LL_ENDL; + + // The parent end of this pipe is nonblocking. If we weren't able + // to write everything we wanted, don't keep banging on it -- that + // won't change until the child reads some. Wait for next tick(). + if (written < towrite) + { + keepwriting = false; // break outer loop over buffers too + break; + } + } // next chunk of current buffer + } // next buffer + // In all, we managed to write 'consumed' bytes. Remove them from the + // streambuf so we don't keep trying to send them. This could be + // anywhere from 0 up to mStreambuf.size(); anything we haven't yet + // sent, we'll try again later. + mStreambuf.consume(consumed); + } + + return false; + } private: - std::string mDesc; - apr_file_t* mPipe; - LLTempBoundListener mConnection; - boost::asio::streambuf mStreambuf; - std::ostream mStream; + std::string mDesc; + apr_file_t* mPipe; + LLTempBoundListener mConnection; + boost::asio::streambuf mStreambuf; + std::ostream mStream; }; class ReadPipeImpl: public LLProcess::ReadPipe { - LOG_CLASS(ReadPipeImpl); + LOG_CLASS(ReadPipeImpl); public: - ReadPipeImpl(const std::string& desc, apr_file_t* pipe, LLProcess::FILESLOT index): - mDesc(desc), - mPipe(pipe), - mIndex(index), - // Essential to initialize our std::istream with our special streambuf! - mStream(&mStreambuf), - mPump("ReadPipe", true), // tweak name as needed to avoid collisions - mLimit(0), - mEOF(false) - { - mConnection = LLEventPumps::instance().obtain("mainloop") - .listen(LLEventPump::inventName("ReadPipe"), - boost::bind(&ReadPipeImpl::tick, this, _1)); - } + ReadPipeImpl(const std::string& desc, apr_file_t* pipe, LLProcess::FILESLOT index): + mDesc(desc), + mPipe(pipe), + mIndex(index), + // Essential to initialize our std::istream with our special streambuf! + mStream(&mStreambuf), + mPump("ReadPipe", true), // tweak name as needed to avoid collisions + mLimit(0), + mEOF(false) + { + mConnection = LLEventPumps::instance().obtain("mainloop") + .listen(LLEventPump::inventName("ReadPipe"), + boost::bind(&ReadPipeImpl::tick, this, _1)); + } ~ReadPipeImpl() { @@ -279,200 +279,200 @@ public: } } - // Much of the implementation is simply connecting the abstract virtual - // methods with implementation data concealed from the base class. - virtual std::istream& get_istream() { return mStream; } - virtual std::string getline() { return LLProcess::getline(mStream); } - virtual LLEventPump& getPump() { return mPump; } - virtual void setLimit(size_type limit) { mLimit = limit; } - virtual size_type getLimit() const { return mLimit; } - virtual size_type size() const { return mStreambuf.size(); } - - virtual std::string read(size_type len) - { - // Read specified number of bytes into a buffer. - size_type readlen((std::min)(size(), len)); - // Formally, &buffer[0] is invalid for a vector of size() 0. Exit - // early in that situation. - if (! readlen) - return ""; - // Make a buffer big enough. - std::vector buffer(readlen); - mStream.read(&buffer[0], readlen); - // Since we've already clamped 'readlen', we can think of no reason - // why mStream.read() should read fewer than 'readlen' bytes. - // Nonetheless, use the actual retrieved length. - return std::string(&buffer[0], mStream.gcount()); - } - - virtual std::string peek(size_type offset=0, size_type len=npos) const - { - // Constrain caller's offset and len to overlap actual buffer content. - std::size_t real_offset = (std::min)(mStreambuf.size(), std::size_t(offset)); - size_type want_end = (len == npos)? npos : (real_offset + len); - std::size_t real_end = (std::min)(mStreambuf.size(), std::size_t(want_end)); - boost::asio::streambuf::const_buffers_type cbufs = mStreambuf.data(); - return std::string(boost::asio::buffers_begin(cbufs) + real_offset, - boost::asio::buffers_begin(cbufs) + real_end); - } - - virtual size_type find(const std::string& seek, size_type offset=0) const - { - // If we're passing a string of length 1, use find(char), which can - // use an O(n) std::find() rather than the O(n^2) std::search(). - if (seek.length() == 1) - { - return find(seek[0], offset); - } - - // If offset is beyond the whole buffer, can't even construct a valid - // iterator range; can't possibly find the string we seek. - if (offset > mStreambuf.size()) - { - return npos; - } - - boost::asio::streambuf::const_buffers_type cbufs = mStreambuf.data(); - boost::asio::buffers_iterator - begin(boost::asio::buffers_begin(cbufs)), - end (boost::asio::buffers_end(cbufs)), - found(std::search(begin + offset, end, seek.begin(), seek.end())); - return (found == end)? npos : (found - begin); - } - - virtual size_type find(char seek, size_type offset=0) const - { - // If offset is beyond the whole buffer, can't even construct a valid - // iterator range; can't possibly find the char we seek. - if (offset > mStreambuf.size()) - { - return npos; - } - - boost::asio::streambuf::const_buffers_type cbufs = mStreambuf.data(); - boost::asio::buffers_iterator - begin(boost::asio::buffers_begin(cbufs)), - end (boost::asio::buffers_end(cbufs)), - found(std::find(begin + offset, end, seek)); - return (found == end)? npos : (found - begin); - } - - bool tick(const LLSD&) - { - // Once we've hit EOF, skip all the rest of this. - if (mEOF) - return false; - - typedef boost::asio::streambuf::mutable_buffers_type mutable_buffer_sequence; - // Try, every time, to read into our streambuf. In fact, we have no - // idea how much data the child might be trying to send: keep trying - // until we're convinced we've temporarily exhausted the pipe. - enum PipeState { RETRY, EXHAUSTED, CLOSED }; - PipeState state = RETRY; - std::size_t committed(0); - do - { - // attempt to read an arbitrary size - mutable_buffer_sequence bufs = mStreambuf.prepare(4096); - // In general, the mutable_buffer_sequence returned by prepare() might - // contain a number of different physical buffers; iterate over those. - std::size_t tocommit(0); - for (mutable_buffer_sequence::const_iterator bufi(bufs.begin()), bufend(bufs.end()); - bufi != bufend; ++bufi) - { - // http://www.boost.org/doc/libs/1_49_0_beta1/doc/html/boost_asio/reference/buffer.html#boost_asio.reference.buffer.accessing_buffer_contents - std::size_t toread(boost::asio::buffer_size(*bufi)); - apr_size_t gotten(toread); - apr_status_t err = apr_file_read(mPipe, - boost::asio::buffer_cast(*bufi), - &gotten); - // EAGAIN is exactly what we want from a nonblocking pipe. - // Rather than waiting for data, it should return immediately. - if (! (err == APR_SUCCESS || APR_STATUS_IS_EAGAIN(err))) - { - // Handle EOF specially: it's part of normal-case processing. - if (err == APR_EOF) - { - LL_DEBUGS("LLProcess") << "EOF on " << mDesc << LL_ENDL; - } - else - { - LL_WARNS("LLProcess") << "apr_file_read(" << toread << ") on " << mDesc - << " got " << err << ":" << LL_ENDL; - ll_apr_warn_status(err); - } - // Either way, though, we won't need any more tick() calls. - mConnection.disconnect(); - // Ignore any subsequent calls we might get anyway. - mEOF = true; - state = CLOSED; // also break outer retry loop - break; - } - - // 'gotten' was modified to reflect the number of bytes actually - // received. Make sure we commit those later. (Don't commit them - // now, that would invalidate the buffer iterator sequence!) - tocommit += gotten; - LL_DEBUGS("LLProcess") << "filled " << gotten << " of " << toread - << " bytes from " << mDesc << LL_ENDL; - - // The parent end of this pipe is nonblocking. If we weren't even - // able to fill this buffer, don't loop to try to fill the next -- - // that won't change until the child writes more. Wait for next - // tick(). - if (gotten < toread) - { - // break outer retry loop too - state = EXHAUSTED; - break; - } - } - - // Don't forget to "commit" the data! - mStreambuf.commit(tocommit); - committed += tocommit; - - // state is changed from RETRY when we can't fill any one buffer - // of the mutable_buffer_sequence established by the current - // prepare() call -- whether due to error or not enough bytes. - // That is, if state is still RETRY, we've filled every physical - // buffer in the mutable_buffer_sequence. In that case, for all we - // know, the child might have still more data pending -- go for it! - } while (state == RETRY); - - // Once we recognize that the pipe is closed, make one more call to - // listener. The listener might be waiting for a particular substring - // to arrive, or a particular length of data or something. The event - // with "eof" == true announces that nothing further will arrive, so - // use it or lose it. - if (committed || state == CLOSED) - { - // If we actually received new data, publish it on our LLEventPump - // as advertised. Constrain it by mLimit. But show listener the - // actual accumulated buffer size, regardless of mLimit. - size_type datasize((std::min)(mLimit, size_type(mStreambuf.size()))); - mPump.post(LLSDMap - ("data", peek(0, datasize)) - ("len", LLSD::Integer(mStreambuf.size())) - ("slot", LLSD::Integer(mIndex)) - ("name", whichfile(mIndex)) - ("desc", mDesc) - ("eof", state == CLOSED)); - } - - return false; - } + // Much of the implementation is simply connecting the abstract virtual + // methods with implementation data concealed from the base class. + virtual std::istream& get_istream() { return mStream; } + virtual std::string getline() { return LLProcess::getline(mStream); } + virtual LLEventPump& getPump() { return mPump; } + virtual void setLimit(size_type limit) { mLimit = limit; } + virtual size_type getLimit() const { return mLimit; } + virtual size_type size() const { return mStreambuf.size(); } + + virtual std::string read(size_type len) + { + // Read specified number of bytes into a buffer. + size_type readlen((std::min)(size(), len)); + // Formally, &buffer[0] is invalid for a vector of size() 0. Exit + // early in that situation. + if (! readlen) + return ""; + // Make a buffer big enough. + std::vector buffer(readlen); + mStream.read(&buffer[0], readlen); + // Since we've already clamped 'readlen', we can think of no reason + // why mStream.read() should read fewer than 'readlen' bytes. + // Nonetheless, use the actual retrieved length. + return std::string(&buffer[0], mStream.gcount()); + } + + virtual std::string peek(size_type offset=0, size_type len=npos) const + { + // Constrain caller's offset and len to overlap actual buffer content. + std::size_t real_offset = (std::min)(mStreambuf.size(), std::size_t(offset)); + size_type want_end = (len == npos)? npos : (real_offset + len); + std::size_t real_end = (std::min)(mStreambuf.size(), std::size_t(want_end)); + boost::asio::streambuf::const_buffers_type cbufs = mStreambuf.data(); + return std::string(boost::asio::buffers_begin(cbufs) + real_offset, + boost::asio::buffers_begin(cbufs) + real_end); + } + + virtual size_type find(const std::string& seek, size_type offset=0) const + { + // If we're passing a string of length 1, use find(char), which can + // use an O(n) std::find() rather than the O(n^2) std::search(). + if (seek.length() == 1) + { + return find(seek[0], offset); + } + + // If offset is beyond the whole buffer, can't even construct a valid + // iterator range; can't possibly find the string we seek. + if (offset > mStreambuf.size()) + { + return npos; + } + + boost::asio::streambuf::const_buffers_type cbufs = mStreambuf.data(); + boost::asio::buffers_iterator + begin(boost::asio::buffers_begin(cbufs)), + end (boost::asio::buffers_end(cbufs)), + found(std::search(begin + offset, end, seek.begin(), seek.end())); + return (found == end)? npos : (found - begin); + } + + virtual size_type find(char seek, size_type offset=0) const + { + // If offset is beyond the whole buffer, can't even construct a valid + // iterator range; can't possibly find the char we seek. + if (offset > mStreambuf.size()) + { + return npos; + } + + boost::asio::streambuf::const_buffers_type cbufs = mStreambuf.data(); + boost::asio::buffers_iterator + begin(boost::asio::buffers_begin(cbufs)), + end (boost::asio::buffers_end(cbufs)), + found(std::find(begin + offset, end, seek)); + return (found == end)? npos : (found - begin); + } + + bool tick(const LLSD&) + { + // Once we've hit EOF, skip all the rest of this. + if (mEOF) + return false; + + typedef boost::asio::streambuf::mutable_buffers_type mutable_buffer_sequence; + // Try, every time, to read into our streambuf. In fact, we have no + // idea how much data the child might be trying to send: keep trying + // until we're convinced we've temporarily exhausted the pipe. + enum PipeState { RETRY, EXHAUSTED, CLOSED }; + PipeState state = RETRY; + std::size_t committed(0); + do + { + // attempt to read an arbitrary size + mutable_buffer_sequence bufs = mStreambuf.prepare(4096); + // In general, the mutable_buffer_sequence returned by prepare() might + // contain a number of different physical buffers; iterate over those. + std::size_t tocommit(0); + for (mutable_buffer_sequence::const_iterator bufi(bufs.begin()), bufend(bufs.end()); + bufi != bufend; ++bufi) + { + // http://www.boost.org/doc/libs/1_49_0_beta1/doc/html/boost_asio/reference/buffer.html#boost_asio.reference.buffer.accessing_buffer_contents + std::size_t toread(boost::asio::buffer_size(*bufi)); + apr_size_t gotten(toread); + apr_status_t err = apr_file_read(mPipe, + boost::asio::buffer_cast(*bufi), + &gotten); + // EAGAIN is exactly what we want from a nonblocking pipe. + // Rather than waiting for data, it should return immediately. + if (! (err == APR_SUCCESS || APR_STATUS_IS_EAGAIN(err))) + { + // Handle EOF specially: it's part of normal-case processing. + if (err == APR_EOF) + { + LL_DEBUGS("LLProcess") << "EOF on " << mDesc << LL_ENDL; + } + else + { + LL_WARNS("LLProcess") << "apr_file_read(" << toread << ") on " << mDesc + << " got " << err << ":" << LL_ENDL; + ll_apr_warn_status(err); + } + // Either way, though, we won't need any more tick() calls. + mConnection.disconnect(); + // Ignore any subsequent calls we might get anyway. + mEOF = true; + state = CLOSED; // also break outer retry loop + break; + } + + // 'gotten' was modified to reflect the number of bytes actually + // received. Make sure we commit those later. (Don't commit them + // now, that would invalidate the buffer iterator sequence!) + tocommit += gotten; + LL_DEBUGS("LLProcess") << "filled " << gotten << " of " << toread + << " bytes from " << mDesc << LL_ENDL; + + // The parent end of this pipe is nonblocking. If we weren't even + // able to fill this buffer, don't loop to try to fill the next -- + // that won't change until the child writes more. Wait for next + // tick(). + if (gotten < toread) + { + // break outer retry loop too + state = EXHAUSTED; + break; + } + } + + // Don't forget to "commit" the data! + mStreambuf.commit(tocommit); + committed += tocommit; + + // state is changed from RETRY when we can't fill any one buffer + // of the mutable_buffer_sequence established by the current + // prepare() call -- whether due to error or not enough bytes. + // That is, if state is still RETRY, we've filled every physical + // buffer in the mutable_buffer_sequence. In that case, for all we + // know, the child might have still more data pending -- go for it! + } while (state == RETRY); + + // Once we recognize that the pipe is closed, make one more call to + // listener. The listener might be waiting for a particular substring + // to arrive, or a particular length of data or something. The event + // with "eof" == true announces that nothing further will arrive, so + // use it or lose it. + if (committed || state == CLOSED) + { + // If we actually received new data, publish it on our LLEventPump + // as advertised. Constrain it by mLimit. But show listener the + // actual accumulated buffer size, regardless of mLimit. + size_type datasize((std::min)(mLimit, size_type(mStreambuf.size()))); + mPump.post(LLSDMap + ("data", peek(0, datasize)) + ("len", LLSD::Integer(mStreambuf.size())) + ("slot", LLSD::Integer(mIndex)) + ("name", whichfile(mIndex)) + ("desc", mDesc) + ("eof", state == CLOSED)); + } + + return false; + } private: - std::string mDesc; - apr_file_t* mPipe; - LLProcess::FILESLOT mIndex; - LLTempBoundListener mConnection; - boost::asio::streambuf mStreambuf; - std::istream mStream; - LLEventStream mPump; - size_type mLimit; - bool mEOF; + std::string mDesc; + apr_file_t* mPipe; + LLProcess::FILESLOT mIndex; + LLTempBoundListener mConnection; + boost::asio::streambuf mStreambuf; + std::istream mStream; + LLEventStream mPump; + size_type mLimit; + bool mEOF; }; /***************************************************************************** @@ -482,72 +482,72 @@ private: /// internal use only struct LLProcessError: public LLException { - LLProcessError(const std::string& msg): LLException(msg) {} + LLProcessError(const std::string& msg): LLException(msg) {} }; LLProcessPtr LLProcess::create(const LLSDOrParams& params) { - try - { - return LLProcessPtr(new LLProcess(params)); - } - catch (const LLProcessError& e) - { - LL_WARNS("LLProcess") << e.what() << LL_ENDL; - - // If caller is requesting an event on process termination, send one - // indicating bad launch. This may prevent someone waiting forever for - // a termination post that can't arrive because the child never - // started. - if (params.postend.isProvided()) - { - LLEventPumps::instance().obtain(params.postend) - .post(LLSDMap - // no "id" - ("desc", getDesc(params)) - ("state", LLProcess::UNSTARTED) - // no "data" - ("string", e.what()) - ); - } - - return LLProcessPtr(); - } + try + { + return LLProcessPtr(new LLProcess(params)); + } + catch (const LLProcessError& e) + { + LL_WARNS("LLProcess") << e.what() << LL_ENDL; + + // If caller is requesting an event on process termination, send one + // indicating bad launch. This may prevent someone waiting forever for + // a termination post that can't arrive because the child never + // started. + if (params.postend.isProvided()) + { + LLEventPumps::instance().obtain(params.postend) + .post(LLSDMap + // no "id" + ("desc", getDesc(params)) + ("state", LLProcess::UNSTARTED) + // no "data" + ("string", e.what()) + ); + } + + return LLProcessPtr(); + } } /// Call an apr function returning apr_status_t. On failure, log warning and /// throw LLProcessError mentioning the function call that produced that /// result. #define chkapr(func) \ - if (ll_apr_warn_status(func)) \ - throw LLProcessError(#func " failed") + if (ll_apr_warn_status(func)) \ + throw LLProcessError(#func " failed") LLProcess::LLProcess(const LLSDOrParams& params): - mAutokill(params.autokill), - // Because 'autokill' originally meant both 'autokill' and 'attached', to - // preserve existing semantics, we promise that mAttached defaults to the - // same setting as mAutokill. - mAttached(params.attached.isProvided()? params.attached : params.autokill), + mAutokill(params.autokill), + // Because 'autokill' originally meant both 'autokill' and 'attached', to + // preserve existing semantics, we promise that mAttached defaults to the + // same setting as mAutokill. + mAttached(params.attached.isProvided()? params.attached : params.autokill), mPool(NULL), - mPipes(NSLOTS) + mPipes(NSLOTS) { - // Hmm, when you construct a ptr_vector with a size, it merely reserves - // space, it doesn't actually make it that big. Explicitly make it bigger. - // Because of ptr_vector's odd semantics, have to push_back(0) the right - // number of times! resize() wants to default-construct new BasePipe - // instances, which fails because it's pure virtual. But because of the - // constructor call, these push_back() calls should require no new - // allocation. - for (size_t i = 0; i < mPipes.capacity(); ++i) - mPipes.push_back(0); - - if (! params.validateBlock(true)) - { - LLTHROW(LLProcessError(STRINGIZE("not launched: failed parameter validation\n" - << LLSDNotationStreamer(params)))); - } - - mPostend = params.postend; + // Hmm, when you construct a ptr_vector with a size, it merely reserves + // space, it doesn't actually make it that big. Explicitly make it bigger. + // Because of ptr_vector's odd semantics, have to push_back(0) the right + // number of times! resize() wants to default-construct new BasePipe + // instances, which fails because it's pure virtual. But because of the + // constructor call, these push_back() calls should require no new + // allocation. + for (size_t i = 0; i < mPipes.capacity(); ++i) + mPipes.push_back(0); + + if (! params.validateBlock(true)) + { + LLTHROW(LLProcessError(STRINGIZE("not launched: failed parameter validation\n" + << LLSDNotationStreamer(params)))); + } + + mPostend = params.postend; apr_pool_create(&mPool, gAPRPoolp); if (!mPool) @@ -555,272 +555,272 @@ LLProcess::LLProcess(const LLSDOrParams& params): LLTHROW(LLProcessError(STRINGIZE("failed to create apr pool"))); } - apr_procattr_t *procattr = NULL; - chkapr(apr_procattr_create(&procattr, mPool)); - - // IQA-490, CHOP-900: On Windows, ask APR to jump through hoops to - // constrain the set of handles passed to the child process. Before we - // changed to APR, the Windows implementation of LLProcessLauncher called - // CreateProcess(bInheritHandles=FALSE), meaning to pass NO open handles - // to the child process. Now that we support pipes, though, we must allow - // apr_proc_create() to pass bInheritHandles=TRUE. But without taking - // special pains, that causes trouble in a number of ways, due to the fact - // that the viewer is constantly opening and closing files -- most of - // which CreateProcess() passes to every child process! + apr_procattr_t *procattr = NULL; + chkapr(apr_procattr_create(&procattr, mPool)); + + // IQA-490, CHOP-900: On Windows, ask APR to jump through hoops to + // constrain the set of handles passed to the child process. Before we + // changed to APR, the Windows implementation of LLProcessLauncher called + // CreateProcess(bInheritHandles=FALSE), meaning to pass NO open handles + // to the child process. Now that we support pipes, though, we must allow + // apr_proc_create() to pass bInheritHandles=TRUE. But without taking + // special pains, that causes trouble in a number of ways, due to the fact + // that the viewer is constantly opening and closing files -- most of + // which CreateProcess() passes to every child process! #if ! defined(APR_HAS_PROCATTR_CONSTRAIN_HANDLE_SET) - // Our special preprocessor symbol isn't even defined -- wrong APR - LL_WARNS("LLProcess") << "This version of APR lacks Linden " - << "apr_procattr_constrain_handle_set() extension" << LL_ENDL; + // Our special preprocessor symbol isn't even defined -- wrong APR + LL_WARNS("LLProcess") << "This version of APR lacks Linden " + << "apr_procattr_constrain_handle_set() extension" << LL_ENDL; #else - chkapr(apr_procattr_constrain_handle_set(procattr, 1)); + chkapr(apr_procattr_constrain_handle_set(procattr, 1)); #endif - // For which of stdin, stdout, stderr should we create a pipe to the - // child? In the viewer, there are only a couple viable - // apr_procattr_io_set() alternatives: inherit the viewer's own stdxxx - // handle (APR_NO_PIPE, e.g. for stdout, stderr), or create a pipe that's - // blocking on the child end but nonblocking at the viewer end - // (APR_CHILD_BLOCK). - // Other major options could include explicitly creating a single APR pipe - // and passing it as both stdout and stderr (apr_procattr_child_out_set(), - // apr_procattr_child_err_set()), or accepting a filename, opening it and - // passing that apr_file_t (simple <, >, 2> redirect emulation). - std::vector select; - for (const FileParam& fparam : params.files) - { - // Every iteration, we're going to append an item to 'select'. At the - // top of the loop, its size() is, in effect, an index. Use that to - // pick a string description for messages. - std::string which(whichfile(FILESLOT(select.size()))); - if (fparam.type().empty()) // inherit our file descriptor - { - select.push_back(APR_NO_PIPE); - } - else if (fparam.type() == "pipe") // anonymous pipe - { - if (! fparam.name().empty()) - { - LL_WARNS("LLProcess") << "For " << params.executable() - << ": internal names for reusing pipes ('" - << fparam.name() << "' for " << which - << ") are not yet supported -- creating distinct pipe" - << LL_ENDL; - } - // The viewer can't block for anything: the parent end MUST be - // nonblocking. As the APR documentation itself points out, it - // makes very little sense to set nonblocking I/O for the child - // end of a pipe: only a specially-written child could deal with - // that. - select.push_back(APR_CHILD_BLOCK); - } - else - { - LLTHROW(LLProcessError(STRINGIZE("For " << params.executable() - << ": unsupported FileParam for " << which - << ": type='" << fparam.type() - << "', name='" << fparam.name() << "'"))); - } - } - // By default, pass APR_NO_PIPE for unspecified slots. - while (select.size() < NSLOTS) - { - select.push_back(APR_NO_PIPE); - } - chkapr(apr_procattr_io_set(procattr, select[STDIN], select[STDOUT], select[STDERR])); - - // Thumbs down on implicitly invoking the shell to invoke the child. From - // our point of view, the other major alternative to APR_PROGRAM_PATH - // would be APR_PROGRAM_ENV: still copy environment, but require full - // executable pathname. I don't see a downside to searching the PATH, - // though: if our caller wants (e.g.) a specific Python interpreter, s/he - // can still pass the full pathname. - chkapr(apr_procattr_cmdtype_set(procattr, APR_PROGRAM_PATH)); - // YES, do extra work if necessary to report child exec() failures back to - // parent process. - chkapr(apr_procattr_error_check_set(procattr, 1)); - // Do not start a non-autokill child in detached state. On Posix - // platforms, this setting attempts to daemonize the new child, closing - // std handles and the like, and that's a bit more detachment than we - // want. autokill=false just means not to implicitly kill the child when - // the parent terminates! -// chkapr(apr_procattr_detach_set(procattr, mAutokill? 0 : 1)); - - if (mAutokill) - { + // For which of stdin, stdout, stderr should we create a pipe to the + // child? In the viewer, there are only a couple viable + // apr_procattr_io_set() alternatives: inherit the viewer's own stdxxx + // handle (APR_NO_PIPE, e.g. for stdout, stderr), or create a pipe that's + // blocking on the child end but nonblocking at the viewer end + // (APR_CHILD_BLOCK). + // Other major options could include explicitly creating a single APR pipe + // and passing it as both stdout and stderr (apr_procattr_child_out_set(), + // apr_procattr_child_err_set()), or accepting a filename, opening it and + // passing that apr_file_t (simple <, >, 2> redirect emulation). + std::vector select; + for (const FileParam& fparam : params.files) + { + // Every iteration, we're going to append an item to 'select'. At the + // top of the loop, its size() is, in effect, an index. Use that to + // pick a string description for messages. + std::string which(whichfile(FILESLOT(select.size()))); + if (fparam.type().empty()) // inherit our file descriptor + { + select.push_back(APR_NO_PIPE); + } + else if (fparam.type() == "pipe") // anonymous pipe + { + if (! fparam.name().empty()) + { + LL_WARNS("LLProcess") << "For " << params.executable() + << ": internal names for reusing pipes ('" + << fparam.name() << "' for " << which + << ") are not yet supported -- creating distinct pipe" + << LL_ENDL; + } + // The viewer can't block for anything: the parent end MUST be + // nonblocking. As the APR documentation itself points out, it + // makes very little sense to set nonblocking I/O for the child + // end of a pipe: only a specially-written child could deal with + // that. + select.push_back(APR_CHILD_BLOCK); + } + else + { + LLTHROW(LLProcessError(STRINGIZE("For " << params.executable() + << ": unsupported FileParam for " << which + << ": type='" << fparam.type() + << "', name='" << fparam.name() << "'"))); + } + } + // By default, pass APR_NO_PIPE for unspecified slots. + while (select.size() < NSLOTS) + { + select.push_back(APR_NO_PIPE); + } + chkapr(apr_procattr_io_set(procattr, select[STDIN], select[STDOUT], select[STDERR])); + + // Thumbs down on implicitly invoking the shell to invoke the child. From + // our point of view, the other major alternative to APR_PROGRAM_PATH + // would be APR_PROGRAM_ENV: still copy environment, but require full + // executable pathname. I don't see a downside to searching the PATH, + // though: if our caller wants (e.g.) a specific Python interpreter, s/he + // can still pass the full pathname. + chkapr(apr_procattr_cmdtype_set(procattr, APR_PROGRAM_PATH)); + // YES, do extra work if necessary to report child exec() failures back to + // parent process. + chkapr(apr_procattr_error_check_set(procattr, 1)); + // Do not start a non-autokill child in detached state. On Posix + // platforms, this setting attempts to daemonize the new child, closing + // std handles and the like, and that's a bit more detachment than we + // want. autokill=false just means not to implicitly kill the child when + // the parent terminates! +// chkapr(apr_procattr_detach_set(procattr, mAutokill? 0 : 1)); + + if (mAutokill) + { #if ! defined(APR_HAS_PROCATTR_AUTOKILL_SET) - // Our special preprocessor symbol isn't even defined -- wrong APR - LL_WARNS("LLProcess") << "This version of APR lacks Linden apr_procattr_autokill_set() extension" << LL_ENDL; + // Our special preprocessor symbol isn't even defined -- wrong APR + LL_WARNS("LLProcess") << "This version of APR lacks Linden apr_procattr_autokill_set() extension" << LL_ENDL; #elif ! APR_HAS_PROCATTR_AUTOKILL_SET - // Symbol is defined, but to 0: expect apr_procattr_autokill_set() to - // return APR_ENOTIMPL. + // Symbol is defined, but to 0: expect apr_procattr_autokill_set() to + // return APR_ENOTIMPL. #else // APR_HAS_PROCATTR_AUTOKILL_SET nonzero - ll_apr_warn_status(apr_procattr_autokill_set(procattr, 1)); + ll_apr_warn_status(apr_procattr_autokill_set(procattr, 1)); #endif - } - - // In preparation for calling apr_proc_create(), we collect a number of - // const char* pointers obtained from std::string::c_str(). Turns out - // LLInitParam::Block's helpers Optional, Mandatory, Multiple et al. - // guarantee that converting to the wrapped type (std::string in our - // case), e.g. by calling operator(), returns a reference to *the same - // instance* of the wrapped type that's stored in our Block subclass. - // That's important! We know 'params' persists throughout this method - // call; but without that guarantee, we'd have to assume that converting - // one of its members to std::string might return a different (temp) - // instance. Capturing the c_str() from a temporary std::string is Bad Bad - // Bad. But armed with this knowledge, when you see params.cwd().c_str(), - // grit your teeth and smile and carry on. - - if (params.cwd.isProvided()) - { - chkapr(apr_procattr_dir_set(procattr, params.cwd().c_str())); - } - - // create an argv vector for the child process - std::vector argv; - - // Add the executable path. See above remarks about c_str(). - argv.push_back(params.executable().c_str()); - - // Add arguments. See above remarks about c_str(). - for (const std::string& arg : params.args) - { - argv.push_back(arg.c_str()); - } - - // terminate with a null pointer - argv.push_back(NULL); - - // Launch! The NULL would be the environment block, if we were passing - // one. Hand-expand chkapr() macro so we can fill in the actual command - // string instead of the variable names. - if (ll_apr_warn_status(apr_proc_create(&mProcess, argv[0], &argv[0], NULL, procattr, - mPool))) - { - LLTHROW(LLProcessError(STRINGIZE(params << " failed"))); - } - - // arrange to call status_callback() - apr_proc_other_child_register(&mProcess, &LLProcess::status_callback, this, mProcess.in, + } + + // In preparation for calling apr_proc_create(), we collect a number of + // const char* pointers obtained from std::string::c_str(). Turns out + // LLInitParam::Block's helpers Optional, Mandatory, Multiple et al. + // guarantee that converting to the wrapped type (std::string in our + // case), e.g. by calling operator(), returns a reference to *the same + // instance* of the wrapped type that's stored in our Block subclass. + // That's important! We know 'params' persists throughout this method + // call; but without that guarantee, we'd have to assume that converting + // one of its members to std::string might return a different (temp) + // instance. Capturing the c_str() from a temporary std::string is Bad Bad + // Bad. But armed with this knowledge, when you see params.cwd().c_str(), + // grit your teeth and smile and carry on. + + if (params.cwd.isProvided()) + { + chkapr(apr_procattr_dir_set(procattr, params.cwd().c_str())); + } + + // create an argv vector for the child process + std::vector argv; + + // Add the executable path. See above remarks about c_str(). + argv.push_back(params.executable().c_str()); + + // Add arguments. See above remarks about c_str(). + for (const std::string& arg : params.args) + { + argv.push_back(arg.c_str()); + } + + // terminate with a null pointer + argv.push_back(NULL); + + // Launch! The NULL would be the environment block, if we were passing + // one. Hand-expand chkapr() macro so we can fill in the actual command + // string instead of the variable names. + if (ll_apr_warn_status(apr_proc_create(&mProcess, argv[0], &argv[0], NULL, procattr, + mPool))) + { + LLTHROW(LLProcessError(STRINGIZE(params << " failed"))); + } + + // arrange to call status_callback() + apr_proc_other_child_register(&mProcess, &LLProcess::status_callback, this, mProcess.in, mPool); - // and make sure we poll it once per "mainloop" tick - sProcessListener.addPoll(*this); - mStatus.mState = RUNNING; - - mDesc = STRINGIZE(getDesc(params) << " (" << mProcess.pid << ')'); - LL_INFOS("LLProcess") << mDesc << ": launched " << params << LL_ENDL; - - // Unless caller explicitly turned off autokill (child should persist), - // take steps to terminate the child. This is all suspenders-and-belt: in - // theory our destructor should kill an autokill child, but in practice - // that doesn't always work (e.g. VWR-21538). - if (mAutokill) - { + // and make sure we poll it once per "mainloop" tick + sProcessListener.addPoll(*this); + mStatus.mState = RUNNING; + + mDesc = STRINGIZE(getDesc(params) << " (" << mProcess.pid << ')'); + LL_INFOS("LLProcess") << mDesc << ": launched " << params << LL_ENDL; + + // Unless caller explicitly turned off autokill (child should persist), + // take steps to terminate the child. This is all suspenders-and-belt: in + // theory our destructor should kill an autokill child, but in practice + // that doesn't always work (e.g. VWR-21538). + if (mAutokill) + { /*==========================================================================*| - // NO: There may be an APR bug, not sure -- but at least on Mac, when - // gAPRPoolp is destroyed, OUR process receives SIGTERM! Apparently - // either our own PID is getting into the list of processes to kill() - // (unlikely), or somehow one of those PIDs is getting zeroed first, - // so that kill() sends SIGTERM to the whole process group -- this - // process included. I'd have to build and link with a debug version - // of APR to know for sure. It's too bad: this mechanism would be just - // right for dealing with static autokill LLProcessPtr variables, - // which aren't destroyed until after APR is no longer available. - - // Tie the lifespan of this child process to the lifespan of our APR - // pool: on destruction of the pool, forcibly kill the process. Tell - // APR to try SIGTERM and suspend 3 seconds. If that didn't work, use - // SIGKILL. - apr_pool_note_subprocess(gAPRPoolp, &mProcess, APR_KILL_AFTER_TIMEOUT); + // NO: There may be an APR bug, not sure -- but at least on Mac, when + // gAPRPoolp is destroyed, OUR process receives SIGTERM! Apparently + // either our own PID is getting into the list of processes to kill() + // (unlikely), or somehow one of those PIDs is getting zeroed first, + // so that kill() sends SIGTERM to the whole process group -- this + // process included. I'd have to build and link with a debug version + // of APR to know for sure. It's too bad: this mechanism would be just + // right for dealing with static autokill LLProcessPtr variables, + // which aren't destroyed until after APR is no longer available. + + // Tie the lifespan of this child process to the lifespan of our APR + // pool: on destruction of the pool, forcibly kill the process. Tell + // APR to try SIGTERM and suspend 3 seconds. If that didn't work, use + // SIGKILL. + apr_pool_note_subprocess(gAPRPoolp, &mProcess, APR_KILL_AFTER_TIMEOUT); |*==========================================================================*/ - // On Windows, associate the new child process with our Job Object. - autokill(); - } - - // Instantiate the proper pipe I/O machinery - // want to be able to point to apr_proc_t::in, out, err by index - typedef apr_file_t* apr_proc_t::*apr_proc_file_ptr; - static apr_proc_file_ptr members[] = - { &apr_proc_t::in, &apr_proc_t::out, &apr_proc_t::err }; - for (size_t i = 0; i < NSLOTS; ++i) - { - if (select[i] != APR_CHILD_BLOCK) - continue; - std::string desc(STRINGIZE(mDesc << ' ' << whichfile(FILESLOT(i)))); - apr_file_t* pipe(mProcess.*(members[i])); - if (i == STDIN) - { - mPipes.replace(i, new WritePipeImpl(desc, pipe)); - } - else - { - mPipes.replace(i, new ReadPipeImpl(desc, pipe, FILESLOT(i))); - } - // Removed temporaily for Xcode 7 build tests: error was: - // "error: expression with side effects will be evaluated despite - // being used as an operand to 'typeid' [-Werror,-Wpotentially-evaluated-expression]"" - //LL_DEBUGS("LLProcess") << "Instantiating " << typeid(mPipes[i]).name() - // << "('" << desc << "')" << LL_ENDL; - } + // On Windows, associate the new child process with our Job Object. + autokill(); + } + + // Instantiate the proper pipe I/O machinery + // want to be able to point to apr_proc_t::in, out, err by index + typedef apr_file_t* apr_proc_t::*apr_proc_file_ptr; + static apr_proc_file_ptr members[] = + { &apr_proc_t::in, &apr_proc_t::out, &apr_proc_t::err }; + for (size_t i = 0; i < NSLOTS; ++i) + { + if (select[i] != APR_CHILD_BLOCK) + continue; + std::string desc(STRINGIZE(mDesc << ' ' << whichfile(FILESLOT(i)))); + apr_file_t* pipe(mProcess.*(members[i])); + if (i == STDIN) + { + mPipes.replace(i, new WritePipeImpl(desc, pipe)); + } + else + { + mPipes.replace(i, new ReadPipeImpl(desc, pipe, FILESLOT(i))); + } + // Removed temporaily for Xcode 7 build tests: error was: + // "error: expression with side effects will be evaluated despite + // being used as an operand to 'typeid' [-Werror,-Wpotentially-evaluated-expression]"" + //LL_DEBUGS("LLProcess") << "Instantiating " << typeid(mPipes[i]).name() + // << "('" << desc << "')" << LL_ENDL; + } } // Helper to obtain a description string, given a Params block static std::string getDesc(const LLProcess::Params& params) { - // If caller specified a description string, by all means use it. - if (params.desc.isProvided()) - return params.desc; + // If caller specified a description string, by all means use it. + if (params.desc.isProvided()) + return params.desc; - // Caller didn't say. Use the executable name -- but use just the filename - // part. On Mac, for instance, full pathnames get cumbersome. - return LLProcess::basename(params.executable); + // Caller didn't say. Use the executable name -- but use just the filename + // part. On Mac, for instance, full pathnames get cumbersome. + return LLProcess::basename(params.executable); } //static std::string LLProcess::basename(const std::string& path) { - // If there are Linden utility functions to manipulate pathnames, I - // haven't found them -- and for this usage, Boost.Filesystem seems kind - // of heavyweight. - std::string::size_type delim = path.find_last_of("\\/"); - // If path contains no pathname delimiters, return the whole thing. - if (delim == std::string::npos) - return path; - - // Return just the part beyond the last delimiter. - return path.substr(delim + 1); + // If there are Linden utility functions to manipulate pathnames, I + // haven't found them -- and for this usage, Boost.Filesystem seems kind + // of heavyweight. + std::string::size_type delim = path.find_last_of("\\/"); + // If path contains no pathname delimiters, return the whole thing. + if (delim == std::string::npos) + return path; + + // Return just the part beyond the last delimiter. + return path.substr(delim + 1); } LLProcess::~LLProcess() { - // In the Linden viewer, there's at least one static LLProcessPtr. Its - // destructor will be called *after* ll_cleanup_apr(). In such a case, - // unregistering is pointless (and fatal!) -- and kill(), which also - // relies on APR, is impossible. - if (! gAPRPoolp) - return; - - // Only in state RUNNING are we registered for callback. In UNSTARTED we - // haven't yet registered. And since receiving the callback is the only - // way we detect child termination, we only change from state RUNNING at - // the same time we unregister. - if (mStatus.mState == RUNNING) - { - // We're still registered for a callback: unregister. Do it before - // we even issue the kill(): even if kill() somehow prompted an - // instantaneous callback (unlikely), this object is going away! Any - // information updated in this object by such a callback is no longer - // available to any consumer anyway. - apr_proc_other_child_unregister(this); - // One less LLProcess to poll for - sProcessListener.dropPoll(*this); - } - - if (mAttached) - { - kill("destructor"); - } + // In the Linden viewer, there's at least one static LLProcessPtr. Its + // destructor will be called *after* ll_cleanup_apr(). In such a case, + // unregistering is pointless (and fatal!) -- and kill(), which also + // relies on APR, is impossible. + if (! gAPRPoolp) + return; + + // Only in state RUNNING are we registered for callback. In UNSTARTED we + // haven't yet registered. And since receiving the callback is the only + // way we detect child termination, we only change from state RUNNING at + // the same time we unregister. + if (mStatus.mState == RUNNING) + { + // We're still registered for a callback: unregister. Do it before + // we even issue the kill(): even if kill() somehow prompted an + // instantaneous callback (unlikely), this object is going away! Any + // information updated in this object by such a callback is no longer + // available to any consumer anyway. + apr_proc_other_child_unregister(this); + // One less LLProcess to poll for + sProcessListener.dropPoll(*this); + } + + if (mAttached) + { + kill("destructor"); + } if (mPool) { @@ -831,330 +831,330 @@ LLProcess::~LLProcess() bool LLProcess::kill(const std::string& who) { - if (isRunning()) - { - LL_INFOS("LLProcess") << who << " killing " << mDesc << LL_ENDL; + if (isRunning()) + { + LL_INFOS("LLProcess") << who << " killing " << mDesc << LL_ENDL; #if LL_WINDOWS - int sig = -1; + int sig = -1; #else // Posix - int sig = SIGTERM; + int sig = SIGTERM; #endif - ll_apr_warn_status(apr_proc_kill(&mProcess, sig)); - } + ll_apr_warn_status(apr_proc_kill(&mProcess, sig)); + } - return ! isRunning(); + return ! isRunning(); } //static bool LLProcess::kill(const LLProcessPtr& p, const std::string& who) { - if (! p) - return true; // process dead! (was never running) - return p->kill(who); + if (! p) + return true; // process dead! (was never running) + return p->kill(who); } bool LLProcess::isRunning() const { - return getStatus().mState == RUNNING; + return getStatus().mState == RUNNING; } //static bool LLProcess::isRunning(const LLProcessPtr& p) { - if (! p) - return false; - return p->isRunning(); + if (! p) + return false; + return p->isRunning(); } LLProcess::Status LLProcess::getStatus() const { - return mStatus; + return mStatus; } //static LLProcess::Status LLProcess::getStatus(const LLProcessPtr& p) { - if (! p) - { - // default-constructed Status has mState == UNSTARTED - return Status(); - } - return p->getStatus(); + if (! p) + { + // default-constructed Status has mState == UNSTARTED + return Status(); + } + return p->getStatus(); } std::string LLProcess::getStatusString() const { - return getStatusString(getStatus()); + return getStatusString(getStatus()); } std::string LLProcess::getStatusString(const Status& status) const { - return getStatusString(mDesc, status); + return getStatusString(mDesc, status); } //static std::string LLProcess::getStatusString(const std::string& desc, const LLProcessPtr& p) { - if (! p) - { - // default-constructed Status has mState == UNSTARTED - return getStatusString(desc, Status()); - } - return desc + " " + p->getStatusString(); + if (! p) + { + // default-constructed Status has mState == UNSTARTED + return getStatusString(desc, Status()); + } + return desc + " " + p->getStatusString(); } //static std::string LLProcess::getStatusString(const std::string& desc, const Status& status) { - if (status.mState == UNSTARTED) - return desc + " was never launched"; + if (status.mState == UNSTARTED) + return desc + " was never launched"; - if (status.mState == RUNNING) - return desc + " running"; + if (status.mState == RUNNING) + return desc + " running"; - if (status.mState == EXITED) - return STRINGIZE(desc << " exited with code " << status.mData); + if (status.mState == EXITED) + return STRINGIZE(desc << " exited with code " << status.mData); - if (status.mState == KILLED) + if (status.mState == KILLED) #if LL_WINDOWS - return STRINGIZE(desc << " killed with exception " << std::hex << status.mData); + return STRINGIZE(desc << " killed with exception " << std::hex << status.mData); #else - return STRINGIZE(desc << " killed by signal " << status.mData - << " (" << apr_signal_description_get(status.mData) << ")"); + return STRINGIZE(desc << " killed by signal " << status.mData + << " (" << apr_signal_description_get(status.mData) << ")"); #endif - return STRINGIZE(desc << " in unknown state " << status.mState << " (" << status.mData << ")"); + return STRINGIZE(desc << " in unknown state " << status.mState << " (" << status.mData << ")"); } // Classic-C-style APR callback void LLProcess::status_callback(int reason, void* data, int status) { - // Our only role is to bounce this static method call back into object - // space. - static_cast(data)->handle_status(reason, status); + // Our only role is to bounce this static method call back into object + // space. + static_cast(data)->handle_status(reason, status); } #define tabent(symbol) { symbol, #symbol } static struct ReasonCode { - int code; - const char* name; + int code; + const char* name; } reasons[] = { - tabent(APR_OC_REASON_DEATH), - tabent(APR_OC_REASON_UNWRITABLE), - tabent(APR_OC_REASON_RESTART), - tabent(APR_OC_REASON_UNREGISTER), - tabent(APR_OC_REASON_LOST), - tabent(APR_OC_REASON_RUNNING) + tabent(APR_OC_REASON_DEATH), + tabent(APR_OC_REASON_UNWRITABLE), + tabent(APR_OC_REASON_RESTART), + tabent(APR_OC_REASON_UNREGISTER), + tabent(APR_OC_REASON_LOST), + tabent(APR_OC_REASON_RUNNING) }; #undef tabent // Object-oriented callback void LLProcess::handle_status(int reason, int status) { - { - // This odd appearance of LL_DEBUGS is just to bracket a lookup that will - // only be performed if in fact we're going to produce the log message. - LL_DEBUGS("LLProcess") << empty; - std::string reason_str; - for (const ReasonCode& rcp : reasons) - { - if (reason == rcp.code) - { - reason_str = rcp.name; - break; - } - } - if (reason_str.empty()) - { - reason_str = STRINGIZE("unknown reason " << reason); - } - LL_CONT << mDesc << ": handle_status(" << reason_str << ", " << status << ")" << LL_ENDL; - } - - if (! (reason == APR_OC_REASON_DEATH || reason == APR_OC_REASON_LOST)) - { - // We're only interested in the call when the child terminates. - return; - } - - // Somewhat oddly, APR requires that you explicitly unregister even when - // it already knows the child has terminated. We must pass the same 'data' - // pointer as for the register() call, which was our 'this'. - apr_proc_other_child_unregister(this); - // don't keep polling for a terminated process - sProcessListener.dropPoll(*this); - // We overload mStatus.mState to indicate whether the child is registered - // for APR callback: only RUNNING means registered. Track that we've - // unregistered. We know the child has terminated; might be EXITED or - // KILLED; refine below. - mStatus.mState = EXITED; - - // Make last-gasp calls for each of the ReadPipes we have on hand. Since - // they're listening on "mainloop", we can be sure they'll eventually - // collect all pending data from the child. But we want to be able to - // guarantee to our consumer that by the time we post on the "postend" - // LLEventPump, our ReadPipes are already buffering all the data there - // will ever be from the child. That lets the "postend" listener decide - // what to do with that final data. - for (size_t i = 0; i < mPipes.size(); ++i) - { - std::string error; - ReadPipeImpl* ppipe = getPipePtr(error, FILESLOT(i)); - if (ppipe) - { - static LLSD trivial; - ppipe->tick(trivial); - } - } - -// wi->rv = apr_proc_wait(wi->child, &wi->rc, &wi->why, APR_NOWAIT); - // It's just wrong to call apr_proc_wait() here. The only way APR knows to - // call us with APR_OC_REASON_DEATH is that it's already reaped this child - // process, so calling wait() will only produce "huh?" from the OS. We - // must rely on the status param passed in, which unfortunately comes - // straight from the OS wait() call, which means we have to decode it by - // hand. - mStatus = interpret_status(status); - LL_INFOS("LLProcess") << getStatusString() << LL_ENDL; - - // If caller requested notification on child termination, send it. - if (! mPostend.empty()) - { - LLEventPumps::instance().obtain(mPostend) - .post(LLSDMap - ("id", getProcessID()) - ("desc", mDesc) - ("state", mStatus.mState) - ("data", mStatus.mData) - ("string", getStatusString()) - ); - } + { + // This odd appearance of LL_DEBUGS is just to bracket a lookup that will + // only be performed if in fact we're going to produce the log message. + LL_DEBUGS("LLProcess") << empty; + std::string reason_str; + for (const ReasonCode& rcp : reasons) + { + if (reason == rcp.code) + { + reason_str = rcp.name; + break; + } + } + if (reason_str.empty()) + { + reason_str = STRINGIZE("unknown reason " << reason); + } + LL_CONT << mDesc << ": handle_status(" << reason_str << ", " << status << ")" << LL_ENDL; + } + + if (! (reason == APR_OC_REASON_DEATH || reason == APR_OC_REASON_LOST)) + { + // We're only interested in the call when the child terminates. + return; + } + + // Somewhat oddly, APR requires that you explicitly unregister even when + // it already knows the child has terminated. We must pass the same 'data' + // pointer as for the register() call, which was our 'this'. + apr_proc_other_child_unregister(this); + // don't keep polling for a terminated process + sProcessListener.dropPoll(*this); + // We overload mStatus.mState to indicate whether the child is registered + // for APR callback: only RUNNING means registered. Track that we've + // unregistered. We know the child has terminated; might be EXITED or + // KILLED; refine below. + mStatus.mState = EXITED; + + // Make last-gasp calls for each of the ReadPipes we have on hand. Since + // they're listening on "mainloop", we can be sure they'll eventually + // collect all pending data from the child. But we want to be able to + // guarantee to our consumer that by the time we post on the "postend" + // LLEventPump, our ReadPipes are already buffering all the data there + // will ever be from the child. That lets the "postend" listener decide + // what to do with that final data. + for (size_t i = 0; i < mPipes.size(); ++i) + { + std::string error; + ReadPipeImpl* ppipe = getPipePtr(error, FILESLOT(i)); + if (ppipe) + { + static LLSD trivial; + ppipe->tick(trivial); + } + } + +// wi->rv = apr_proc_wait(wi->child, &wi->rc, &wi->why, APR_NOWAIT); + // It's just wrong to call apr_proc_wait() here. The only way APR knows to + // call us with APR_OC_REASON_DEATH is that it's already reaped this child + // process, so calling wait() will only produce "huh?" from the OS. We + // must rely on the status param passed in, which unfortunately comes + // straight from the OS wait() call, which means we have to decode it by + // hand. + mStatus = interpret_status(status); + LL_INFOS("LLProcess") << getStatusString() << LL_ENDL; + + // If caller requested notification on child termination, send it. + if (! mPostend.empty()) + { + LLEventPumps::instance().obtain(mPostend) + .post(LLSDMap + ("id", getProcessID()) + ("desc", mDesc) + ("state", mStatus.mState) + ("data", mStatus.mData) + ("string", getStatusString()) + ); + } } LLProcess::id LLProcess::getProcessID() const { - return mProcess.pid; + return mProcess.pid; } LLProcess::handle LLProcess::getProcessHandle() const { #if LL_WINDOWS - return mProcess.hproc; + return mProcess.hproc; #else - return mProcess.pid; + return mProcess.pid; #endif } std::string LLProcess::getPipeName(FILESLOT) const { - // LLProcess::FileParam::type "npipe" is not yet implemented - return ""; + // LLProcess::FileParam::type "npipe" is not yet implemented + return ""; } template PIPETYPE* LLProcess::getPipePtr(std::string& error, FILESLOT slot) { - if (slot >= NSLOTS) - { - error = STRINGIZE(mDesc << " has no slot " << slot); - return NULL; - } - if (mPipes.is_null(slot)) - { - error = STRINGIZE(mDesc << ' ' << whichfile(slot) << " not a monitored pipe"); - return NULL; - } - // Make sure we dynamic_cast in pointer domain so we can test, rather than - // accepting runtime's exception. - PIPETYPE* ppipe = dynamic_cast(&mPipes[slot]); - if (! ppipe) - { - error = STRINGIZE(mDesc << ' ' << whichfile(slot) << " not a " << typeid(PIPETYPE).name()); - return NULL; - } - - error.clear(); - return ppipe; + if (slot >= NSLOTS) + { + error = STRINGIZE(mDesc << " has no slot " << slot); + return NULL; + } + if (mPipes.is_null(slot)) + { + error = STRINGIZE(mDesc << ' ' << whichfile(slot) << " not a monitored pipe"); + return NULL; + } + // Make sure we dynamic_cast in pointer domain so we can test, rather than + // accepting runtime's exception. + PIPETYPE* ppipe = dynamic_cast(&mPipes[slot]); + if (! ppipe) + { + error = STRINGIZE(mDesc << ' ' << whichfile(slot) << " not a " << typeid(PIPETYPE).name()); + return NULL; + } + + error.clear(); + return ppipe; } template PIPETYPE& LLProcess::getPipe(FILESLOT slot) { - std::string error; - PIPETYPE* wp = getPipePtr(error, slot); - if (! wp) - { - LLTHROW(NoPipe(error)); - } - return *wp; + std::string error; + PIPETYPE* wp = getPipePtr(error, slot); + if (! wp) + { + LLTHROW(NoPipe(error)); + } + return *wp; } template boost::optional LLProcess::getOptPipe(FILESLOT slot) { - std::string error; - PIPETYPE* wp = getPipePtr(error, slot); - if (! wp) - { - LL_DEBUGS("LLProcess") << error << LL_ENDL; - return boost::optional(); - } - return *wp; + std::string error; + PIPETYPE* wp = getPipePtr(error, slot); + if (! wp) + { + LL_DEBUGS("LLProcess") << error << LL_ENDL; + return boost::optional(); + } + return *wp; } LLProcess::WritePipe& LLProcess::getWritePipe(FILESLOT slot) { - return getPipe(slot); + return getPipe(slot); } boost::optional LLProcess::getOptWritePipe(FILESLOT slot) { - return getOptPipe(slot); + return getOptPipe(slot); } LLProcess::ReadPipe& LLProcess::getReadPipe(FILESLOT slot) { - return getPipe(slot); + return getPipe(slot); } boost::optional LLProcess::getOptReadPipe(FILESLOT slot) { - return getOptPipe(slot); + return getOptPipe(slot); } //static std::string LLProcess::getline(std::istream& in) { - std::string line; - std::getline(in, line); - // Blur the distinction between "\r\n" and plain "\n". std::getline() will - // have eaten the "\n", but we could still end up with a trailing "\r". - std::string::size_type lastpos = line.find_last_not_of("\r"); - if (lastpos != std::string::npos) - { - // Found at least one character that's not a trailing '\r'. SKIP OVER - // IT and erase the rest of the line. - line.erase(lastpos+1); - } - return line; + std::string line; + std::getline(in, line); + // Blur the distinction between "\r\n" and plain "\n". std::getline() will + // have eaten the "\n", but we could still end up with a trailing "\r". + std::string::size_type lastpos = line.find_last_not_of("\r"); + if (lastpos != std::string::npos) + { + // Found at least one character that's not a trailing '\r'. SKIP OVER + // IT and erase the rest of the line. + line.erase(lastpos+1); + } + return line; } std::ostream& operator<<(std::ostream& out, const LLProcess::Params& params) { - if (params.cwd.isProvided()) - { - out << "cd " << LLStringUtil::quote(params.cwd) << ": "; - } - out << LLStringUtil::quote(params.executable); - for (const std::string& arg : params.args) - { - out << ' ' << LLStringUtil::quote(arg); - } - return out; + if (params.cwd.isProvided()) + { + out << "cd " << LLStringUtil::quote(params.cwd) << ": "; + } + out << LLStringUtil::quote(params.executable); + for (const std::string& arg : params.args) + { + out << ' ' << LLStringUtil::quote(arg); + } + return out; } /***************************************************************************** @@ -1166,68 +1166,68 @@ static std::string WindowsErrorString(const std::string& operation); void LLProcess::autokill() { - // hopefully now handled by apr_procattr_autokill_set() + // hopefully now handled by apr_procattr_autokill_set() } LLProcess::handle LLProcess::isRunning(handle h, const std::string& desc) { - // This direct Windows implementation is because we have no access to the - // apr_proc_t struct: we expect it's been destroyed. - if (! h) - return 0; - - DWORD waitresult = WaitForSingleObject(h, 0); - if(waitresult == WAIT_OBJECT_0) - { - // the process has completed. - if (! desc.empty()) - { - DWORD status = 0; - if (! GetExitCodeProcess(h, &status)) - { - LL_WARNS("LLProcess") << desc << " terminated, but " - << WindowsErrorString("GetExitCodeProcess()") << LL_ENDL; - } - { - LL_INFOS("LLProcess") << getStatusString(desc, interpret_status(status)) - << LL_ENDL; - } - } - CloseHandle(h); - return 0; - } - - return h; + // This direct Windows implementation is because we have no access to the + // apr_proc_t struct: we expect it's been destroyed. + if (! h) + return 0; + + DWORD waitresult = WaitForSingleObject(h, 0); + if(waitresult == WAIT_OBJECT_0) + { + // the process has completed. + if (! desc.empty()) + { + DWORD status = 0; + if (! GetExitCodeProcess(h, &status)) + { + LL_WARNS("LLProcess") << desc << " terminated, but " + << WindowsErrorString("GetExitCodeProcess()") << LL_ENDL; + } + { + LL_INFOS("LLProcess") << getStatusString(desc, interpret_status(status)) + << LL_ENDL; + } + } + CloseHandle(h); + return 0; + } + + return h; } static LLProcess::Status interpret_status(int status) { - LLProcess::Status result; - - // This bit of code is cribbed from apr/threadproc/win32/proc.c, a - // function (unfortunately static) called why_from_exit_code(): - /* See WinNT.h STATUS_ACCESS_VIOLATION and family for how - * this class of failures was determined - */ - if ((status & 0xFFFF0000) == 0xC0000000) - { - result.mState = LLProcess::KILLED; - } - else - { - result.mState = LLProcess::EXITED; - } - result.mData = status; - - return result; + LLProcess::Status result; + + // This bit of code is cribbed from apr/threadproc/win32/proc.c, a + // function (unfortunately static) called why_from_exit_code(): + /* See WinNT.h STATUS_ACCESS_VIOLATION and family for how + * this class of failures was determined + */ + if ((status & 0xFFFF0000) == 0xC0000000) + { + result.mState = LLProcess::KILLED; + } + else + { + result.mState = LLProcess::EXITED; + } + result.mData = status; + + return result; } /// GetLastError()/FormatMessage() boilerplate static std::string WindowsErrorString(const std::string& operation) { - auto result = GetLastError(); - return STRINGIZE(operation << " failed (" << result << "): " - << windows_message(result)); + auto result = GetLastError(); + return STRINGIZE(operation << " failed (" << result << "): " + << windows_message(result)); } /***************************************************************************** @@ -1242,117 +1242,117 @@ static std::string WindowsErrorString(const std::string& operation) void LLProcess::autokill() { - // What we ought to do here is to: - // 1. create a unique process group and run all autokill children in that - // group (see https://jira.secondlife.com/browse/SWAT-563); - // 2. figure out a way to intercept control when the viewer exits -- - // gracefully or not; - // 3. when the viewer exits, kill off the aforementioned process group. - - // It's point 2 that's troublesome. Although I've seen some signal- - // handling logic in the Posix viewer code, I haven't yet found any bit of - // code that's run no matter how the viewer exits (a try/finally for the - // whole process, as it were). + // What we ought to do here is to: + // 1. create a unique process group and run all autokill children in that + // group (see https://jira.secondlife.com/browse/SWAT-563); + // 2. figure out a way to intercept control when the viewer exits -- + // gracefully or not; + // 3. when the viewer exits, kill off the aforementioned process group. + + // It's point 2 that's troublesome. Although I've seen some signal- + // handling logic in the Posix viewer code, I haven't yet found any bit of + // code that's run no matter how the viewer exits (a try/finally for the + // whole process, as it were). } // Attempt to reap a process ID -- returns true if the process has exited and been reaped, false otherwise. static bool reap_pid(pid_t pid, LLProcess::Status* pstatus=NULL) { - LLProcess::Status dummy; - if (! pstatus) - { - // If caller doesn't want to see Status, give us a target anyway so we - // don't have to have a bunch of conditionals. - pstatus = &dummy; - } - - int status = 0; - pid_t wait_result = ::waitpid(pid, &status, WNOHANG); - if (wait_result == pid) - { - *pstatus = interpret_status(status); - return true; - } - if (wait_result == 0) - { - pstatus->mState = LLProcess::RUNNING; - pstatus->mData = 0; - return false; - } - - // Clear caller's Status block; caller must interpret UNSTARTED to mean - // "if this PID was ever valid, it no longer is." - *pstatus = LLProcess::Status(); - - // We've dealt with the success cases: we were able to reap the child - // (wait_result == pid) or it's still running (wait_result == 0). It may - // be that the child terminated but didn't hang around long enough for us - // to reap. In that case we still have no Status to report, but we can at - // least state that it's not running. - if (wait_result == -1 && errno == ECHILD) - { - // No such process -- this may mean we're ignoring SIGCHILD. - return true; - } - - // Uh, should never happen?! - LL_WARNS("LLProcess") << "LLProcess::reap_pid(): waitpid(" << pid << ") returned " - << wait_result << "; not meaningful?" << LL_ENDL; - // If caller is looping until this pid terminates, and if we can't find - // out, better to break the loop than to claim it's still running. - return true; + LLProcess::Status dummy; + if (! pstatus) + { + // If caller doesn't want to see Status, give us a target anyway so we + // don't have to have a bunch of conditionals. + pstatus = &dummy; + } + + int status = 0; + pid_t wait_result = ::waitpid(pid, &status, WNOHANG); + if (wait_result == pid) + { + *pstatus = interpret_status(status); + return true; + } + if (wait_result == 0) + { + pstatus->mState = LLProcess::RUNNING; + pstatus->mData = 0; + return false; + } + + // Clear caller's Status block; caller must interpret UNSTARTED to mean + // "if this PID was ever valid, it no longer is." + *pstatus = LLProcess::Status(); + + // We've dealt with the success cases: we were able to reap the child + // (wait_result == pid) or it's still running (wait_result == 0). It may + // be that the child terminated but didn't hang around long enough for us + // to reap. In that case we still have no Status to report, but we can at + // least state that it's not running. + if (wait_result == -1 && errno == ECHILD) + { + // No such process -- this may mean we're ignoring SIGCHILD. + return true; + } + + // Uh, should never happen?! + LL_WARNS("LLProcess") << "LLProcess::reap_pid(): waitpid(" << pid << ") returned " + << wait_result << "; not meaningful?" << LL_ENDL; + // If caller is looping until this pid terminates, and if we can't find + // out, better to break the loop than to claim it's still running. + return true; } LLProcess::id LLProcess::isRunning(id pid, const std::string& desc) { - // This direct Posix implementation is because we have no access to the - // apr_proc_t struct: we expect it's been destroyed. - if (! pid) - return 0; - - // Check whether the process has exited, and reap it if it has. - LLProcess::Status status; - if(reap_pid(pid, &status)) - { - // the process has exited. - if (! desc.empty()) - { - std::string statstr(desc + " apparently terminated: no status available"); - // We don't just pass UNSTARTED to getStatusString() because, in - // the context of reap_pid(), that state has special meaning. - if (status.mState != UNSTARTED) - { - statstr = getStatusString(desc, status); - } - LL_INFOS("LLProcess") << statstr << LL_ENDL; - } - return 0; - } - - return pid; + // This direct Posix implementation is because we have no access to the + // apr_proc_t struct: we expect it's been destroyed. + if (! pid) + return 0; + + // Check whether the process has exited, and reap it if it has. + LLProcess::Status status; + if(reap_pid(pid, &status)) + { + // the process has exited. + if (! desc.empty()) + { + std::string statstr(desc + " apparently terminated: no status available"); + // We don't just pass UNSTARTED to getStatusString() because, in + // the context of reap_pid(), that state has special meaning. + if (status.mState != UNSTARTED) + { + statstr = getStatusString(desc, status); + } + LL_INFOS("LLProcess") << statstr << LL_ENDL; + } + return 0; + } + + return pid; } static LLProcess::Status interpret_status(int status) { - LLProcess::Status result; - - if (WIFEXITED(status)) - { - result.mState = LLProcess::EXITED; - result.mData = WEXITSTATUS(status); - } - else if (WIFSIGNALED(status)) - { - result.mState = LLProcess::KILLED; - result.mData = WTERMSIG(status); - } - else // uh, shouldn't happen? - { - result.mState = LLProcess::EXITED; - result.mData = status; // someone else will have to decode - } - - return result; + LLProcess::Status result; + + if (WIFEXITED(status)) + { + result.mState = LLProcess::EXITED; + result.mData = WEXITSTATUS(status); + } + else if (WIFSIGNALED(status)) + { + result.mState = LLProcess::KILLED; + result.mData = WTERMSIG(status); + } + else // uh, shouldn't happen? + { + result.mState = LLProcess::EXITED; + result.mData = status; // someone else will have to decode + } + + return result; } #endif // Posix diff --git a/indra/llcommon/llprocess.h b/indra/llcommon/llprocess.h index c57821bf52..166da8f424 100644 --- a/indra/llcommon/llprocess.h +++ b/indra/llcommon/llprocess.h @@ -1,29 +1,29 @@ -/** +/** * @file llprocess.h * @brief Utility class for launching, terminating, and tracking child processes. * * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ - + #ifndef LL_LLPROCESS_H #define LL_LLPROCESS_H @@ -39,7 +39,7 @@ #include // std::ostream #if LL_WINDOWS -#include "llwin32headerslean.h" // for HANDLE +#include "llwin32headerslean.h" // for HANDLE #elif LL_LINUX #if defined(Status) #undef Status @@ -71,503 +71,503 @@ typedef std::shared_ptr LLProcessPtr; */ class LL_COMMON_API LLProcess: public boost::noncopyable { - LOG_CLASS(LLProcess); + LOG_CLASS(LLProcess); public: - /** - * Specify what to pass for each of child stdin, stdout, stderr. - * @see LLProcess::Params::files. - */ - struct FileParam: public LLInitParam::Block - { - /** - * type of file handle to pass to child process - * - * - "" (default): let the child inherit the same file handle used by - * this process. For instance, if passed as stdout, child stdout - * will be interleaved with stdout from this process. In this case, - * @a name is moot and should be left "". - * - * - "file": open an OS filesystem file with the specified @a name. - * Not yet implemented. - * - * - "pipe" or "tpipe" or "npipe": depends on @a name - * - * - @a name.empty(): construct an OS pipe used only for this slot - * of the forthcoming child process. - * - * - ! @a name.empty(): in a global registry, find or create (using - * the specified @a name) an OS pipe. The point of the (purely - * internal) @a name is that passing the same @a name in more than - * one slot for a given LLProcess -- or for slots in different - * LLProcess instances -- means the same pipe. For example, you - * might pass the same @a name value as both stdout and stderr to - * make the child process produce both on the same actual pipe. Or - * you might pass the same @a name as the stdout for one LLProcess - * and the stdin for another to connect the two child processes. - * Use LLProcess::getPipeName() to generate a unique name - * guaranteed not to already exist in the registry. Not yet - * implemented. - * - * The difference between "pipe", "tpipe" and "npipe" is as follows. - * - * - "pipe": direct LLProcess to monitor the parent end of the pipe, - * pumping nonblocking I/O every frame. The expectation (at least - * for stdout or stderr) is that the caller will listen for - * incoming data and consume it as it arrives. It's important not - * to neglect such a pipe, because it's buffered in memory. If you - * suspect the child may produce a great volume of output between - * frames, consider directing the child to write to a filesystem - * file instead, then read the file later. - * - * - "tpipe": do not engage LLProcess machinery to monitor the - * parent end of the pipe. A "tpipe" is used only to connect - * different child processes. As such, it makes little sense to - * pass an empty @a name. Not yet implemented. - * - * - "npipe": like "tpipe", but use an OS named pipe with a - * generated name. Note that @a name is the @em internal name of - * the pipe in our global registry -- it doesn't necessarily have - * anything to do with the pipe's name in the OS filesystem. Use - * LLProcess::getPipeName() to obtain the named pipe's OS - * filesystem name, e.g. to pass it as the @a name to another - * LLProcess instance using @a type "file". This supports usage - * like bash's <(subcommand...) or >(subcommand...) - * constructs. Not yet implemented. - * - * In all cases the open mode (read, write) is determined by the child - * slot you're filling. Child stdin means select the "read" end of a - * pipe, or open a filesystem file for reading; child stdout or stderr - * means select the "write" end of a pipe, or open a filesystem file - * for writing. - * - * Confusion such as passing the same pipe as the stdin of two - * processes (rather than stdout for one and stdin for the other) is - * explicitly permitted: it's up to the caller to construct meaningful - * LLProcess pipe graphs. - */ - Optional type; - Optional name; - - FileParam(const std::string& tp="", const std::string& nm=""): - type("type"), - name("name") - { - // If caller wants to specify values, use explicit assignment to - // set them rather than initialization. - if (! tp.empty()) type = tp; - if (! nm.empty()) name = nm; - } - }; - - /// Param block definition - struct Params: public LLInitParam::Block - { - Params(): - executable("executable"), - args("args"), - cwd("cwd"), - autokill("autokill", true), - attached("attached", true), - files("files"), - postend("postend"), - desc("desc") - {} - - /// pathname of executable - Mandatory executable; - /** - * zero or more additional command-line arguments. Arguments are - * passed through as exactly as we can manage, whitespace and all. - * @note On Windows we manage this by implicitly double-quoting each - * argument while assembling the command line. - */ - Multiple args; - /// current working directory, if need it changed - Optional cwd; - /// implicitly kill child process on termination of parent, whether - /// voluntary or crash (default true) - Optional autokill; - /// implicitly kill process on destruction of LLProcess object - /// (default same as autokill) - /// - /// Originally, 'autokill' conflated two concepts: kill child process on - /// - destruction of its LLProcess object, and - /// - termination of parent process, voluntary or otherwise. - /// - /// It's useful to tease these apart. Some child processes are sent a - /// "clean up and terminate" message before the associated LLProcess - /// object is destroyed. A child process launched with attached=false - /// has an extra time window from the destruction of its LLProcess - /// until parent-process termination in which to perform its own - /// orderly shutdown, yet autokill=true still guarantees that we won't - /// accumulate orphan instances of such processes indefinitely. With - /// attached=true, if a child process cannot clean up between the - /// shutdown message and LLProcess destruction (presumably very soon - /// thereafter), it's forcibly killed anyway -- which can lead to - /// distressing user-visible crash indications. - /// - /// (The usefulness of attached=true with autokill=false is less - /// clear, but we don't prohibit that combination.) - Optional attached; - /** - * Up to three FileParam items: for child stdin, stdout, stderr. - * Passing two FileParam entries means default treatment for stderr, - * and so forth. - * - * @note LLInitParam::Block permits usage like this: - * @code - * LLProcess::Params params; - * ... - * params.files - * .add(LLProcess::FileParam()) // stdin - * .add(LLProcess::FileParam().type("pipe") // stdout - * .add(LLProcess::FileParam().type("file").name("error.log")); - * @endcode - * - * @note While it's theoretically plausible to pass additional open - * file handles to a child specifically written to expect them, our - * underlying implementation doesn't yet support that. - */ - Multiple > files; - /** - * On child-process termination, if this LLProcess object still - * exists, post LLSD event to LLEventPump with specified name (default - * no event). Event contains at least: - * - * - "id" as obtained from getProcessID() - * - "desc" short string description of child (executable + pid) - * - "state" @c state enum value, from Status.mState - * - "data" if "state" is EXITED, exit code; if KILLED, on Posix, - * signal number - * - "string" English text describing "state" and "data" (e.g. "exited - * with code 0") - */ - Optional postend; - /** - * Description of child process for logging purposes. It need not be - * unique; the logged description string will contain the PID as well. - * If this is omitted, a description will be derived from the - * executable name. - */ - Optional desc; - }; - typedef LLSDParamAdapter LLSDOrParams; - - /** - * Factory accepting either plain LLSD::Map or Params block. - * MAY RETURN DEFAULT-CONSTRUCTED LLProcessPtr if params invalid! - */ - static LLProcessPtr create(const LLSDOrParams& params); - virtual ~LLProcess(); - - /// Is child process still running? - bool isRunning() const; - // static isRunning(LLProcessPtr), getStatus(LLProcessPtr), - // getStatusString(LLProcessPtr), kill(LLProcessPtr) handle the case in - // which the passed LLProcessPtr might be NULL (default-constructed). - static bool isRunning(const LLProcessPtr&); - - /** - * State of child process - */ - enum state - { - UNSTARTED, ///< initial value, invisible to consumer - RUNNING, ///< child process launched - EXITED, ///< child process terminated voluntarily - KILLED ///< child process terminated involuntarily - }; - - /** - * Status info - */ - struct Status - { - Status(): - mState(UNSTARTED), - mData(0) - {} - - state mState; ///< @see state - /** - * - for mState == EXITED: mData is exit() code - * - for mState == KILLED: mData is signal number (Posix) - * - otherwise: mData is undefined - */ - int mData; - }; - - /// Status query - Status getStatus() const; - static Status getStatus(const LLProcessPtr&); - /// English Status string query, for logging etc. - std::string getStatusString() const; - static std::string getStatusString(const std::string& desc, const LLProcessPtr&); - /// English Status string query for previously-captured Status - std::string getStatusString(const Status& status) const; - /// static English Status string query - static std::string getStatusString(const std::string& desc, const Status& status); - - // Attempt to kill the process -- returns true if the process is no longer running when it returns. - // Note that even if this returns false, the process may exit some time after it's called. - bool kill(const std::string& who=""); - static bool kill(const LLProcessPtr& p, const std::string& who=""); + /** + * Specify what to pass for each of child stdin, stdout, stderr. + * @see LLProcess::Params::files. + */ + struct FileParam: public LLInitParam::Block + { + /** + * type of file handle to pass to child process + * + * - "" (default): let the child inherit the same file handle used by + * this process. For instance, if passed as stdout, child stdout + * will be interleaved with stdout from this process. In this case, + * @a name is moot and should be left "". + * + * - "file": open an OS filesystem file with the specified @a name. + * Not yet implemented. + * + * - "pipe" or "tpipe" or "npipe": depends on @a name + * + * - @a name.empty(): construct an OS pipe used only for this slot + * of the forthcoming child process. + * + * - ! @a name.empty(): in a global registry, find or create (using + * the specified @a name) an OS pipe. The point of the (purely + * internal) @a name is that passing the same @a name in more than + * one slot for a given LLProcess -- or for slots in different + * LLProcess instances -- means the same pipe. For example, you + * might pass the same @a name value as both stdout and stderr to + * make the child process produce both on the same actual pipe. Or + * you might pass the same @a name as the stdout for one LLProcess + * and the stdin for another to connect the two child processes. + * Use LLProcess::getPipeName() to generate a unique name + * guaranteed not to already exist in the registry. Not yet + * implemented. + * + * The difference between "pipe", "tpipe" and "npipe" is as follows. + * + * - "pipe": direct LLProcess to monitor the parent end of the pipe, + * pumping nonblocking I/O every frame. The expectation (at least + * for stdout or stderr) is that the caller will listen for + * incoming data and consume it as it arrives. It's important not + * to neglect such a pipe, because it's buffered in memory. If you + * suspect the child may produce a great volume of output between + * frames, consider directing the child to write to a filesystem + * file instead, then read the file later. + * + * - "tpipe": do not engage LLProcess machinery to monitor the + * parent end of the pipe. A "tpipe" is used only to connect + * different child processes. As such, it makes little sense to + * pass an empty @a name. Not yet implemented. + * + * - "npipe": like "tpipe", but use an OS named pipe with a + * generated name. Note that @a name is the @em internal name of + * the pipe in our global registry -- it doesn't necessarily have + * anything to do with the pipe's name in the OS filesystem. Use + * LLProcess::getPipeName() to obtain the named pipe's OS + * filesystem name, e.g. to pass it as the @a name to another + * LLProcess instance using @a type "file". This supports usage + * like bash's <(subcommand...) or >(subcommand...) + * constructs. Not yet implemented. + * + * In all cases the open mode (read, write) is determined by the child + * slot you're filling. Child stdin means select the "read" end of a + * pipe, or open a filesystem file for reading; child stdout or stderr + * means select the "write" end of a pipe, or open a filesystem file + * for writing. + * + * Confusion such as passing the same pipe as the stdin of two + * processes (rather than stdout for one and stdin for the other) is + * explicitly permitted: it's up to the caller to construct meaningful + * LLProcess pipe graphs. + */ + Optional type; + Optional name; + + FileParam(const std::string& tp="", const std::string& nm=""): + type("type"), + name("name") + { + // If caller wants to specify values, use explicit assignment to + // set them rather than initialization. + if (! tp.empty()) type = tp; + if (! nm.empty()) name = nm; + } + }; + + /// Param block definition + struct Params: public LLInitParam::Block + { + Params(): + executable("executable"), + args("args"), + cwd("cwd"), + autokill("autokill", true), + attached("attached", true), + files("files"), + postend("postend"), + desc("desc") + {} + + /// pathname of executable + Mandatory executable; + /** + * zero or more additional command-line arguments. Arguments are + * passed through as exactly as we can manage, whitespace and all. + * @note On Windows we manage this by implicitly double-quoting each + * argument while assembling the command line. + */ + Multiple args; + /// current working directory, if need it changed + Optional cwd; + /// implicitly kill child process on termination of parent, whether + /// voluntary or crash (default true) + Optional autokill; + /// implicitly kill process on destruction of LLProcess object + /// (default same as autokill) + /// + /// Originally, 'autokill' conflated two concepts: kill child process on + /// - destruction of its LLProcess object, and + /// - termination of parent process, voluntary or otherwise. + /// + /// It's useful to tease these apart. Some child processes are sent a + /// "clean up and terminate" message before the associated LLProcess + /// object is destroyed. A child process launched with attached=false + /// has an extra time window from the destruction of its LLProcess + /// until parent-process termination in which to perform its own + /// orderly shutdown, yet autokill=true still guarantees that we won't + /// accumulate orphan instances of such processes indefinitely. With + /// attached=true, if a child process cannot clean up between the + /// shutdown message and LLProcess destruction (presumably very soon + /// thereafter), it's forcibly killed anyway -- which can lead to + /// distressing user-visible crash indications. + /// + /// (The usefulness of attached=true with autokill=false is less + /// clear, but we don't prohibit that combination.) + Optional attached; + /** + * Up to three FileParam items: for child stdin, stdout, stderr. + * Passing two FileParam entries means default treatment for stderr, + * and so forth. + * + * @note LLInitParam::Block permits usage like this: + * @code + * LLProcess::Params params; + * ... + * params.files + * .add(LLProcess::FileParam()) // stdin + * .add(LLProcess::FileParam().type("pipe") // stdout + * .add(LLProcess::FileParam().type("file").name("error.log")); + * @endcode + * + * @note While it's theoretically plausible to pass additional open + * file handles to a child specifically written to expect them, our + * underlying implementation doesn't yet support that. + */ + Multiple > files; + /** + * On child-process termination, if this LLProcess object still + * exists, post LLSD event to LLEventPump with specified name (default + * no event). Event contains at least: + * + * - "id" as obtained from getProcessID() + * - "desc" short string description of child (executable + pid) + * - "state" @c state enum value, from Status.mState + * - "data" if "state" is EXITED, exit code; if KILLED, on Posix, + * signal number + * - "string" English text describing "state" and "data" (e.g. "exited + * with code 0") + */ + Optional postend; + /** + * Description of child process for logging purposes. It need not be + * unique; the logged description string will contain the PID as well. + * If this is omitted, a description will be derived from the + * executable name. + */ + Optional desc; + }; + typedef LLSDParamAdapter LLSDOrParams; + + /** + * Factory accepting either plain LLSD::Map or Params block. + * MAY RETURN DEFAULT-CONSTRUCTED LLProcessPtr if params invalid! + */ + static LLProcessPtr create(const LLSDOrParams& params); + virtual ~LLProcess(); + + /// Is child process still running? + bool isRunning() const; + // static isRunning(LLProcessPtr), getStatus(LLProcessPtr), + // getStatusString(LLProcessPtr), kill(LLProcessPtr) handle the case in + // which the passed LLProcessPtr might be NULL (default-constructed). + static bool isRunning(const LLProcessPtr&); + + /** + * State of child process + */ + enum state + { + UNSTARTED, ///< initial value, invisible to consumer + RUNNING, ///< child process launched + EXITED, ///< child process terminated voluntarily + KILLED ///< child process terminated involuntarily + }; + + /** + * Status info + */ + struct Status + { + Status(): + mState(UNSTARTED), + mData(0) + {} + + state mState; ///< @see state + /** + * - for mState == EXITED: mData is exit() code + * - for mState == KILLED: mData is signal number (Posix) + * - otherwise: mData is undefined + */ + int mData; + }; + + /// Status query + Status getStatus() const; + static Status getStatus(const LLProcessPtr&); + /// English Status string query, for logging etc. + std::string getStatusString() const; + static std::string getStatusString(const std::string& desc, const LLProcessPtr&); + /// English Status string query for previously-captured Status + std::string getStatusString(const Status& status) const; + /// static English Status string query + static std::string getStatusString(const std::string& desc, const Status& status); + + // Attempt to kill the process -- returns true if the process is no longer running when it returns. + // Note that even if this returns false, the process may exit some time after it's called. + bool kill(const std::string& who=""); + static bool kill(const LLProcessPtr& p, const std::string& who=""); #if LL_WINDOWS - typedef int id; ///< as returned by getProcessID() - typedef HANDLE handle; ///< as returned by getProcessHandle() + typedef int id; ///< as returned by getProcessID() + typedef HANDLE handle; ///< as returned by getProcessHandle() #else - typedef pid_t id; - typedef pid_t handle; + typedef pid_t id; + typedef pid_t handle; #endif - /** - * Get an int-like id value. This is primarily intended for a human reader - * to differentiate processes. - */ - id getProcessID() const; - /** - * Get a "handle" of a kind that you might pass to platform-specific API - * functions to engage features not directly supported by LLProcess. - */ - handle getProcessHandle() const; - - /** - * Test if a process (@c handle obtained from getProcessHandle()) is still - * running. Return same nonzero @c handle value if still running, else - * zero, so you can test it like a bool. But if you want to update a - * stored variable as a side effect, you can write code like this: - * @code - * hchild = LLProcess::isRunning(hchild); - * @endcode - * @note This method is intended as a unit-test hook, not as the first of - * a whole set of operations supported on freestanding @c handle values. - * New functionality should be added as nonstatic members operating on - * the same data as getProcessHandle(). - * - * In particular, if child termination is detected by this static isRunning() - * rather than by nonstatic isRunning(), the LLProcess object won't be - * aware of the child's changed status and may encounter OS errors trying - * to obtain it. This static isRunning() is only intended for after the - * launching LLProcess object has been destroyed. - */ - static handle isRunning(handle, const std::string& desc=""); - - /// Provide symbolic access to child's file slots - enum FILESLOT { STDIN=0, STDOUT=1, STDERR=2, NSLOTS=3 }; - - /** - * For a pipe constructed with @a type "npipe", obtain the generated OS - * filesystem name for the specified pipe. Otherwise returns the empty - * string. @see LLProcess::FileParam::type - */ - std::string getPipeName(FILESLOT) const; - - /// base of ReadPipe, WritePipe - class LL_COMMON_API BasePipe - { - public: - virtual ~BasePipe() = 0; - - typedef std::size_t size_type; - static const size_type npos; - - /** - * Get accumulated buffer length. - * - * For WritePipe, is there still pending data to send to child? - * - * For ReadPipe, we often need to refrain from actually reading the - * std::istream returned by get_istream() until we've accumulated - * enough data to make it worthwhile. For instance, if we're expecting - * a number from the child, but the child happens to flush "12" before - * emitting "3\n", get_istream() >> myint could return 12 rather than - * 123! - */ - virtual size_type size() const = 0; - }; - - /// As returned by getWritePipe() or getOptWritePipe() - class WritePipe: public BasePipe - { - public: - /** - * Get ostream& on which to write to child's stdin. - * - * @usage - * @code - * myProcess->getWritePipe().get_ostream() << "Hello, child!" << std::endl; - * @endcode - */ - virtual std::ostream& get_ostream() = 0; - }; - - /// As returned by getReadPipe() or getOptReadPipe() - class ReadPipe: public BasePipe - { - public: - /** - * Get istream& on which to read from child's stdout or stderr. - * - * @usage - * @code - * std::string stuff; - * myProcess->getReadPipe().get_istream() >> stuff; - * @endcode - * - * You should be sure in advance that the ReadPipe in question can - * fill the request. @see getPump() - */ - virtual std::istream& get_istream() = 0; - - /** - * Like std::getline(get_istream(), line), but trims off trailing '\r' - * to make calling code less platform-sensitive. - */ - virtual std::string getline() = 0; - - /** - * Like get_istream().read(buffer, n), but returns std::string rather - * than requiring caller to construct a buffer, etc. - */ - virtual std::string read(size_type len) = 0; - - /** - * Peek at accumulated buffer data without consuming it. Optional - * parameters give you substr() functionality. - * - * @note You can discard buffer data using get_istream().ignore(n). - */ - virtual std::string peek(size_type offset=0, size_type len=npos) const = 0; - - /** - * Detect presence of a substring (or char) in accumulated buffer data - * without retrieving it. Optional offset allows you to search from - * specified position. - */ - template - bool contains(SEEK seek, size_type offset=0) const - { return find(seek, offset) != npos; } - - /** - * Search for a substring in accumulated buffer data without - * retrieving it. Returns size_type position at which found, or npos - * meaning not found. Optional offset allows you to search from - * specified position. - */ - virtual size_type find(const std::string& seek, size_type offset=0) const = 0; - - /** - * Search for a char in accumulated buffer data without retrieving it. - * Returns size_type position at which found, or npos meaning not - * found. Optional offset allows you to search from specified - * position. - */ - virtual size_type find(char seek, size_type offset=0) const = 0; - - /** - * Get LLEventPump& on which to listen for incoming data. The posted - * LLSD::Map event will contain: - * - * - "data" part of pending data; see setLimit() - * - "len" entire length of pending data, regardless of setLimit() - * - "slot" this ReadPipe's FILESLOT, e.g. LLProcess::STDOUT - * - "name" e.g. "stdout" - * - "desc" e.g. "SLPlugin (pid) stdout" - * - "eof" @c true means there no more data will arrive on this pipe, - * therefore no more events on this pump - * - * If the child sends "abc", and this ReadPipe posts "data"="abc", but - * you don't consume it by reading the std::istream returned by - * get_istream(), and the child next sends "def", ReadPipe will post - * "data"="abcdef". - */ - virtual LLEventPump& getPump() = 0; - - /** - * Set maximum length of buffer data that will be posted in the LLSD - * announcing arrival of new data from the child. If you call - * setLimit(5), and the child sends "abcdef", the LLSD event will - * contain "data"="abcde". However, you may still read the entire - * "abcdef" from get_istream(): this limit affects only the size of - * the data posted with the LLSD event. If you don't call this method, - * @em no data will be posted: the default is 0 bytes. - */ - virtual void setLimit(size_type limit) = 0; - - /** - * Query the current setLimit() limit. - */ - virtual size_type getLimit() const = 0; - }; - - /// Exception thrown by getWritePipe(), getReadPipe() if you didn't ask to - /// create a pipe at the corresponding FILESLOT. - struct NoPipe: public LLException - { - NoPipe(const std::string& what): LLException(what) {} - }; - - /** - * Get a reference to the (only) WritePipe for this LLProcess. @a slot, if - * specified, must be STDIN. Throws NoPipe if you did not request a "pipe" - * for child stdin. Use this method when you know how you created the - * LLProcess in hand. - */ - WritePipe& getWritePipe(FILESLOT slot=STDIN); - - /** - * Get a boost::optional to the (only) WritePipe for this - * LLProcess. @a slot, if specified, must be STDIN. The return value is - * empty if you did not request a "pipe" for child stdin. Use this method - * for inspecting an LLProcess you did not create. - */ - boost::optional getOptWritePipe(FILESLOT slot=STDIN); - - /** - * Get a reference to one of the ReadPipes for this LLProcess. @a slot, if - * specified, must be STDOUT or STDERR. Throws NoPipe if you did not - * request a "pipe" for child stdout or stderr. Use this method when you - * know how you created the LLProcess in hand. - */ - ReadPipe& getReadPipe(FILESLOT slot); - - /** - * Get a boost::optional to one of the ReadPipes for this - * LLProcess. @a slot, if specified, must be STDOUT or STDERR. The return - * value is empty if you did not request a "pipe" for child stdout or - * stderr. Use this method for inspecting an LLProcess you did not create. - */ - boost::optional getOptReadPipe(FILESLOT slot); - - /// little utilities that really should already be somewhere else in the - /// code base - static std::string basename(const std::string& path); - static std::string getline(std::istream&); + /** + * Get an int-like id value. This is primarily intended for a human reader + * to differentiate processes. + */ + id getProcessID() const; + /** + * Get a "handle" of a kind that you might pass to platform-specific API + * functions to engage features not directly supported by LLProcess. + */ + handle getProcessHandle() const; + + /** + * Test if a process (@c handle obtained from getProcessHandle()) is still + * running. Return same nonzero @c handle value if still running, else + * zero, so you can test it like a bool. But if you want to update a + * stored variable as a side effect, you can write code like this: + * @code + * hchild = LLProcess::isRunning(hchild); + * @endcode + * @note This method is intended as a unit-test hook, not as the first of + * a whole set of operations supported on freestanding @c handle values. + * New functionality should be added as nonstatic members operating on + * the same data as getProcessHandle(). + * + * In particular, if child termination is detected by this static isRunning() + * rather than by nonstatic isRunning(), the LLProcess object won't be + * aware of the child's changed status and may encounter OS errors trying + * to obtain it. This static isRunning() is only intended for after the + * launching LLProcess object has been destroyed. + */ + static handle isRunning(handle, const std::string& desc=""); + + /// Provide symbolic access to child's file slots + enum FILESLOT { STDIN=0, STDOUT=1, STDERR=2, NSLOTS=3 }; + + /** + * For a pipe constructed with @a type "npipe", obtain the generated OS + * filesystem name for the specified pipe. Otherwise returns the empty + * string. @see LLProcess::FileParam::type + */ + std::string getPipeName(FILESLOT) const; + + /// base of ReadPipe, WritePipe + class LL_COMMON_API BasePipe + { + public: + virtual ~BasePipe() = 0; + + typedef std::size_t size_type; + static const size_type npos; + + /** + * Get accumulated buffer length. + * + * For WritePipe, is there still pending data to send to child? + * + * For ReadPipe, we often need to refrain from actually reading the + * std::istream returned by get_istream() until we've accumulated + * enough data to make it worthwhile. For instance, if we're expecting + * a number from the child, but the child happens to flush "12" before + * emitting "3\n", get_istream() >> myint could return 12 rather than + * 123! + */ + virtual size_type size() const = 0; + }; + + /// As returned by getWritePipe() or getOptWritePipe() + class WritePipe: public BasePipe + { + public: + /** + * Get ostream& on which to write to child's stdin. + * + * @usage + * @code + * myProcess->getWritePipe().get_ostream() << "Hello, child!" << std::endl; + * @endcode + */ + virtual std::ostream& get_ostream() = 0; + }; + + /// As returned by getReadPipe() or getOptReadPipe() + class ReadPipe: public BasePipe + { + public: + /** + * Get istream& on which to read from child's stdout or stderr. + * + * @usage + * @code + * std::string stuff; + * myProcess->getReadPipe().get_istream() >> stuff; + * @endcode + * + * You should be sure in advance that the ReadPipe in question can + * fill the request. @see getPump() + */ + virtual std::istream& get_istream() = 0; + + /** + * Like std::getline(get_istream(), line), but trims off trailing '\r' + * to make calling code less platform-sensitive. + */ + virtual std::string getline() = 0; + + /** + * Like get_istream().read(buffer, n), but returns std::string rather + * than requiring caller to construct a buffer, etc. + */ + virtual std::string read(size_type len) = 0; + + /** + * Peek at accumulated buffer data without consuming it. Optional + * parameters give you substr() functionality. + * + * @note You can discard buffer data using get_istream().ignore(n). + */ + virtual std::string peek(size_type offset=0, size_type len=npos) const = 0; + + /** + * Detect presence of a substring (or char) in accumulated buffer data + * without retrieving it. Optional offset allows you to search from + * specified position. + */ + template + bool contains(SEEK seek, size_type offset=0) const + { return find(seek, offset) != npos; } + + /** + * Search for a substring in accumulated buffer data without + * retrieving it. Returns size_type position at which found, or npos + * meaning not found. Optional offset allows you to search from + * specified position. + */ + virtual size_type find(const std::string& seek, size_type offset=0) const = 0; + + /** + * Search for a char in accumulated buffer data without retrieving it. + * Returns size_type position at which found, or npos meaning not + * found. Optional offset allows you to search from specified + * position. + */ + virtual size_type find(char seek, size_type offset=0) const = 0; + + /** + * Get LLEventPump& on which to listen for incoming data. The posted + * LLSD::Map event will contain: + * + * - "data" part of pending data; see setLimit() + * - "len" entire length of pending data, regardless of setLimit() + * - "slot" this ReadPipe's FILESLOT, e.g. LLProcess::STDOUT + * - "name" e.g. "stdout" + * - "desc" e.g. "SLPlugin (pid) stdout" + * - "eof" @c true means there no more data will arrive on this pipe, + * therefore no more events on this pump + * + * If the child sends "abc", and this ReadPipe posts "data"="abc", but + * you don't consume it by reading the std::istream returned by + * get_istream(), and the child next sends "def", ReadPipe will post + * "data"="abcdef". + */ + virtual LLEventPump& getPump() = 0; + + /** + * Set maximum length of buffer data that will be posted in the LLSD + * announcing arrival of new data from the child. If you call + * setLimit(5), and the child sends "abcdef", the LLSD event will + * contain "data"="abcde". However, you may still read the entire + * "abcdef" from get_istream(): this limit affects only the size of + * the data posted with the LLSD event. If you don't call this method, + * @em no data will be posted: the default is 0 bytes. + */ + virtual void setLimit(size_type limit) = 0; + + /** + * Query the current setLimit() limit. + */ + virtual size_type getLimit() const = 0; + }; + + /// Exception thrown by getWritePipe(), getReadPipe() if you didn't ask to + /// create a pipe at the corresponding FILESLOT. + struct NoPipe: public LLException + { + NoPipe(const std::string& what): LLException(what) {} + }; + + /** + * Get a reference to the (only) WritePipe for this LLProcess. @a slot, if + * specified, must be STDIN. Throws NoPipe if you did not request a "pipe" + * for child stdin. Use this method when you know how you created the + * LLProcess in hand. + */ + WritePipe& getWritePipe(FILESLOT slot=STDIN); + + /** + * Get a boost::optional to the (only) WritePipe for this + * LLProcess. @a slot, if specified, must be STDIN. The return value is + * empty if you did not request a "pipe" for child stdin. Use this method + * for inspecting an LLProcess you did not create. + */ + boost::optional getOptWritePipe(FILESLOT slot=STDIN); + + /** + * Get a reference to one of the ReadPipes for this LLProcess. @a slot, if + * specified, must be STDOUT or STDERR. Throws NoPipe if you did not + * request a "pipe" for child stdout or stderr. Use this method when you + * know how you created the LLProcess in hand. + */ + ReadPipe& getReadPipe(FILESLOT slot); + + /** + * Get a boost::optional to one of the ReadPipes for this + * LLProcess. @a slot, if specified, must be STDOUT or STDERR. The return + * value is empty if you did not request a "pipe" for child stdout or + * stderr. Use this method for inspecting an LLProcess you did not create. + */ + boost::optional getOptReadPipe(FILESLOT slot); + + /// little utilities that really should already be somewhere else in the + /// code base + static std::string basename(const std::string& path); + static std::string getline(std::istream&); private: - /// constructor is private: use create() instead - LLProcess(const LLSDOrParams& params); - void autokill(); - // Classic-C-style APR callback - static void status_callback(int reason, void* data, int status); - // Object-oriented callback - void handle_status(int reason, int status); - // implementation for get[Opt][Read|Write]Pipe() - template - PIPETYPE& getPipe(FILESLOT slot); - template - boost::optional getOptPipe(FILESLOT slot); - template - PIPETYPE* getPipePtr(std::string& error, FILESLOT slot); - - std::string mDesc; - std::string mPostend; - apr_proc_t mProcess; - bool mAutokill, mAttached; - Status mStatus; - // explicitly want this ptr_vector to be able to store NULLs - typedef boost::ptr_vector< boost::nullable > PipeVector; - PipeVector mPipes; + /// constructor is private: use create() instead + LLProcess(const LLSDOrParams& params); + void autokill(); + // Classic-C-style APR callback + static void status_callback(int reason, void* data, int status); + // Object-oriented callback + void handle_status(int reason, int status); + // implementation for get[Opt][Read|Write]Pipe() + template + PIPETYPE& getPipe(FILESLOT slot); + template + boost::optional getOptPipe(FILESLOT slot); + template + PIPETYPE* getPipePtr(std::string& error, FILESLOT slot); + + std::string mDesc; + std::string mPostend; + apr_proc_t mProcess; + bool mAutokill, mAttached; + Status mStatus; + // explicitly want this ptr_vector to be able to store NULLs + typedef boost::ptr_vector< boost::nullable > PipeVector; + PipeVector mPipes; apr_pool_t* mPool; }; diff --git a/indra/llcommon/llprocessor.cpp b/indra/llcommon/llprocessor.cpp index 28f8bc2b93..9d53b9be35 100644 --- a/indra/llcommon/llprocessor.cpp +++ b/indra/llcommon/llprocessor.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llprocessor.cpp * @brief Code to figure out the processor. Originally by Benjamin Jurke. * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -34,199 +34,199 @@ //#include #if LL_WINDOWS -# include "llwin32headerslean.h" -# define _interlockedbittestandset _renamed_interlockedbittestandset -# define _interlockedbittestandreset _renamed_interlockedbittestandreset -# include -# undef _interlockedbittestandset -# undef _interlockedbittestandreset +# include "llwin32headerslean.h" +# define _interlockedbittestandset _renamed_interlockedbittestandset +# define _interlockedbittestandreset _renamed_interlockedbittestandreset +# include +# undef _interlockedbittestandset +# undef _interlockedbittestandreset #endif #include "llsd.h" class LLProcessorInfoImpl; // foward declaration for the mImpl; -namespace +namespace { - enum cpu_info - { - eBrandName = 0, - eFrequency, - eVendor, - eStepping, - eFamily, - eExtendedFamily, - eModel, - eExtendedModel, - eType, - eBrandID, - eFamilyName - }; - - - const char* cpu_info_names[] = - { - "Processor Name", - "Frequency", - "Vendor", - "Stepping", - "Family", - "Extended Family", - "Model", - "Extended Model", - "Type", - "Brand ID", - "Family Name" - }; - - enum cpu_config - { - eMaxID, - eMaxExtID, - eCLFLUSHCacheLineSize, - eAPICPhysicalID, - eCacheLineSize, - eL2Associativity, - eCacheSizeK, - eFeatureBits, - eExtFeatureBits - }; - - const char* cpu_config_names[] = - { - "Max Supported CPUID level", - "Max Supported Ext. CPUID level", - "CLFLUSH cache line size", - "APIC Physical ID", - "Cache Line Size", - "L2 Associativity", - "Cache Size", - "Feature Bits", - "Ext. Feature Bits" - }; - - - - // *NOTE:Mani - this contains the elements we reference directly and extensions beyond the first 32. - // The rest of the names are referenced by bit maks returned from cpuid. - enum cpu_features - { - eSSE_Ext=25, - eSSE2_Ext=26, - - eSSE3_Features=32, - eMONTIOR_MWAIT=33, - eCPLDebugStore=34, - eThermalMonitor2=35, - eAltivec=36, + enum cpu_info + { + eBrandName = 0, + eFrequency, + eVendor, + eStepping, + eFamily, + eExtendedFamily, + eModel, + eExtendedModel, + eType, + eBrandID, + eFamilyName + }; + + + const char* cpu_info_names[] = + { + "Processor Name", + "Frequency", + "Vendor", + "Stepping", + "Family", + "Extended Family", + "Model", + "Extended Model", + "Type", + "Brand ID", + "Family Name" + }; + + enum cpu_config + { + eMaxID, + eMaxExtID, + eCLFLUSHCacheLineSize, + eAPICPhysicalID, + eCacheLineSize, + eL2Associativity, + eCacheSizeK, + eFeatureBits, + eExtFeatureBits + }; + + const char* cpu_config_names[] = + { + "Max Supported CPUID level", + "Max Supported Ext. CPUID level", + "CLFLUSH cache line size", + "APIC Physical ID", + "Cache Line Size", + "L2 Associativity", + "Cache Size", + "Feature Bits", + "Ext. Feature Bits" + }; + + + + // *NOTE:Mani - this contains the elements we reference directly and extensions beyond the first 32. + // The rest of the names are referenced by bit maks returned from cpuid. + enum cpu_features + { + eSSE_Ext=25, + eSSE2_Ext=26, + + eSSE3_Features=32, + eMONTIOR_MWAIT=33, + eCPLDebugStore=34, + eThermalMonitor2=35, + eAltivec=36, eSSE3S_Features = 37, eSSE4_1_Features = 38, eSSE4_2_Features = 39, eSSE4a_Features = 40, - }; - - const char* cpu_feature_names[] = - { - "x87 FPU On Chip", - "Virtual-8086 Mode Enhancement", - "Debugging Extensions", - "Page Size Extensions", - "Time Stamp Counter", - "RDMSR and WRMSR Support", - "Physical Address Extensions", - "Machine Check Exception", - "CMPXCHG8B Instruction", - "APIC On Chip", - "Unknown1", - "SYSENTER and SYSEXIT", - "Memory Type Range Registers", - "PTE Global Bit", - "Machine Check Architecture", - "Conditional Move/Compare Instruction", - "Page Attribute Table", - "Page Size Extension", - "Processor Serial Number", - "CFLUSH Extension", - "Unknown2", - "Debug Store", - "Thermal Monitor and Clock Ctrl", - "MMX Technology", - "FXSAVE/FXRSTOR", - "SSE Extensions", - "SSE2 Extensions", - "Self Snoop", - "Hyper-threading Technology", - "Thermal Monitor", - "Unknown4", - "Pend. Brk. EN.", // 31 End of FeatureInfo bits - - "SSE3 New Instructions", // 32 - "MONITOR/MWAIT", - "CPL Qualified Debug Store", - "Thermal Monitor 2", - - "Altivec", + }; + + const char* cpu_feature_names[] = + { + "x87 FPU On Chip", + "Virtual-8086 Mode Enhancement", + "Debugging Extensions", + "Page Size Extensions", + "Time Stamp Counter", + "RDMSR and WRMSR Support", + "Physical Address Extensions", + "Machine Check Exception", + "CMPXCHG8B Instruction", + "APIC On Chip", + "Unknown1", + "SYSENTER and SYSEXIT", + "Memory Type Range Registers", + "PTE Global Bit", + "Machine Check Architecture", + "Conditional Move/Compare Instruction", + "Page Attribute Table", + "Page Size Extension", + "Processor Serial Number", + "CFLUSH Extension", + "Unknown2", + "Debug Store", + "Thermal Monitor and Clock Ctrl", + "MMX Technology", + "FXSAVE/FXRSTOR", + "SSE Extensions", + "SSE2 Extensions", + "Self Snoop", + "Hyper-threading Technology", + "Thermal Monitor", + "Unknown4", + "Pend. Brk. EN.", // 31 End of FeatureInfo bits + + "SSE3 New Instructions", // 32 + "MONITOR/MWAIT", + "CPL Qualified Debug Store", + "Thermal Monitor 2", + + "Altivec", "SSE3S Instructions", "SSE4.1 Instructions", "SSE4.2 Instructions", "SSE4a Instructions", - }; - - std::string intel_CPUFamilyName(int composed_family) - { - switch(composed_family) - { - case 3: return "Intel i386"; - case 4: return "Intel i486"; - case 5: return "Intel Pentium"; - case 6: return "Intel Pentium Pro/2/3, Core"; - case 7: return "Intel Itanium (IA-64)"; - case 0xF: return "Intel Pentium 4"; - case 0x10: return "Intel Itanium 2 (IA-64)"; - } - return STRINGIZE("Intel "); - } - - std::string amd_CPUFamilyName(int composed_family) - { + }; + + std::string intel_CPUFamilyName(int composed_family) + { + switch(composed_family) + { + case 3: return "Intel i386"; + case 4: return "Intel i486"; + case 5: return "Intel Pentium"; + case 6: return "Intel Pentium Pro/2/3, Core"; + case 7: return "Intel Itanium (IA-64)"; + case 0xF: return "Intel Pentium 4"; + case 0x10: return "Intel Itanium 2 (IA-64)"; + } + return STRINGIZE("Intel "); + } + + std::string amd_CPUFamilyName(int composed_family) + { // https://en.wikipedia.org/wiki/List_of_AMD_CPU_microarchitectures // https://developer.amd.com/resources/developer-guides-manuals/ - switch(composed_family) - { - case 4: return "AMD 80486/5x86"; - case 5: return "AMD K5/K6"; - case 6: return "AMD K7"; - case 0xF: return "AMD K8"; - case 0x10: return "AMD K8L"; - case 0x12: return "AMD K10"; - case 0x14: return "AMD Bobcat"; - case 0x15: return "AMD Bulldozer"; - case 0x16: return "AMD Jaguar"; - case 0x17: return "AMD Zen/Zen+/Zen2"; - case 0x18: return "AMD Hygon Dhyana"; - case 0x19: return "AMD Zen 3"; - } - return STRINGIZE("AMD "); - } - - std::string compute_CPUFamilyName(const char* cpu_vendor, int family, int ext_family) - { - const char* intel_string = "GenuineIntel"; - const char* amd_string = "AuthenticAMD"; - if (LLStringUtil::startsWith(cpu_vendor, intel_string)) - { - U32 composed_family = family + ext_family; - return intel_CPUFamilyName(composed_family); - } - else if (LLStringUtil::startsWith(cpu_vendor, amd_string)) - { - U32 composed_family = (family == 0xF) - ? family + ext_family - : family; - return amd_CPUFamilyName(composed_family); - } - return STRINGIZE("Unrecognized CPU vendor <" << cpu_vendor << ">"); - } + switch(composed_family) + { + case 4: return "AMD 80486/5x86"; + case 5: return "AMD K5/K6"; + case 6: return "AMD K7"; + case 0xF: return "AMD K8"; + case 0x10: return "AMD K8L"; + case 0x12: return "AMD K10"; + case 0x14: return "AMD Bobcat"; + case 0x15: return "AMD Bulldozer"; + case 0x16: return "AMD Jaguar"; + case 0x17: return "AMD Zen/Zen+/Zen2"; + case 0x18: return "AMD Hygon Dhyana"; + case 0x19: return "AMD Zen 3"; + } + return STRINGIZE("AMD "); + } + + std::string compute_CPUFamilyName(const char* cpu_vendor, int family, int ext_family) + { + const char* intel_string = "GenuineIntel"; + const char* amd_string = "AuthenticAMD"; + if (LLStringUtil::startsWith(cpu_vendor, intel_string)) + { + U32 composed_family = family + ext_family; + return intel_CPUFamilyName(composed_family); + } + else if (LLStringUtil::startsWith(cpu_vendor, amd_string)) + { + U32 composed_family = (family == 0xF) + ? family + ext_family + : family; + return amd_CPUFamilyName(composed_family); + } + return STRINGIZE("Unrecognized CPU vendor <" << cpu_vendor << ">"); + } } // end unnamed namespace @@ -235,28 +235,28 @@ namespace class LLProcessorInfoImpl { public: - LLProcessorInfoImpl() - { - mProcessorInfo["info"] = LLSD::emptyMap(); - mProcessorInfo["config"] = LLSD::emptyMap(); - mProcessorInfo["extension"] = LLSD::emptyMap(); - } - virtual ~LLProcessorInfoImpl() {} - - F64 getCPUFrequency() const - { - return getInfo(eFrequency, 0).asReal(); - } - - bool hasSSE() const - { - return hasExtension(cpu_feature_names[eSSE_Ext]); - } - - bool hasSSE2() const - { - return hasExtension(cpu_feature_names[eSSE2_Ext]); - } + LLProcessorInfoImpl() + { + mProcessorInfo["info"] = LLSD::emptyMap(); + mProcessorInfo["config"] = LLSD::emptyMap(); + mProcessorInfo["extension"] = LLSD::emptyMap(); + } + virtual ~LLProcessorInfoImpl() {} + + F64 getCPUFrequency() const + { + return getInfo(eFrequency, 0).asReal(); + } + + bool hasSSE() const + { + return hasExtension(cpu_feature_names[eSSE_Ext]); + } + + bool hasSSE2() const + { + return hasExtension(cpu_feature_names[eSSE2_Ext]); + } bool hasSSE3() const { @@ -283,229 +283,229 @@ public: return hasExtension(cpu_feature_names[eSSE4a_Features]); } - bool hasAltivec() const - { - return hasExtension("Altivec"); - } - - std::string getCPUFamilyName() const { return getInfo(eFamilyName, "Unset family").asString(); } - std::string getCPUBrandName() const { return getInfo(eBrandName, "Unset brand").asString(); } - - // This is virtual to support a different linux format. - // *NOTE:Mani - I didn't want to screw up server use of this data... - virtual std::string getCPUFeatureDescription() const - { - std::ostringstream out; - out << std::endl << std::endl; - out << "// CPU General Information" << std::endl; - out << "//////////////////////////" << std::endl; - out << "Processor Name: " << getCPUBrandName() << std::endl; - out << "Frequency: " << getCPUFrequency() << " MHz" << std::endl; - out << "Vendor: " << getInfo(eVendor, "Unset vendor").asString() << std::endl; - out << "Family: " << getCPUFamilyName() << " (" << getInfo(eFamily, 0) << ")" << std::endl; - out << "Extended family: " << getInfo(eExtendedFamily, 0) << std::endl; - out << "Model: " << getInfo(eModel, 0) << std::endl; - out << "Extended model: " << getInfo(eExtendedModel, 0) << std::endl; - out << "Type: " << getInfo(eType, 0) << std::endl; - out << "Brand ID: " << getInfo(eBrandID, 0) << std::endl; - out << std::endl; - out << "// CPU Configuration" << std::endl; - out << "//////////////////////////" << std::endl; - - // Iterate through the dictionary of configuration options. - LLSD configs = mProcessorInfo["config"]; - for(LLSD::map_const_iterator cfgItr = configs.beginMap(); cfgItr != configs.endMap(); ++cfgItr) - { - out << cfgItr->first << " = " << cfgItr->second << std::endl; - } - out << std::endl; - - out << "// CPU Extensions" << std::endl; - out << "//////////////////////////" << std::endl; - - for(LLSD::map_const_iterator itr = mProcessorInfo["extension"].beginMap(); itr != mProcessorInfo["extension"].endMap(); ++itr) - { - out << " " << itr->first << std::endl; - } - return out.str(); - } + bool hasAltivec() const + { + return hasExtension("Altivec"); + } + + std::string getCPUFamilyName() const { return getInfo(eFamilyName, "Unset family").asString(); } + std::string getCPUBrandName() const { return getInfo(eBrandName, "Unset brand").asString(); } + + // This is virtual to support a different linux format. + // *NOTE:Mani - I didn't want to screw up server use of this data... + virtual std::string getCPUFeatureDescription() const + { + std::ostringstream out; + out << std::endl << std::endl; + out << "// CPU General Information" << std::endl; + out << "//////////////////////////" << std::endl; + out << "Processor Name: " << getCPUBrandName() << std::endl; + out << "Frequency: " << getCPUFrequency() << " MHz" << std::endl; + out << "Vendor: " << getInfo(eVendor, "Unset vendor").asString() << std::endl; + out << "Family: " << getCPUFamilyName() << " (" << getInfo(eFamily, 0) << ")" << std::endl; + out << "Extended family: " << getInfo(eExtendedFamily, 0) << std::endl; + out << "Model: " << getInfo(eModel, 0) << std::endl; + out << "Extended model: " << getInfo(eExtendedModel, 0) << std::endl; + out << "Type: " << getInfo(eType, 0) << std::endl; + out << "Brand ID: " << getInfo(eBrandID, 0) << std::endl; + out << std::endl; + out << "// CPU Configuration" << std::endl; + out << "//////////////////////////" << std::endl; + + // Iterate through the dictionary of configuration options. + LLSD configs = mProcessorInfo["config"]; + for(LLSD::map_const_iterator cfgItr = configs.beginMap(); cfgItr != configs.endMap(); ++cfgItr) + { + out << cfgItr->first << " = " << cfgItr->second << std::endl; + } + out << std::endl; + + out << "// CPU Extensions" << std::endl; + out << "//////////////////////////" << std::endl; + + for(LLSD::map_const_iterator itr = mProcessorInfo["extension"].beginMap(); itr != mProcessorInfo["extension"].endMap(); ++itr) + { + out << " " << itr->first << std::endl; + } + return out.str(); + } protected: - void setInfo(cpu_info info_type, const LLSD& value) - { - setInfo(cpu_info_names[info_type], value); - } + void setInfo(cpu_info info_type, const LLSD& value) + { + setInfo(cpu_info_names[info_type], value); + } LLSD getInfo(cpu_info info_type, const LLSD& defaultVal) const - { - return getInfo(cpu_info_names[info_type], defaultVal); - } - - void setConfig(cpu_config config_type, const LLSD& value) - { - setConfig(cpu_config_names[config_type], value); - } - LLSD getConfig(cpu_config config_type, const LLSD& defaultVal) const - { - return getConfig(cpu_config_names[config_type], defaultVal); - } - - void setExtension(const std::string& name) { mProcessorInfo["extension"][name] = "true"; } - bool hasExtension(const std::string& name) const - { - return mProcessorInfo["extension"].has(name); - } + { + return getInfo(cpu_info_names[info_type], defaultVal); + } + + void setConfig(cpu_config config_type, const LLSD& value) + { + setConfig(cpu_config_names[config_type], value); + } + LLSD getConfig(cpu_config config_type, const LLSD& defaultVal) const + { + return getConfig(cpu_config_names[config_type], defaultVal); + } + + void setExtension(const std::string& name) { mProcessorInfo["extension"][name] = "true"; } + bool hasExtension(const std::string& name) const + { + return mProcessorInfo["extension"].has(name); + } private: - void setInfo(const std::string& name, const LLSD& value) { mProcessorInfo["info"][name]=value; } - LLSD getInfo(const std::string& name, const LLSD& defaultVal) const - { - if(mProcessorInfo["info"].has(name)) - { - return mProcessorInfo["info"][name]; - } - return defaultVal; - } - void setConfig(const std::string& name, const LLSD& value) { mProcessorInfo["config"][name]=value; } - LLSD getConfig(const std::string& name, const LLSD& defaultVal) const - { - LLSD r = mProcessorInfo["config"].get(name); - return r.isDefined() ? r : defaultVal; - } + void setInfo(const std::string& name, const LLSD& value) { mProcessorInfo["info"][name]=value; } + LLSD getInfo(const std::string& name, const LLSD& defaultVal) const + { + if(mProcessorInfo["info"].has(name)) + { + return mProcessorInfo["info"][name]; + } + return defaultVal; + } + void setConfig(const std::string& name, const LLSD& value) { mProcessorInfo["config"][name]=value; } + LLSD getConfig(const std::string& name, const LLSD& defaultVal) const + { + LLSD r = mProcessorInfo["config"].get(name); + return r.isDefined() ? r : defaultVal; + } private: - LLSD mProcessorInfo; + LLSD mProcessorInfo; }; #ifdef LL_MSVC -// LL_MSVC and not LLWINDOWS because some of the following code +// LL_MSVC and not LLWINDOWS because some of the following code // uses the MSVC compiler intrinsics __cpuid() and __rdtsc(). // Delays for the specified amount of milliseconds static void _Delay(unsigned int ms) { - LARGE_INTEGER freq, c1, c2; - __int64 x; - - // Get High-Res Timer frequency - if (!QueryPerformanceFrequency(&freq)) - return; - - // Convert ms to High-Res Timer value - x = freq.QuadPart/1000*ms; - - // Get first snapshot of High-Res Timer value - QueryPerformanceCounter(&c1); - do - { - // Get second snapshot - QueryPerformanceCounter(&c2); - }while(c2.QuadPart-c1.QuadPart < x); - // Loop while (second-first < x) + LARGE_INTEGER freq, c1, c2; + __int64 x; + + // Get High-Res Timer frequency + if (!QueryPerformanceFrequency(&freq)) + return; + + // Convert ms to High-Res Timer value + x = freq.QuadPart/1000*ms; + + // Get first snapshot of High-Res Timer value + QueryPerformanceCounter(&c1); + do + { + // Get second snapshot + QueryPerformanceCounter(&c2); + }while(c2.QuadPart-c1.QuadPart < x); + // Loop while (second-first < x) } static F64 calculate_cpu_frequency(U32 measure_msecs) { - if(measure_msecs == 0) - { - return 0; - } - - // After that we declare some vars and check the frequency of the high - // resolution timer for the measure process. - // If there"s no high-res timer, we exit. - unsigned __int64 starttime, endtime, timedif, freq, start, end, dif; - if (!QueryPerformanceFrequency((LARGE_INTEGER *) &freq)) - { - return 0; - } - - // Now we can init the measure process. We set the process and thread priority - // to the highest available level (Realtime priority). Also we focus the - // first processor in the multiprocessor system. - HANDLE hProcess = GetCurrentProcess(); - HANDLE hThread = GetCurrentThread(); - unsigned long dwCurPriorityClass = GetPriorityClass(hProcess); - int iCurThreadPriority = GetThreadPriority(hThread); - DWORD_PTR dwProcessMask, dwSystemMask, dwNewMask = 1; - GetProcessAffinityMask(hProcess, &dwProcessMask, &dwSystemMask); - - SetPriorityClass(hProcess, REALTIME_PRIORITY_CLASS); - SetThreadPriority(hThread, THREAD_PRIORITY_TIME_CRITICAL); - SetProcessAffinityMask(hProcess, dwNewMask); - - //// Now we call a CPUID to ensure, that all other prior called functions are - //// completed now (serialization) - //__asm cpuid - int cpu_info[4] = {-1}; - __cpuid(cpu_info, 0); - - // We ask the high-res timer for the start time - QueryPerformanceCounter((LARGE_INTEGER *) &starttime); - - // Then we get the current cpu clock and store it - start = __rdtsc(); - - // Now we wart for some msecs - _Delay(measure_msecs); - // Sleep(uiMeasureMSecs); - - // We ask for the end time - QueryPerformanceCounter((LARGE_INTEGER *) &endtime); - - // And also for the end cpu clock - end = __rdtsc(); - - // Now we can restore the default process and thread priorities - SetProcessAffinityMask(hProcess, dwProcessMask); - SetThreadPriority(hThread, iCurThreadPriority); - SetPriorityClass(hProcess, dwCurPriorityClass); - - // Then we calculate the time and clock differences - dif = end - start; - timedif = endtime - starttime; - - // And finally the frequency is the clock difference divided by the time - // difference. - F64 frequency = (F64)dif / (((F64)timedif) / freq); - - // At last we just return the frequency that is also stored in the call - // member var uqwFrequency - converted to MHz - return frequency / (F64)1000000; + if(measure_msecs == 0) + { + return 0; + } + + // After that we declare some vars and check the frequency of the high + // resolution timer for the measure process. + // If there"s no high-res timer, we exit. + unsigned __int64 starttime, endtime, timedif, freq, start, end, dif; + if (!QueryPerformanceFrequency((LARGE_INTEGER *) &freq)) + { + return 0; + } + + // Now we can init the measure process. We set the process and thread priority + // to the highest available level (Realtime priority). Also we focus the + // first processor in the multiprocessor system. + HANDLE hProcess = GetCurrentProcess(); + HANDLE hThread = GetCurrentThread(); + unsigned long dwCurPriorityClass = GetPriorityClass(hProcess); + int iCurThreadPriority = GetThreadPriority(hThread); + DWORD_PTR dwProcessMask, dwSystemMask, dwNewMask = 1; + GetProcessAffinityMask(hProcess, &dwProcessMask, &dwSystemMask); + + SetPriorityClass(hProcess, REALTIME_PRIORITY_CLASS); + SetThreadPriority(hThread, THREAD_PRIORITY_TIME_CRITICAL); + SetProcessAffinityMask(hProcess, dwNewMask); + + //// Now we call a CPUID to ensure, that all other prior called functions are + //// completed now (serialization) + //__asm cpuid + int cpu_info[4] = {-1}; + __cpuid(cpu_info, 0); + + // We ask the high-res timer for the start time + QueryPerformanceCounter((LARGE_INTEGER *) &starttime); + + // Then we get the current cpu clock and store it + start = __rdtsc(); + + // Now we wart for some msecs + _Delay(measure_msecs); + // Sleep(uiMeasureMSecs); + + // We ask for the end time + QueryPerformanceCounter((LARGE_INTEGER *) &endtime); + + // And also for the end cpu clock + end = __rdtsc(); + + // Now we can restore the default process and thread priorities + SetProcessAffinityMask(hProcess, dwProcessMask); + SetThreadPriority(hThread, iCurThreadPriority); + SetPriorityClass(hProcess, dwCurPriorityClass); + + // Then we calculate the time and clock differences + dif = end - start; + timedif = endtime - starttime; + + // And finally the frequency is the clock difference divided by the time + // difference. + F64 frequency = (F64)dif / (((F64)timedif) / freq); + + // At last we just return the frequency that is also stored in the call + // member var uqwFrequency - converted to MHz + return frequency / (F64)1000000; } // Windows implementation class LLProcessorInfoWindowsImpl : public LLProcessorInfoImpl { public: - LLProcessorInfoWindowsImpl() - { - getCPUIDInfo(); - setInfo(eFrequency, calculate_cpu_frequency(50)); - } + LLProcessorInfoWindowsImpl() + { + getCPUIDInfo(); + setInfo(eFrequency, calculate_cpu_frequency(50)); + } private: - void getCPUIDInfo() - { - // http://msdn.microsoft.com/en-us/library/hskdteyh(VS.80).aspx - - // __cpuid with an InfoType argument of 0 returns the number of - // valid Ids in cpu_info[0] and the CPU identification string in - // the other three array elements. The CPU identification string is - // not in linear order. The code below arranges the information - // in a human readable form. - int cpu_info[4] = {-1}; - __cpuid(cpu_info, 0); - unsigned int ids = (unsigned int)cpu_info[0]; - setConfig(eMaxID, (S32)ids); - - char cpu_vendor[0x20]; - memset(cpu_vendor, 0, sizeof(cpu_vendor)); - *((int*)cpu_vendor) = cpu_info[1]; - *((int*)(cpu_vendor+4)) = cpu_info[3]; - *((int*)(cpu_vendor+8)) = cpu_info[2]; - setInfo(eVendor, cpu_vendor); + void getCPUIDInfo() + { + // http://msdn.microsoft.com/en-us/library/hskdteyh(VS.80).aspx + + // __cpuid with an InfoType argument of 0 returns the number of + // valid Ids in cpu_info[0] and the CPU identification string in + // the other three array elements. The CPU identification string is + // not in linear order. The code below arranges the information + // in a human readable form. + int cpu_info[4] = {-1}; + __cpuid(cpu_info, 0); + unsigned int ids = (unsigned int)cpu_info[0]; + setConfig(eMaxID, (S32)ids); + + char cpu_vendor[0x20]; + memset(cpu_vendor, 0, sizeof(cpu_vendor)); + *((int*)cpu_vendor) = cpu_info[1]; + *((int*)(cpu_vendor+4)) = cpu_info[3]; + *((int*)(cpu_vendor+8)) = cpu_info[2]; + setInfo(eVendor, cpu_vendor); std::string cmp_vendor(cpu_vendor); bool is_amd = false; if (cmp_vendor == "AuthenticAMD") @@ -513,49 +513,49 @@ private: is_amd = true; } - // Get the information associated with each valid Id - for(unsigned int i=0; i<=ids; ++i) - { - __cpuid(cpu_info, i); - - // Interpret CPU feature information. - if (i == 1) - { - setInfo(eStepping, cpu_info[0] & 0xf); - setInfo(eModel, (cpu_info[0] >> 4) & 0xf); - int family = (cpu_info[0] >> 8) & 0xf; - setInfo(eFamily, family); - setInfo(eType, (cpu_info[0] >> 12) & 0x3); - setInfo(eExtendedModel, (cpu_info[0] >> 16) & 0xf); - int ext_family = (cpu_info[0] >> 20) & 0xff; - setInfo(eExtendedFamily, ext_family); - setInfo(eBrandID, cpu_info[1] & 0xff); - - setInfo(eFamilyName, compute_CPUFamilyName(cpu_vendor, family, ext_family)); - - setConfig(eCLFLUSHCacheLineSize, ((cpu_info[1] >> 8) & 0xff) * 8); - setConfig(eAPICPhysicalID, (cpu_info[1] >> 24) & 0xff); - - if(cpu_info[2] & 0x1) - { - setExtension(cpu_feature_names[eSSE3_Features]); - } - - if(cpu_info[2] & 0x8) - { + // Get the information associated with each valid Id + for(unsigned int i=0; i<=ids; ++i) + { + __cpuid(cpu_info, i); + + // Interpret CPU feature information. + if (i == 1) + { + setInfo(eStepping, cpu_info[0] & 0xf); + setInfo(eModel, (cpu_info[0] >> 4) & 0xf); + int family = (cpu_info[0] >> 8) & 0xf; + setInfo(eFamily, family); + setInfo(eType, (cpu_info[0] >> 12) & 0x3); + setInfo(eExtendedModel, (cpu_info[0] >> 16) & 0xf); + int ext_family = (cpu_info[0] >> 20) & 0xff; + setInfo(eExtendedFamily, ext_family); + setInfo(eBrandID, cpu_info[1] & 0xff); + + setInfo(eFamilyName, compute_CPUFamilyName(cpu_vendor, family, ext_family)); + + setConfig(eCLFLUSHCacheLineSize, ((cpu_info[1] >> 8) & 0xff) * 8); + setConfig(eAPICPhysicalID, (cpu_info[1] >> 24) & 0xff); + + if(cpu_info[2] & 0x1) + { + setExtension(cpu_feature_names[eSSE3_Features]); + } + + if(cpu_info[2] & 0x8) + { // intel specific SSE3 suplements - setExtension(cpu_feature_names[eMONTIOR_MWAIT]); - } - - if(cpu_info[2] & 0x10) - { - setExtension(cpu_feature_names[eCPLDebugStore]); - } - - if(cpu_info[2] & 0x100) - { - setExtension(cpu_feature_names[eThermalMonitor2]); - } + setExtension(cpu_feature_names[eMONTIOR_MWAIT]); + } + + if(cpu_info[2] & 0x10) + { + setExtension(cpu_feature_names[eCPLDebugStore]); + } + + if(cpu_info[2] & 0x100) + { + setExtension(cpu_feature_names[eThermalMonitor2]); + } if (cpu_info[2] & 0x200) { @@ -572,32 +572,32 @@ private: setExtension(cpu_feature_names[eSSE4_2_Features]); } - unsigned int feature_info = (unsigned int) cpu_info[3]; - for(unsigned int index = 0, bit = 1; index < eSSE3_Features; ++index, bit <<= 1) - { - if(feature_info & bit) - { - setExtension(cpu_feature_names[index]); - } - } - } - } - - // Calling __cpuid with 0x80000000 as the InfoType argument - // gets the number of valid extended IDs. - __cpuid(cpu_info, 0x80000000); - unsigned int ext_ids = cpu_info[0]; - setConfig(eMaxExtID, 0); - - char cpu_brand_string[0x40]; - memset(cpu_brand_string, 0, sizeof(cpu_brand_string)); - - // Get the information associated with each extended ID. - for(unsigned int i=0x80000000; i<=ext_ids; ++i) - { - __cpuid(cpu_info, i); - - // Interpret CPU brand string and cache information. + unsigned int feature_info = (unsigned int) cpu_info[3]; + for(unsigned int index = 0, bit = 1; index < eSSE3_Features; ++index, bit <<= 1) + { + if(feature_info & bit) + { + setExtension(cpu_feature_names[index]); + } + } + } + } + + // Calling __cpuid with 0x80000000 as the InfoType argument + // gets the number of valid extended IDs. + __cpuid(cpu_info, 0x80000000); + unsigned int ext_ids = cpu_info[0]; + setConfig(eMaxExtID, 0); + + char cpu_brand_string[0x40]; + memset(cpu_brand_string, 0, sizeof(cpu_brand_string)); + + // Get the information associated with each extended ID. + for(unsigned int i=0x80000000; i<=ext_ids; ++i) + { + __cpuid(cpu_info, i); + + // Interpret CPU brand string and cache information. if (i == 0x80000001) { if (is_amd) @@ -609,21 +609,21 @@ private: { memcpy(cpu_brand_string, cpu_info, sizeof(cpu_info)); } - else if (i == 0x80000003) - memcpy(cpu_brand_string + 16, cpu_info, sizeof(cpu_info)); - else if (i == 0x80000004) - { - memcpy(cpu_brand_string + 32, cpu_info, sizeof(cpu_info)); - setInfo(eBrandName, cpu_brand_string); - } - else if (i == 0x80000006) - { - setConfig(eCacheLineSize, cpu_info[2] & 0xff); - setConfig(eL2Associativity, (cpu_info[2] >> 12) & 0xf); - setConfig(eCacheSizeK, (cpu_info[2] >> 16) & 0xffff); - } - } - } + else if (i == 0x80000003) + memcpy(cpu_brand_string + 16, cpu_info, sizeof(cpu_info)); + else if (i == 0x80000004) + { + memcpy(cpu_brand_string + 32, cpu_info, sizeof(cpu_info)); + setInfo(eBrandName, cpu_brand_string); + } + else if (i == 0x80000006) + { + setConfig(eCacheLineSize, cpu_info[2] & 0xff); + setConfig(eL2Associativity, (cpu_info[2] >> 12) & 0xf); + setConfig(eCacheSizeK, (cpu_info[2] >> 16) & 0xffff); + } + } + } }; #elif LL_DARWIN @@ -634,126 +634,126 @@ private: class LLProcessorInfoDarwinImpl : public LLProcessorInfoImpl { public: - LLProcessorInfoDarwinImpl() - { - getCPUIDInfo(); - uint64_t frequency = getSysctlInt64("hw.cpufrequency"); - setInfo(eFrequency, (F64)frequency / (F64)1000000); - } + LLProcessorInfoDarwinImpl() + { + getCPUIDInfo(); + uint64_t frequency = getSysctlInt64("hw.cpufrequency"); + setInfo(eFrequency, (F64)frequency / (F64)1000000); + } - virtual ~LLProcessorInfoDarwinImpl() {} + virtual ~LLProcessorInfoDarwinImpl() {} private: - int getSysctlInt(const char* name) - { - int result = 0; - size_t len = sizeof(int); - int error = sysctlbyname(name, (void*)&result, &len, NULL, 0); - return error == -1 ? 0 : result; - } - - uint64_t getSysctlInt64(const char* name) - { - uint64_t value = 0; - size_t size = sizeof(value); - int result = sysctlbyname(name, (void*)&value, &size, NULL, 0); - if ( result == 0 ) - { - if ( size == sizeof( uint64_t ) ) - ; - else if ( size == sizeof( uint32_t ) ) - value = (uint64_t)(( uint32_t *)&value); - else if ( size == sizeof( uint16_t ) ) - value = (uint64_t)(( uint16_t *)&value); - else if ( size == sizeof( uint8_t ) ) - value = (uint64_t)(( uint8_t *)&value); - else - { - LL_WARNS() << "Unknown type returned from sysctl" << LL_ENDL; - } - } - - return result == -1 ? 0 : value; - } - - void getCPUIDInfo() - { - size_t len = 0; - - char cpu_brand_string[0x40]; - len = sizeof(cpu_brand_string); - memset(cpu_brand_string, 0, len); - sysctlbyname("machdep.cpu.brand_string", (void*)cpu_brand_string, &len, NULL, 0); - cpu_brand_string[0x3f] = 0; - setInfo(eBrandName, cpu_brand_string); - - char cpu_vendor[0x20]; - len = sizeof(cpu_vendor); - memset(cpu_vendor, 0, len); - sysctlbyname("machdep.cpu.vendor", (void*)cpu_vendor, &len, NULL, 0); - cpu_vendor[0x1f] = 0; - setInfo(eVendor, cpu_vendor); - - setInfo(eStepping, getSysctlInt("machdep.cpu.stepping")); - setInfo(eModel, getSysctlInt("machdep.cpu.model")); - int family = getSysctlInt("machdep.cpu.family"); - int ext_family = getSysctlInt("machdep.cpu.extfamily"); - setInfo(eFamily, family); - setInfo(eExtendedFamily, ext_family); - setInfo(eFamilyName, compute_CPUFamilyName(cpu_vendor, family, ext_family)); - setInfo(eExtendedModel, getSysctlInt("machdep.cpu.extmodel")); - setInfo(eBrandID, getSysctlInt("machdep.cpu.brand")); - setInfo(eType, 0); // ? where to find this? - - //setConfig(eCLFLUSHCacheLineSize, ((cpu_info[1] >> 8) & 0xff) * 8); - //setConfig(eAPICPhysicalID, (cpu_info[1] >> 24) & 0xff); - setConfig(eCacheLineSize, getSysctlInt("machdep.cpu.cache.linesize")); - setConfig(eL2Associativity, getSysctlInt("machdep.cpu.cache.L2_associativity")); - setConfig(eCacheSizeK, getSysctlInt("machdep.cpu.cache.size")); - - uint64_t feature_info = getSysctlInt64("machdep.cpu.feature_bits"); - S32 *feature_infos = (S32*)(&feature_info); - - setConfig(eFeatureBits, feature_infos[0]); - - for(unsigned int index = 0, bit = 1; index < eSSE3_Features; ++index, bit <<= 1) - { - if(feature_info & bit) - { - setExtension(cpu_feature_names[index]); - } - } - - // *NOTE:Mani - I didn't find any docs that assure me that machdep.cpu.feature_bits will always be - // The feature bits I think it is. Here's a test: + int getSysctlInt(const char* name) + { + int result = 0; + size_t len = sizeof(int); + int error = sysctlbyname(name, (void*)&result, &len, NULL, 0); + return error == -1 ? 0 : result; + } + + uint64_t getSysctlInt64(const char* name) + { + uint64_t value = 0; + size_t size = sizeof(value); + int result = sysctlbyname(name, (void*)&value, &size, NULL, 0); + if ( result == 0 ) + { + if ( size == sizeof( uint64_t ) ) + ; + else if ( size == sizeof( uint32_t ) ) + value = (uint64_t)(( uint32_t *)&value); + else if ( size == sizeof( uint16_t ) ) + value = (uint64_t)(( uint16_t *)&value); + else if ( size == sizeof( uint8_t ) ) + value = (uint64_t)(( uint8_t *)&value); + else + { + LL_WARNS() << "Unknown type returned from sysctl" << LL_ENDL; + } + } + + return result == -1 ? 0 : value; + } + + void getCPUIDInfo() + { + size_t len = 0; + + char cpu_brand_string[0x40]; + len = sizeof(cpu_brand_string); + memset(cpu_brand_string, 0, len); + sysctlbyname("machdep.cpu.brand_string", (void*)cpu_brand_string, &len, NULL, 0); + cpu_brand_string[0x3f] = 0; + setInfo(eBrandName, cpu_brand_string); + + char cpu_vendor[0x20]; + len = sizeof(cpu_vendor); + memset(cpu_vendor, 0, len); + sysctlbyname("machdep.cpu.vendor", (void*)cpu_vendor, &len, NULL, 0); + cpu_vendor[0x1f] = 0; + setInfo(eVendor, cpu_vendor); + + setInfo(eStepping, getSysctlInt("machdep.cpu.stepping")); + setInfo(eModel, getSysctlInt("machdep.cpu.model")); + int family = getSysctlInt("machdep.cpu.family"); + int ext_family = getSysctlInt("machdep.cpu.extfamily"); + setInfo(eFamily, family); + setInfo(eExtendedFamily, ext_family); + setInfo(eFamilyName, compute_CPUFamilyName(cpu_vendor, family, ext_family)); + setInfo(eExtendedModel, getSysctlInt("machdep.cpu.extmodel")); + setInfo(eBrandID, getSysctlInt("machdep.cpu.brand")); + setInfo(eType, 0); // ? where to find this? + + //setConfig(eCLFLUSHCacheLineSize, ((cpu_info[1] >> 8) & 0xff) * 8); + //setConfig(eAPICPhysicalID, (cpu_info[1] >> 24) & 0xff); + setConfig(eCacheLineSize, getSysctlInt("machdep.cpu.cache.linesize")); + setConfig(eL2Associativity, getSysctlInt("machdep.cpu.cache.L2_associativity")); + setConfig(eCacheSizeK, getSysctlInt("machdep.cpu.cache.size")); + + uint64_t feature_info = getSysctlInt64("machdep.cpu.feature_bits"); + S32 *feature_infos = (S32*)(&feature_info); + + setConfig(eFeatureBits, feature_infos[0]); + + for(unsigned int index = 0, bit = 1; index < eSSE3_Features; ++index, bit <<= 1) + { + if(feature_info & bit) + { + setExtension(cpu_feature_names[index]); + } + } + + // *NOTE:Mani - I didn't find any docs that assure me that machdep.cpu.feature_bits will always be + // The feature bits I think it is. Here's a test: #ifndef LL_RELEASE_FOR_DOWNLOAD - #if defined(__i386__) && defined(__PIC__) - /* %ebx may be the PIC register. */ - #define __cpuid(level, a, b, c, d) \ - __asm__ ("xchgl\t%%ebx, %1\n\t" \ - "cpuid\n\t" \ - "xchgl\t%%ebx, %1\n\t" \ - : "=a" (a), "=r" (b), "=c" (c), "=d" (d) \ - : "0" (level)) - #else - #define __cpuid(level, a, b, c, d) \ - __asm__ ("cpuid\n\t" \ - : "=a" (a), "=b" (b), "=c" (c), "=d" (d) \ - : "0" (level)) - #endif - - unsigned int eax, ebx, ecx, edx; - __cpuid(0x1, eax, ebx, ecx, edx); - if(feature_infos[0] != (S32)edx) - { - LL_WARNS() << "machdep.cpu.feature_bits doesn't match expected cpuid result!" << LL_ENDL; - } -#endif // LL_RELEASE_FOR_DOWNLOAD - - - uint64_t ext_feature_info = getSysctlInt64("machdep.cpu.extfeature_bits"); - S32 *ext_feature_infos = (S32*)(&ext_feature_info); - setConfig(eExtFeatureBits, ext_feature_infos[0]); + #if defined(__i386__) && defined(__PIC__) + /* %ebx may be the PIC register. */ + #define __cpuid(level, a, b, c, d) \ + __asm__ ("xchgl\t%%ebx, %1\n\t" \ + "cpuid\n\t" \ + "xchgl\t%%ebx, %1\n\t" \ + : "=a" (a), "=r" (b), "=c" (c), "=d" (d) \ + : "0" (level)) + #else + #define __cpuid(level, a, b, c, d) \ + __asm__ ("cpuid\n\t" \ + : "=a" (a), "=b" (b), "=c" (c), "=d" (d) \ + : "0" (level)) + #endif + + unsigned int eax, ebx, ecx, edx; + __cpuid(0x1, eax, ebx, ecx, edx); + if(feature_infos[0] != (S32)edx) + { + LL_WARNS() << "machdep.cpu.feature_bits doesn't match expected cpuid result!" << LL_ENDL; + } +#endif // LL_RELEASE_FOR_DOWNLOAD + + + uint64_t ext_feature_info = getSysctlInt64("machdep.cpu.extfeature_bits"); + S32 *ext_feature_infos = (S32*)(&ext_feature_info); + setConfig(eExtFeatureBits, ext_feature_infos[0]); char cpu_features[1024]; @@ -789,7 +789,7 @@ private: // Not supposed to happen? setExtension(cpu_feature_names[eSSE4a_Features]); } - } + } }; #elif LL_LINUX @@ -798,107 +798,107 @@ const char CPUINFO_FILE[] = "/proc/cpuinfo"; class LLProcessorInfoLinuxImpl : public LLProcessorInfoImpl { public: - LLProcessorInfoLinuxImpl() - { - get_proc_cpuinfo(); - } + LLProcessorInfoLinuxImpl() + { + get_proc_cpuinfo(); + } - virtual ~LLProcessorInfoLinuxImpl() {} + virtual ~LLProcessorInfoLinuxImpl() {} private: - void get_proc_cpuinfo() - { - std::map< std::string, std::string > cpuinfo; - LLFILE* cpuinfo_fp = LLFile::fopen(CPUINFO_FILE, "rb"); - if(cpuinfo_fp) - { - char line[MAX_STRING]; - memset(line, 0, MAX_STRING); - while(fgets(line, MAX_STRING, cpuinfo_fp)) - { - // /proc/cpuinfo on Linux looks like: - // name\t*: value\n - char* tabspot = strchr( line, '\t' ); - if (tabspot == NULL) - continue; - char* colspot = strchr( tabspot, ':' ); - if (colspot == NULL) - continue; - char* spacespot = strchr( colspot, ' ' ); - if (spacespot == NULL) - continue; - char* nlspot = strchr( line, '\n' ); - if (nlspot == NULL) - nlspot = line + strlen( line ); // Fallback to terminating NUL - std::string linename( line, tabspot ); - std::string llinename(linename); - LLStringUtil::toLower(llinename); - std::string lineval( spacespot + 1, nlspot ); - cpuinfo[ llinename ] = lineval; - } - fclose(cpuinfo_fp); - } + void get_proc_cpuinfo() + { + std::map< std::string, std::string > cpuinfo; + LLFILE* cpuinfo_fp = LLFile::fopen(CPUINFO_FILE, "rb"); + if(cpuinfo_fp) + { + char line[MAX_STRING]; + memset(line, 0, MAX_STRING); + while(fgets(line, MAX_STRING, cpuinfo_fp)) + { + // /proc/cpuinfo on Linux looks like: + // name\t*: value\n + char* tabspot = strchr( line, '\t' ); + if (tabspot == NULL) + continue; + char* colspot = strchr( tabspot, ':' ); + if (colspot == NULL) + continue; + char* spacespot = strchr( colspot, ' ' ); + if (spacespot == NULL) + continue; + char* nlspot = strchr( line, '\n' ); + if (nlspot == NULL) + nlspot = line + strlen( line ); // Fallback to terminating NUL + std::string linename( line, tabspot ); + std::string llinename(linename); + LLStringUtil::toLower(llinename); + std::string lineval( spacespot + 1, nlspot ); + cpuinfo[ llinename ] = lineval; + } + fclose(cpuinfo_fp); + } # if LL_X86 // *NOTE:Mani - eww, macros! srry. #define LLPI_SET_INFO_STRING(llpi_id, cpuinfo_id) \ - if (!cpuinfo[cpuinfo_id].empty()) \ - { setInfo(llpi_id, cpuinfo[cpuinfo_id]);} + if (!cpuinfo[cpuinfo_id].empty()) \ + { setInfo(llpi_id, cpuinfo[cpuinfo_id]);} #define LLPI_SET_INFO_INT(llpi_id, cpuinfo_id) \ - {\ - S32 result; \ - if (!cpuinfo[cpuinfo_id].empty() \ - && LLStringUtil::convertToS32(cpuinfo[cpuinfo_id], result)) \ - { setInfo(llpi_id, result);} \ - } - - F64 mhz; - if (LLStringUtil::convertToF64(cpuinfo["cpu mhz"], mhz) - && 200.0 < mhz && mhz < 10000.0) - { - setInfo(eFrequency,(F64)(mhz)); - } - - LLPI_SET_INFO_STRING(eBrandName, "model name"); - LLPI_SET_INFO_STRING(eVendor, "vendor_id"); - - LLPI_SET_INFO_INT(eStepping, "stepping"); - LLPI_SET_INFO_INT(eModel, "model"); - - - S32 family; - if (!cpuinfo["cpu family"].empty() - && LLStringUtil::convertToS32(cpuinfo["cpu family"], family)) - { - setInfo(eFamily, family); - } - - setInfo(eFamilyName, compute_CPUFamilyName(cpuinfo["vendor_id"].c_str(), family, 0)); - - // setInfo(eExtendedModel, getSysctlInt("machdep.cpu.extmodel")); - // setInfo(eBrandID, getSysctlInt("machdep.cpu.brand")); - // setInfo(eType, 0); // ? where to find this? - - //setConfig(eCLFLUSHCacheLineSize, ((cpu_info[1] >> 8) & 0xff) * 8); - //setConfig(eAPICPhysicalID, (cpu_info[1] >> 24) & 0xff); - //setConfig(eCacheLineSize, getSysctlInt("machdep.cpu.cache.linesize")); - //setConfig(eL2Associativity, getSysctlInt("machdep.cpu.cache.L2_associativity")); - //setConfig(eCacheSizeK, getSysctlInt("machdep.cpu.cache.size")); - - // Read extensions - std::string flags = " " + cpuinfo["flags"] + " "; - LLStringUtil::toLower(flags); - - if( flags.find( " sse " ) != std::string::npos ) - { - setExtension(cpu_feature_names[eSSE_Ext]); - } - - if( flags.find( " sse2 " ) != std::string::npos ) - { - setExtension(cpu_feature_names[eSSE2_Ext]); - } + {\ + S32 result; \ + if (!cpuinfo[cpuinfo_id].empty() \ + && LLStringUtil::convertToS32(cpuinfo[cpuinfo_id], result)) \ + { setInfo(llpi_id, result);} \ + } + + F64 mhz; + if (LLStringUtil::convertToF64(cpuinfo["cpu mhz"], mhz) + && 200.0 < mhz && mhz < 10000.0) + { + setInfo(eFrequency,(F64)(mhz)); + } + + LLPI_SET_INFO_STRING(eBrandName, "model name"); + LLPI_SET_INFO_STRING(eVendor, "vendor_id"); + + LLPI_SET_INFO_INT(eStepping, "stepping"); + LLPI_SET_INFO_INT(eModel, "model"); + + + S32 family; + if (!cpuinfo["cpu family"].empty() + && LLStringUtil::convertToS32(cpuinfo["cpu family"], family)) + { + setInfo(eFamily, family); + } + + setInfo(eFamilyName, compute_CPUFamilyName(cpuinfo["vendor_id"].c_str(), family, 0)); + + // setInfo(eExtendedModel, getSysctlInt("machdep.cpu.extmodel")); + // setInfo(eBrandID, getSysctlInt("machdep.cpu.brand")); + // setInfo(eType, 0); // ? where to find this? + + //setConfig(eCLFLUSHCacheLineSize, ((cpu_info[1] >> 8) & 0xff) * 8); + //setConfig(eAPICPhysicalID, (cpu_info[1] >> 24) & 0xff); + //setConfig(eCacheLineSize, getSysctlInt("machdep.cpu.cache.linesize")); + //setConfig(eL2Associativity, getSysctlInt("machdep.cpu.cache.L2_associativity")); + //setConfig(eCacheSizeK, getSysctlInt("machdep.cpu.cache.size")); + + // Read extensions + std::string flags = " " + cpuinfo["flags"] + " "; + LLStringUtil::toLower(flags); + + if( flags.find( " sse " ) != std::string::npos ) + { + setExtension(cpu_feature_names[eSSE_Ext]); + } + + if( flags.find( " sse2 " ) != std::string::npos ) + { + setExtension(cpu_feature_names[eSSE2_Ext]); + } if (flags.find(" pni ") != std::string::npos) { @@ -924,36 +924,36 @@ private: { setExtension(cpu_feature_names[eSSE4a_Features]); } - + # endif // LL_X86 - } - - std::string getCPUFeatureDescription() const - { - std::ostringstream s; - - // *NOTE:Mani - This is for linux only. - LLFILE* cpuinfo = LLFile::fopen(CPUINFO_FILE, "rb"); - if(cpuinfo) - { - char line[MAX_STRING]; - memset(line, 0, MAX_STRING); - while(fgets(line, MAX_STRING, cpuinfo)) - { - line[strlen(line)-1] = ' '; - s << line; - s << std::endl; - } - fclose(cpuinfo); - s << std::endl; - } - else - { - s << "Unable to collect processor information" << std::endl; - } - return s.str(); - } - + } + + std::string getCPUFeatureDescription() const + { + std::ostringstream s; + + // *NOTE:Mani - This is for linux only. + LLFILE* cpuinfo = LLFile::fopen(CPUINFO_FILE, "rb"); + if(cpuinfo) + { + char line[MAX_STRING]; + memset(line, 0, MAX_STRING); + while(fgets(line, MAX_STRING, cpuinfo)) + { + line[strlen(line)-1] = ' '; + s << line; + s << std::endl; + } + fclose(cpuinfo); + s << std::endl; + } + else + { + s << "Unable to collect processor information" << std::endl; + } + return s.str(); + } + }; @@ -963,20 +963,20 @@ private: // Interface definition LLProcessorInfo::LLProcessorInfo() : mImpl(NULL) { - // *NOTE:Mani - not thread safe. - if(!mImpl) - { + // *NOTE:Mani - not thread safe. + if(!mImpl) + { #ifdef LL_MSVC - static LLProcessorInfoWindowsImpl the_impl; - mImpl = &the_impl; + static LLProcessorInfoWindowsImpl the_impl; + mImpl = &the_impl; #elif LL_DARWIN - static LLProcessorInfoDarwinImpl the_impl; - mImpl = &the_impl; + static LLProcessorInfoDarwinImpl the_impl; + mImpl = &the_impl; #else - static LLProcessorInfoLinuxImpl the_impl; - mImpl = &the_impl; + static LLProcessorInfoLinuxImpl the_impl; + mImpl = &the_impl; #endif // LL_MSVC - } + } } diff --git a/indra/llcommon/llprocessor.h b/indra/llcommon/llprocessor.h index 1a473ddc97..f8ccf686c8 100644 --- a/indra/llcommon/llprocessor.h +++ b/indra/llcommon/llprocessor.h @@ -1,25 +1,25 @@ -/** +/** * @file llprocessor.h * @brief Code to figure out the processor. Originally by Benjamin Jurke. * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -48,23 +48,23 @@ class LLProcessorInfoImpl; class LL_COMMON_API LLProcessorInfo { public: - LLProcessorInfo(); - ~LLProcessorInfo(); + LLProcessorInfo(); + ~LLProcessorInfo(); - F64MegahertzImplicit getCPUFrequency() const; - bool hasSSE() const; - bool hasSSE2() const; + F64MegahertzImplicit getCPUFrequency() const; + bool hasSSE() const; + bool hasSSE2() const; bool hasSSE3() const; bool hasSSE3S() const; bool hasSSE41() const; bool hasSSE42() const; bool hasSSE4a() const; - bool hasAltivec() const; - std::string getCPUFamilyName() const; - std::string getCPUBrandName() const; - std::string getCPUFeatureDescription() const; + bool hasAltivec() const; + std::string getCPUFamilyName() const; + std::string getCPUBrandName() const; + std::string getCPUFeatureDescription() const; private: - LLProcessorInfoImpl* mImpl; + LLProcessorInfoImpl* mImpl; }; #endif // LLPROCESSOR_H diff --git a/indra/llcommon/llprocinfo.cpp b/indra/llcommon/llprocinfo.cpp index c00f979b0b..69be00e14a 100644 --- a/indra/llcommon/llprocinfo.cpp +++ b/indra/llcommon/llprocinfo.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llprocinfo.cpp * @brief Process, cpu and resource usage information APIs. * @author monty@lindenlab.com @@ -30,7 +30,7 @@ #if LL_WINDOWS -#define PSAPI_VERSION 1 +#define PSAPI_VERSION 1 #include "windows.h" #include "psapi.h" @@ -38,7 +38,7 @@ #include #include - + #else #include @@ -52,42 +52,42 @@ void LLProcInfo::getCPUUsage(time_type & user_time, time_type & system_time) { #if LL_WINDOWS - HANDLE self(GetCurrentProcess()); // Does not have to be closed - FILETIME ft_dummy, ft_system, ft_user; - - GetProcessTimes(self, &ft_dummy, &ft_dummy, &ft_system, &ft_user); - ULARGE_INTEGER uli; - uli.u.LowPart = ft_system.dwLowDateTime; - uli.u.HighPart = ft_system.dwHighDateTime; - system_time = uli.QuadPart / U64L(10); // Convert to uS - uli.u.LowPart = ft_user.dwLowDateTime; - uli.u.HighPart = ft_user.dwHighDateTime; - user_time = uli.QuadPart / U64L(10); - + HANDLE self(GetCurrentProcess()); // Does not have to be closed + FILETIME ft_dummy, ft_system, ft_user; + + GetProcessTimes(self, &ft_dummy, &ft_dummy, &ft_system, &ft_user); + ULARGE_INTEGER uli; + uli.u.LowPart = ft_system.dwLowDateTime; + uli.u.HighPart = ft_system.dwHighDateTime; + system_time = uli.QuadPart / U64L(10); // Convert to uS + uli.u.LowPart = ft_user.dwLowDateTime; + uli.u.HighPart = ft_user.dwHighDateTime; + user_time = uli.QuadPart / U64L(10); + #elif LL_DARWIN - struct rusage usage; + struct rusage usage; - if (getrusage(RUSAGE_SELF, &usage)) - { - user_time = system_time = time_type(0U); - return; - } - user_time = U64(usage.ru_utime.tv_sec) * U64L(1000000) + usage.ru_utime.tv_usec; - system_time = U64(usage.ru_stime.tv_sec) * U64L(1000000) + usage.ru_stime.tv_usec; + if (getrusage(RUSAGE_SELF, &usage)) + { + user_time = system_time = time_type(0U); + return; + } + user_time = U64(usage.ru_utime.tv_sec) * U64L(1000000) + usage.ru_utime.tv_usec; + system_time = U64(usage.ru_stime.tv_sec) * U64L(1000000) + usage.ru_stime.tv_usec; #else // Linux - struct rusage usage; + struct rusage usage; + + if (getrusage(RUSAGE_SELF, &usage)) + { + user_time = system_time = time_type(0U); + return; + } + user_time = U64(usage.ru_utime.tv_sec) * U64L(1000000) + usage.ru_utime.tv_usec; + system_time = U64(usage.ru_stime.tv_sec) * U64L(1000000) + usage.ru_stime.tv_usec; - if (getrusage(RUSAGE_SELF, &usage)) - { - user_time = system_time = time_type(0U); - return; - } - user_time = U64(usage.ru_utime.tv_sec) * U64L(1000000) + usage.ru_utime.tv_usec; - system_time = U64(usage.ru_stime.tv_sec) * U64L(1000000) + usage.ru_stime.tv_usec; - #endif // LL_WINDOWS/LL_DARWIN/Linux } diff --git a/indra/llcommon/llprocinfo.h b/indra/llcommon/llprocinfo.h index e78bcf490a..5955799812 100644 --- a/indra/llcommon/llprocinfo.h +++ b/indra/llcommon/llprocinfo.h @@ -1,4 +1,4 @@ -/** +/** * @file llprocinfo.h * @brief Interface to process/cpu/resource information services. * @author monty@lindenlab.com @@ -25,8 +25,8 @@ * $/LicenseInfo$ */ -#ifndef LL_PROCINFO_H -#define LL_PROCINFO_H +#ifndef LL_PROCINFO_H +#define LL_PROCINFO_H #include "linden_common.h" @@ -46,23 +46,23 @@ class LL_COMMON_API LLProcInfo { public: - /// Public types + /// Public types + + typedef U64 time_type; /// Relative microseconds - typedef U64 time_type; /// Relative microseconds - private: - LLProcInfo(); // Not defined - ~LLProcInfo(); // Not defined - LLProcInfo(const LLProcInfo &); // Not defined - void operator=(const LLProcInfo &); // Not defined + LLProcInfo(); // Not defined + ~LLProcInfo(); // Not defined + LLProcInfo(const LLProcInfo &); // Not defined + void operator=(const LLProcInfo &); // Not defined public: - /// Get accumulated system and user CPU time in - /// microseconds. Syscalls involved in every invocation. - /// - /// Threading: expected to be safe. - static void getCPUUsage(time_type & user_time, time_type & system_time); + /// Get accumulated system and user CPU time in + /// microseconds. Syscalls involved in every invocation. + /// + /// Threading: expected to be safe. + static void getCPUUsage(time_type & user_time, time_type & system_time); }; - -#endif // LL_PROCINFO_H + +#endif // LL_PROCINFO_H diff --git a/indra/llcommon/llptrto.cpp b/indra/llcommon/llptrto.cpp index b270291bd6..c4528a47a7 100644 --- a/indra/llcommon/llptrto.cpp +++ b/indra/llcommon/llptrto.cpp @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2008-08-20 * @brief Test for llptrto.h - * + * * $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$ */ diff --git a/indra/llcommon/llptrto.h b/indra/llcommon/llptrto.h index 9ef279fdbf..b57a1ee7f4 100644 --- a/indra/llcommon/llptrto.h +++ b/indra/llcommon/llptrto.h @@ -5,25 +5,25 @@ * @brief LLPtrTo is a template helper to pick either TARGET* or -- when * TARGET is a subclass of LLRefCount or LLThreadSafeRefCount -- * LLPointer. LLPtrTo<> chooses whichever pointer type is best. - * + * * $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$ */ diff --git a/indra/llcommon/llqueuedthread.cpp b/indra/llcommon/llqueuedthread.cpp index 394212ee0d..aaf13ac796 100644 --- a/indra/llcommon/llqueuedthread.cpp +++ b/indra/llcommon/llqueuedthread.cpp @@ -1,24 +1,24 @@ -/** +/** * @file llqueuedthread.cpp * * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -29,7 +29,7 @@ #include #include "llstl.h" -#include "lltimer.h" // ms_sleep() +#include "lltimer.h" // ms_sleep() #include "llmutex.h" //============================================================================ @@ -46,75 +46,75 @@ LLQueuedThread::LLQueuedThread(const std::string& name, bool threaded, bool shou llassert(threaded); // not threaded implementation is deprecated mMainQueue = LL::WorkQueue::getInstance("mainloop"); - if (mThreaded) - { - if(should_pause) - { - pause() ; //call this before start the thread. - } + if (mThreaded) + { + if(should_pause) + { + pause() ; //call this before start the thread. + } - start(); - } + start(); + } } // MAIN THREAD LLQueuedThread::~LLQueuedThread() { - if (!mThreaded) - { - endThread(); - } - shutdown(); - // ~LLThread() will be called here + if (!mThreaded) + { + endThread(); + } + shutdown(); + // ~LLThread() will be called here } void LLQueuedThread::shutdown() { - setQuitting(); + setQuitting(); - unpause(); // MAIN THREAD - if (mThreaded) - { + unpause(); // MAIN THREAD + if (mThreaded) + { if (mRequestQueue.size() == 0) { mRequestQueue.close(); } - S32 timeout = 100; - for ( ; timeout>0; timeout--) - { - if (isStopped()) - { - break; - } - ms_sleep(100); - LLThread::yield(); - } - if (timeout == 0) - { - LL_WARNS() << "~LLQueuedThread (" << mName << ") timed out!" << LL_ENDL; - } - } - else - { - mStatus = STOPPED; - } - - QueuedRequest* req; - S32 active_count = 0; - while ( (req = (QueuedRequest*)mRequestHash.pop_element()) ) - { - if (req->getStatus() == STATUS_QUEUED || req->getStatus() == STATUS_INPROGRESS) - { - ++active_count; - req->setStatus(STATUS_ABORTED); // avoid assert in deleteRequest - } - req->deleteRequest(); - } - if (active_count) - { - LL_WARNS() << "~LLQueuedThread() called with active requests: " << active_count << LL_ENDL; - } + S32 timeout = 100; + for ( ; timeout>0; timeout--) + { + if (isStopped()) + { + break; + } + ms_sleep(100); + LLThread::yield(); + } + if (timeout == 0) + { + LL_WARNS() << "~LLQueuedThread (" << mName << ") timed out!" << LL_ENDL; + } + } + else + { + mStatus = STOPPED; + } + + QueuedRequest* req; + S32 active_count = 0; + while ( (req = (QueuedRequest*)mRequestHash.pop_element()) ) + { + if (req->getStatus() == STATUS_QUEUED || req->getStatus() == STATUS_INPROGRESS) + { + ++active_count; + req->setStatus(STATUS_ABORTED); // avoid assert in deleteRequest + } + req->deleteRequest(); + } + if (active_count) + { + LL_WARNS() << "~LLQueuedThread() called with active requests: " << active_count << LL_ENDL; + } mRequestQueue.close(); } @@ -126,23 +126,23 @@ void LLQueuedThread::shutdown() size_t LLQueuedThread::update(F32 max_time_ms) { LL_PROFILE_ZONE_SCOPED; - if (!mStarted) - { - if (!mThreaded) - { - startThread(); - mStarted = TRUE; - } - } - return updateQueue(max_time_ms); + if (!mStarted) + { + if (!mThreaded) + { + startThread(); + mStarted = TRUE; + } + } + return updateQueue(max_time_ms); } size_t LLQueuedThread::updateQueue(F32 max_time_ms) { LL_PROFILE_ZONE_SCOPED; - // Frame Update - if (mThreaded) - { + // Frame Update + if (mThreaded) + { // schedule a call to threadedUpdate for every call to updateQueue if (!isQuitting()) { @@ -156,29 +156,29 @@ size_t LLQueuedThread::updateQueue(F32 max_time_ms) ); } - if(getPending() > 0) - { - unpause(); - } - } - else - { + if(getPending() > 0) + { + unpause(); + } + } + else + { mRequestQueue.runFor(std::chrono::microseconds((int) (max_time_ms*1000.f))); threadedUpdate(); - } - return getPending(); + } + return getPending(); } void LLQueuedThread::incQueue() { - // Something has been added to the queue - if (!isPaused()) - { - if (mThreaded) - { - wake(); // Wake the thread up if necessary. - } - } + // Something has been added to the queue + if (!isPaused()) + { + if (mThreaded) + { + wake(); // Wake the thread up if necessary. + } + } } //virtual @@ -191,200 +191,200 @@ size_t LLQueuedThread::getPending() // MAIN thread void LLQueuedThread::waitOnPending() { - while(1) - { - update(0); - - if (mIdleThread) - { - break; - } - if (mThreaded) - { - yield(); - } - } - return; + while(1) + { + update(0); + + if (mIdleThread) + { + break; + } + if (mThreaded) + { + yield(); + } + } + return; } // MAIN thread void LLQueuedThread::printQueueStats() { U32 size = mRequestQueue.size(); - if (size > 0) - { - LL_INFOS() << llformat("Pending Requests:%d ", mRequestQueue.size()) << LL_ENDL; - } - else - { - LL_INFOS() << "Queued Thread Idle" << LL_ENDL; - } + if (size > 0) + { + LL_INFOS() << llformat("Pending Requests:%d ", mRequestQueue.size()) << LL_ENDL; + } + else + { + LL_INFOS() << "Queued Thread Idle" << LL_ENDL; + } } // MAIN thread LLQueuedThread::handle_t LLQueuedThread::generateHandle() { U32 res = ++mNextHandle; - return res; + return res; } // MAIN thread bool LLQueuedThread::addRequest(QueuedRequest* req) { LL_PROFILE_ZONE_SCOPED; - if (mStatus == QUITTING) - { - return false; - } - - lockData(); - req->setStatus(STATUS_QUEUED); + if (mStatus == QUITTING) + { + return false; + } + + lockData(); + req->setStatus(STATUS_QUEUED); mRequestHash.insert(req); #if _DEBUG -// LL_INFOS() << llformat("LLQueuedThread::Added req [%08d]",handle) << LL_ENDL; +// LL_INFOS() << llformat("LLQueuedThread::Added req [%08d]",handle) << LL_ENDL; #endif - unlockData(); + unlockData(); llassert(!mDataLock->isSelfLocked()); mRequestQueue.post([this, req]() { processRequest(req); }); - return true; + return true; } // MAIN thread bool LLQueuedThread::waitForResult(LLQueuedThread::handle_t handle, bool auto_complete) { LL_PROFILE_ZONE_SCOPED; - llassert (handle != nullHandle()); - bool res = false; - bool waspaused = isPaused(); - bool done = false; - while(!done) - { - update(0); // unpauses - lockData(); - QueuedRequest* req = (QueuedRequest*)mRequestHash.find(handle); - if (!req) - { - done = true; // request does not exist - } - else if (req->getStatus() == STATUS_COMPLETE) - { - res = true; - if (auto_complete) - { - mRequestHash.erase(handle); - req->deleteRequest(); -// check(); - } - done = true; - } - unlockData(); - - if (!done && mThreaded) - { - yield(); - } - } - if (waspaused) - { - pause(); - } - return res; + llassert (handle != nullHandle()); + bool res = false; + bool waspaused = isPaused(); + bool done = false; + while(!done) + { + update(0); // unpauses + lockData(); + QueuedRequest* req = (QueuedRequest*)mRequestHash.find(handle); + if (!req) + { + done = true; // request does not exist + } + else if (req->getStatus() == STATUS_COMPLETE) + { + res = true; + if (auto_complete) + { + mRequestHash.erase(handle); + req->deleteRequest(); +// check(); + } + done = true; + } + unlockData(); + + if (!done && mThreaded) + { + yield(); + } + } + if (waspaused) + { + pause(); + } + return res; } // MAIN thread LLQueuedThread::QueuedRequest* LLQueuedThread::getRequest(handle_t handle) { - if (handle == nullHandle()) - { - return 0; - } - lockData(); - QueuedRequest* res = (QueuedRequest*)mRequestHash.find(handle); - unlockData(); - return res; + if (handle == nullHandle()) + { + return 0; + } + lockData(); + QueuedRequest* res = (QueuedRequest*)mRequestHash.find(handle); + unlockData(); + return res; } LLQueuedThread::status_t LLQueuedThread::getRequestStatus(handle_t handle) { - status_t res = STATUS_EXPIRED; - lockData(); - QueuedRequest* req = (QueuedRequest*)mRequestHash.find(handle); - if (req) - { - res = req->getStatus(); - } - unlockData(); - return res; + status_t res = STATUS_EXPIRED; + lockData(); + QueuedRequest* req = (QueuedRequest*)mRequestHash.find(handle); + if (req) + { + res = req->getStatus(); + } + unlockData(); + return res; } void LLQueuedThread::abortRequest(handle_t handle, bool autocomplete) { LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; - lockData(); - QueuedRequest* req = (QueuedRequest*)mRequestHash.find(handle); - if (req) - { - req->setFlags(FLAG_ABORT | (autocomplete ? FLAG_AUTO_COMPLETE : 0)); - } - unlockData(); + lockData(); + QueuedRequest* req = (QueuedRequest*)mRequestHash.find(handle); + if (req) + { + req->setFlags(FLAG_ABORT | (autocomplete ? FLAG_AUTO_COMPLETE : 0)); + } + unlockData(); } // MAIN thread void LLQueuedThread::setFlags(handle_t handle, U32 flags) { - lockData(); - QueuedRequest* req = (QueuedRequest*)mRequestHash.find(handle); - if (req) - { - req->setFlags(flags); - } - unlockData(); + lockData(); + QueuedRequest* req = (QueuedRequest*)mRequestHash.find(handle); + if (req) + { + req->setFlags(flags); + } + unlockData(); } bool LLQueuedThread::completeRequest(handle_t handle) { LL_PROFILE_ZONE_SCOPED; - bool res = false; - lockData(); - QueuedRequest* req = (QueuedRequest*)mRequestHash.find(handle); - if (req) - { - llassert_always(req->getStatus() != STATUS_QUEUED); - llassert_always(req->getStatus() != STATUS_INPROGRESS); + bool res = false; + lockData(); + QueuedRequest* req = (QueuedRequest*)mRequestHash.find(handle); + if (req) + { + llassert_always(req->getStatus() != STATUS_QUEUED); + llassert_always(req->getStatus() != STATUS_INPROGRESS); #if _DEBUG -// LL_INFOS() << llformat("LLQueuedThread::Completed req [%08d]",handle) << LL_ENDL; +// LL_INFOS() << llformat("LLQueuedThread::Completed req [%08d]",handle) << LL_ENDL; #endif - mRequestHash.erase(handle); - req->deleteRequest(); -// check(); - res = true; - } - unlockData(); - return res; + mRequestHash.erase(handle); + req->deleteRequest(); +// check(); + res = true; + } + unlockData(); + return res; } bool LLQueuedThread::check() { #if 0 // not a reliable check once mNextHandle wraps, just for quick and dirty debugging - for (int i=0; i* entry = mRequestHash.get_element_at_index(i); - while (entry) - { - if (entry->getHashKey() > mNextHandle) - { - LL_ERRS() << "Hash Error" << LL_ENDL; - return false; - } - entry = entry->getNextEntry(); - } - } + for (int i=0; i* entry = mRequestHash.get_element_at_index(i); + while (entry) + { + if (entry->getHashKey() > mNextHandle) + { + LL_ERRS() << "Hash Error" << LL_ENDL; + return false; + } + entry = entry->getNextEntry(); + } + } #endif - return true; -} - + return true; +} + //============================================================================ // Runs on its OWN thread @@ -395,22 +395,22 @@ void LLQueuedThread::processRequest(LLQueuedThread::QueuedRequest* req) mIdleThread = FALSE; //threadedUpdate(); - // Get next request from pool - lockData(); - - if ((req->getFlags() & FLAG_ABORT) || (mStatus == QUITTING)) - { + // Get next request from pool + lockData(); + + if ((req->getFlags() & FLAG_ABORT) || (mStatus == QUITTING)) + { LL_PROFILE_ZONE_NAMED_CATEGORY_THREAD("qtpr - abort"); - req->setStatus(STATUS_ABORTED); - req->finishRequest(false); - if (req->getFlags() & FLAG_AUTO_COMPLETE) - { - mRequestHash.erase(req); - req->deleteRequest(); -// check(); - } + req->setStatus(STATUS_ABORTED); + req->finishRequest(false); + if (req->getFlags() & FLAG_AUTO_COMPLETE) + { + mRequestHash.erase(req); + req->deleteRequest(); +// check(); + } unlockData(); - } + } else { llassert_always(req->getStatus() == STATUS_QUEUED); @@ -426,7 +426,7 @@ void LLQueuedThread::processRequest(LLQueuedThread::QueuedRequest* req) // safe to access req. if (req) { - // process request + // process request bool complete = req->processRequest(); if (complete) @@ -439,7 +439,7 @@ void LLQueuedThread::processRequest(LLQueuedThread::QueuedRequest* req) { mRequestHash.erase(req); req->deleteRequest(); - // check(); + // check(); } unlockData(); } @@ -449,7 +449,7 @@ void LLQueuedThread::processRequest(LLQueuedThread::QueuedRequest* req) //put back on queue and try again in 0.1ms lockData(); req->setStatus(STATUS_QUEUED); - + unlockData(); llassert(!mDataLock->isSelfLocked()); @@ -480,8 +480,8 @@ void LLQueuedThread::processRequest(LLQueuedThread::QueuedRequest* req) if (LL::WorkQueue::TimePoint::clock::now() < retry_time) { auto sleep_time = std::chrono::duration_cast(retry_time - LL::WorkQueue::TimePoint::clock::now()); - - if (sleep_time.count() > 0) + + if (sleep_time.count() > 0) { ms_sleep(sleep_time.count()); } @@ -489,7 +489,7 @@ void LLQueuedThread::processRequest(LLQueuedThread::QueuedRequest* req) processRequest(req); }); #endif - + } } } @@ -500,48 +500,48 @@ void LLQueuedThread::processRequest(LLQueuedThread::QueuedRequest* req) // virtual bool LLQueuedThread::runCondition() { - // mRunCondition must be locked here - if (mRequestQueue.size() == 0 && mIdleThread) - return false; - else - return true; + // mRunCondition must be locked here + if (mRequestQueue.size() == 0 && mIdleThread) + return false; + else + return true; } // virtual void LLQueuedThread::run() { - // call checPause() immediately so we don't try to do anything before the class is fully constructed - checkPause(); - startThread(); - mStarted = TRUE; - - - /*while (1) - { + // call checPause() immediately so we don't try to do anything before the class is fully constructed + checkPause(); + startThread(); + mStarted = TRUE; + + + /*while (1) + { LL_PROFILE_ZONE_SCOPED; - // this will block on the condition until runCondition() returns true, the thread is unpaused, or the thread leaves the RUNNING state. - checkPause(); - - mIdleThread = FALSE; + // this will block on the condition until runCondition() returns true, the thread is unpaused, or the thread leaves the RUNNING state. + checkPause(); - threadedUpdate(); - - auto pending_work = processNextRequest(); + mIdleThread = FALSE; - if (pending_work == 0) - { + threadedUpdate(); + + auto pending_work = processNextRequest(); + + if (pending_work == 0) + { //LL_PROFILE_ZONE_NAMED("LLQueuedThread - sleep"); - mIdleThread = TRUE; - //ms_sleep(1); - } - //LLThread::yield(); // thread should yield after each request - }*/ + mIdleThread = TRUE; + //ms_sleep(1); + } + //LLThread::yield(); // thread should yield after each request + }*/ mRequestQueue.runUntilClose(); endThread(); - LL_INFOS() << "LLQueuedThread " << mName << " EXITING." << LL_ENDL; + LL_INFOS() << "LLQueuedThread " << mName << " EXITING." << LL_ENDL; + - } // virtual @@ -562,15 +562,15 @@ void LLQueuedThread::threadedUpdate() //============================================================================ LLQueuedThread::QueuedRequest::QueuedRequest(LLQueuedThread::handle_t handle, U32 flags) : - LLSimpleHashEntry(handle), - mStatus(STATUS_UNKNOWN), - mFlags(flags) + LLSimpleHashEntry(handle), + mStatus(STATUS_UNKNOWN), + mFlags(flags) { } LLQueuedThread::QueuedRequest::~QueuedRequest() { - llassert_always(mStatus == STATUS_DELETE); + llassert_always(mStatus == STATUS_DELETE); } //virtual @@ -581,7 +581,7 @@ void LLQueuedThread::QueuedRequest::finishRequest(bool completed) //virtual void LLQueuedThread::QueuedRequest::deleteRequest() { - llassert_always(mStatus != STATUS_INPROGRESS); - setStatus(STATUS_DELETE); - delete this; + llassert_always(mStatus != STATUS_INPROGRESS); + setStatus(STATUS_DELETE); + delete this; } diff --git a/indra/llcommon/llqueuedthread.h b/indra/llcommon/llqueuedthread.h index 814dbc4c38..339299f081 100644 --- a/indra/llcommon/llqueuedthread.h +++ b/indra/llcommon/llqueuedthread.h @@ -1,25 +1,25 @@ -/** +/** * @file llqueuedthread.h * @brief * * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -44,135 +44,135 @@ class LL_COMMON_API LLQueuedThread : public LLThread { - //------------------------------------------------------------------------ + //------------------------------------------------------------------------ public: - enum status_t { - STATUS_EXPIRED = -1, - STATUS_UNKNOWN = 0, - STATUS_QUEUED = 1, - STATUS_INPROGRESS = 2, - STATUS_COMPLETE = 3, - STATUS_ABORTED = 4, - STATUS_DELETE = 5 - }; - enum flags_t { - FLAG_AUTO_COMPLETE = 1, - FLAG_AUTO_DELETE = 2, // child-class dependent - FLAG_ABORT = 4 - }; - - typedef U32 handle_t; - - //------------------------------------------------------------------------ + enum status_t { + STATUS_EXPIRED = -1, + STATUS_UNKNOWN = 0, + STATUS_QUEUED = 1, + STATUS_INPROGRESS = 2, + STATUS_COMPLETE = 3, + STATUS_ABORTED = 4, + STATUS_DELETE = 5 + }; + enum flags_t { + FLAG_AUTO_COMPLETE = 1, + FLAG_AUTO_DELETE = 2, // child-class dependent + FLAG_ABORT = 4 + }; + + typedef U32 handle_t; + + //------------------------------------------------------------------------ public: - class LL_COMMON_API QueuedRequest : public LLSimpleHashEntry - { - friend class LLQueuedThread; - - protected: - virtual ~QueuedRequest(); // use deleteRequest() - - public: - QueuedRequest(handle_t handle, U32 flags = 0); - - status_t getStatus() - { - return mStatus; - } - U32 getFlags() const - { - return mFlags; - } - - protected: - status_t setStatus(status_t newstatus) - { - status_t oldstatus = mStatus; - mStatus = newstatus; - return oldstatus; - } - void setFlags(U32 flags) - { - // NOTE: flags are |'d - mFlags |= flags; - } - - virtual bool processRequest() = 0; // Return true when request has completed - virtual void finishRequest(bool completed); // Always called from thread after request has completed or aborted - virtual void deleteRequest(); // Only method to delete a request - - protected: - LLAtomicBase mStatus; - U32 mFlags; - }; - - //------------------------------------------------------------------------ - + class LL_COMMON_API QueuedRequest : public LLSimpleHashEntry + { + friend class LLQueuedThread; + + protected: + virtual ~QueuedRequest(); // use deleteRequest() + + public: + QueuedRequest(handle_t handle, U32 flags = 0); + + status_t getStatus() + { + return mStatus; + } + U32 getFlags() const + { + return mFlags; + } + + protected: + status_t setStatus(status_t newstatus) + { + status_t oldstatus = mStatus; + mStatus = newstatus; + return oldstatus; + } + void setFlags(U32 flags) + { + // NOTE: flags are |'d + mFlags |= flags; + } + + virtual bool processRequest() = 0; // Return true when request has completed + virtual void finishRequest(bool completed); // Always called from thread after request has completed or aborted + virtual void deleteRequest(); // Only method to delete a request + + protected: + LLAtomicBase mStatus; + U32 mFlags; + }; + + //------------------------------------------------------------------------ + public: - static handle_t nullHandle() { return handle_t(0); } - + static handle_t nullHandle() { return handle_t(0); } + public: - LLQueuedThread(const std::string& name, bool threaded = true, bool should_pause = false); - virtual ~LLQueuedThread(); - virtual void shutdown(); - + LLQueuedThread(const std::string& name, bool threaded = true, bool should_pause = false); + virtual ~LLQueuedThread(); + virtual void shutdown(); + private: - // No copy constructor or copy assignment - LLQueuedThread(const LLQueuedThread&); - LLQueuedThread& operator=(const LLQueuedThread&); + // No copy constructor or copy assignment + LLQueuedThread(const LLQueuedThread&); + LLQueuedThread& operator=(const LLQueuedThread&); - virtual bool runCondition(void); - virtual void run(void); - virtual void startThread(void); - virtual void endThread(void); - virtual void threadedUpdate(void); + virtual bool runCondition(void); + virtual void run(void); + virtual void startThread(void); + virtual void endThread(void); + virtual void threadedUpdate(void); protected: - handle_t generateHandle(); - bool addRequest(QueuedRequest* req); - void processRequest(QueuedRequest* req); - void incQueue(); + handle_t generateHandle(); + bool addRequest(QueuedRequest* req); + void processRequest(QueuedRequest* req); + void incQueue(); public: - bool waitForResult(handle_t handle, bool auto_complete = true); + bool waitForResult(handle_t handle, bool auto_complete = true); - virtual size_t update(F32 max_time_ms); - size_t updateQueue(F32 max_time_ms); + virtual size_t update(F32 max_time_ms); + size_t updateQueue(F32 max_time_ms); - void waitOnPending(); - void printQueueStats(); + void waitOnPending(); + void printQueueStats(); - virtual size_t getPending(); - bool getThreaded() { return mThreaded ? true : false; } + virtual size_t getPending(); + bool getThreaded() { return mThreaded ? true : false; } - // Request accessors - status_t getRequestStatus(handle_t handle); - void abortRequest(handle_t handle, bool autocomplete); - void setFlags(handle_t handle, U32 flags); - bool completeRequest(handle_t handle); - // This is public for support classes like LLWorkerThread, - // but generally the methods above should be used. - QueuedRequest* getRequest(handle_t handle); + // Request accessors + status_t getRequestStatus(handle_t handle); + void abortRequest(handle_t handle, bool autocomplete); + void setFlags(handle_t handle, U32 flags); + bool completeRequest(handle_t handle); + // This is public for support classes like LLWorkerThread, + // but generally the methods above should be used. + QueuedRequest* getRequest(handle_t handle); + + // debug (see source) + bool check(); - // debug (see source) - bool check(); - protected: - BOOL mThreaded; // if false, run on main thread and do updates during update() - BOOL mStarted; // required when mThreaded is false to call startThread() from update() - LLAtomicBool mIdleThread; // request queue is empty (or we are quitting) and the thread is idle - - //typedef std::set request_queue_t; - //request_queue_t mRequestQueue; + BOOL mThreaded; // if false, run on main thread and do updates during update() + BOOL mStarted; // required when mThreaded is false to call startThread() from update() + LLAtomicBool mIdleThread; // request queue is empty (or we are quitting) and the thread is idle + + //typedef std::set request_queue_t; + //request_queue_t mRequestQueue; LL::WorkQueue mRequestQueue; LL::WorkQueue::weak_t mMainQueue; - enum { REQUEST_HASH_SIZE = 512 }; // must be power of 2 - typedef LLSimpleHash request_hash_t; - request_hash_t mRequestHash; + enum { REQUEST_HASH_SIZE = 512 }; // must be power of 2 + typedef LLSimpleHash request_hash_t; + request_hash_t mRequestHash; - handle_t mNextHandle; + handle_t mNextHandle; }; #endif // LL_LLQUEUEDTHREAD_H diff --git a/indra/llcommon/llrand.cpp b/indra/llcommon/llrand.cpp index 0192111574..25d75af568 100644 --- a/indra/llcommon/llrand.cpp +++ b/indra/llcommon/llrand.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llrand.cpp * @brief Global random generator. * * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -69,25 +69,25 @@ inline REAL ll_internal_random(); template <> inline F64 ll_internal_random() { - // *HACK: Through experimentation, we have found that dual core - // CPUs (or at least multi-threaded processes) seem to - // occasionally give an obviously incorrect random number -- like - // 5^15 or something. Sooooo, clamp it as described above. - F64 rv{ gRandomGenerator() }; - if(!((rv >= 0.0) && (rv < 1.0))) return fmod(rv, 1.0); - return rv; + // *HACK: Through experimentation, we have found that dual core + // CPUs (or at least multi-threaded processes) seem to + // occasionally give an obviously incorrect random number -- like + // 5^15 or something. Sooooo, clamp it as described above. + F64 rv{ gRandomGenerator() }; + if(!((rv >= 0.0) && (rv < 1.0))) return fmod(rv, 1.0); + return rv; } template <> inline F32 ll_internal_random() { - // *HACK: clamp the result as described above. - // Per Monty, it's important to clamp using the correct fmodf() rather - // than expanding to F64 for fmod() and then truncating back to F32. Prior - // to this change, we were getting sporadic ll_frand() == 1.0 results. - F32 rv{ narrow(gRandomGenerator()) }; - if(!((rv >= 0.0f) && (rv < 1.0f))) return fmodf(rv, 1.0f); - return rv; + // *HACK: clamp the result as described above. + // Per Monty, it's important to clamp using the correct fmodf() rather + // than expanding to F64 for fmod() and then truncating back to F32. Prior + // to this change, we were getting sporadic ll_frand() == 1.0 results. + F32 rv{ narrow(gRandomGenerator()) }; + if(!((rv >= 0.0f) && (rv < 1.0f))) return fmodf(rv, 1.0f); + return rv; } /*------------------------------ F64 aliases -------------------------------*/ @@ -98,7 +98,7 @@ inline F64 ll_internal_random_double() F64 ll_drand() { - return ll_internal_random_double(); + return ll_internal_random_double(); } /*------------------------------ F32 aliases -------------------------------*/ @@ -109,37 +109,37 @@ inline F32 ll_internal_random_float() F32 ll_frand() { - return ll_internal_random_float(); + return ll_internal_random_float(); } /*-------------------------- clamped random range --------------------------*/ S32 ll_rand() { - return ll_rand(RAND_MAX); + return ll_rand(RAND_MAX); } S32 ll_rand(S32 val) { - // The clamping rules are described above. - S32 rv = (S32)(ll_internal_random_double() * val); - if(rv == val) return 0; - return rv; + // The clamping rules are described above. + S32 rv = (S32)(ll_internal_random_double() * val); + if(rv == val) return 0; + return rv; } template REAL ll_grand(REAL val) { - // The clamping rules are described above. - REAL rv = ll_internal_random() * val; - if(val > 0) - { - if(rv >= val) return REAL(); - } - else - { - if(rv <= val) return REAL(); - } - return rv; + // The clamping rules are described above. + REAL rv = ll_internal_random() * val; + if(val > 0) + { + if(rv >= val) return REAL(); + } + else + { + if(rv <= val) return REAL(); + } + return rv; } F32 ll_frand(F32 val) diff --git a/indra/llcommon/llrand.h b/indra/llcommon/llrand.h index ad317d5bf7..625ae0f5f4 100644 --- a/indra/llcommon/llrand.h +++ b/indra/llcommon/llrand.h @@ -1,25 +1,25 @@ -/** +/** * @file llrand.h * @brief Information, functions, and typedefs for randomness. * * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -42,18 +42,18 @@ * fairly trivial operations to try to limit compiler optimizations, * so these numbers are only good for relative comparisons. * - * usec/inter algorithm - * 0.21 boost::minstd_rand0 - * 0.039 boost:lagged_fibonacci19937 - * 0.036 boost:lagged_fibonacci607 - * 0.44 boost::hellekalek1995 - * 0.44 boost::ecuyer1988 - * 0.042 boost::rand48 - * 0.043 boost::mt11213b - * 0.028 stdlib random() - * 0.05 stdlib lrand48() - * 0.034 stdlib rand() - * 0.020 the old & lame LLRand + * usec/inter algorithm + * 0.21 boost::minstd_rand0 + * 0.039 boost:lagged_fibonacci19937 + * 0.036 boost:lagged_fibonacci607 + * 0.44 boost::hellekalek1995 + * 0.44 boost::ecuyer1988 + * 0.042 boost::rand48 + * 0.043 boost::mt11213b + * 0.028 stdlib random() + * 0.05 stdlib lrand48() + * 0.034 stdlib rand() + * 0.020 the old & lame LLRand */ /** @@ -100,13 +100,13 @@ F64 LL_COMMON_API ll_drand(F64 val); */ typedef boost::lagged_fibonacci607 LLRandLagFib607; -/**< +/**< * lengh of cycle: 2^32,000 * memory: 607*sizeof(double) (about 5K) */ typedef boost::lagged_fibonacci2281 LLRandLagFib2281; -/**< +/**< * lengh of cycle: 2^120,000 * memory: 2281*sizeof(double) (about 17K) */ diff --git a/indra/llcommon/llrefcount.cpp b/indra/llcommon/llrefcount.cpp index 3da94e7a8d..6b546aac63 100644 --- a/indra/llcommon/llrefcount.cpp +++ b/indra/llcommon/llrefcount.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llrefcount.cpp * @brief Base class for reference counted objects for use with LLPointer * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -33,26 +33,26 @@ const S32 gMaxRefCount = LL_REFCOUNT_FREE; LLRefCount::LLRefCount(const LLRefCount& other) -: mRef(0) +: mRef(0) { } LLRefCount& LLRefCount::operator=(const LLRefCount&) { - // do nothing, since ref count is specific to *this* reference - return *this; + // do nothing, since ref count is specific to *this* reference + return *this; } LLRefCount::LLRefCount() : - mRef(0) + mRef(0) { } LLRefCount::~LLRefCount() { - if (mRef != LL_REFCOUNT_FREE && mRef != 0) - { - LL_ERRS() << "deleting non-zero reference" << LL_ENDL; - } + if (mRef != LL_REFCOUNT_FREE && mRef != 0) + { + LL_ERRS() << "deleting non-zero reference" << LL_ENDL; + } } diff --git a/indra/llcommon/llrefcount.h b/indra/llcommon/llrefcount.h index 15e7175fc8..33c9e956b1 100644 --- a/indra/llcommon/llrefcount.h +++ b/indra/llcommon/llrefcount.h @@ -1,25 +1,25 @@ -/** +/** * @file llrefcount.h * @brief Base class for reference counted objects for use with LLPointer * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -44,42 +44,42 @@ extern const S32 gMaxRefCount; class LL_COMMON_API LLRefCount { protected: - LLRefCount(const LLRefCount& other); - LLRefCount& operator=(const LLRefCount&); - virtual ~LLRefCount(); // use unref() - + LLRefCount(const LLRefCount& other); + LLRefCount& operator=(const LLRefCount&); + virtual ~LLRefCount(); // use unref() + public: - LLRefCount(); - - inline void ref() const - { - llassert(mRef != LL_REFCOUNT_FREE); // object is deleted - mRef++; - llassert(mRef < gMaxRefCount); // ref count excessive, likely memory leak - } - - inline S32 unref() const - { - llassert(mRef != LL_REFCOUNT_FREE); // object is deleted - llassert(mRef > 0); // ref count below 1, likely corrupted - if (0 == --mRef) - { - mRef = LL_REFCOUNT_FREE; // set to nonsense yet recognizable value to aid in debugging - delete this; - return 0; - } - return mRef; - } - - //NOTE: when passing around a const LLRefCount object, this can return different results - // at different types, since mRef is mutable - S32 getNumRefs() const - { - return mRef; - } + LLRefCount(); + + inline void ref() const + { + llassert(mRef != LL_REFCOUNT_FREE); // object is deleted + mRef++; + llassert(mRef < gMaxRefCount); // ref count excessive, likely memory leak + } + + inline S32 unref() const + { + llassert(mRef != LL_REFCOUNT_FREE); // object is deleted + llassert(mRef > 0); // ref count below 1, likely corrupted + if (0 == --mRef) + { + mRef = LL_REFCOUNT_FREE; // set to nonsense yet recognizable value to aid in debugging + delete this; + return 0; + } + return mRef; + } + + //NOTE: when passing around a const LLRefCount object, this can return different results + // at different types, since mRef is mutable + S32 getNumRefs() const + { + return mRef; + } private: - mutable S32 mRef; + mutable S32 mRef; }; @@ -90,50 +90,50 @@ private: class LL_COMMON_API LLThreadSafeRefCount { public: - static void initThreadSafeRefCount(); // creates sMutex - static void cleanupThreadSafeRefCount(); // destroys sMutex + static void initThreadSafeRefCount(); // creates sMutex + static void cleanupThreadSafeRefCount(); // destroys sMutex private: - static LLMutex* sMutex; + static LLMutex* sMutex; protected: - virtual ~LLThreadSafeRefCount(); // use unref() + virtual ~LLThreadSafeRefCount(); // use unref() public: - LLThreadSafeRefCount(); - LLThreadSafeRefCount(const LLThreadSafeRefCount&); - LLThreadSafeRefCount& operator=(const LLThreadSafeRefCount& ref) - { - mRef = 0; - return *this; - } - - void ref() - { - mRef++; - } - - void unref() - { - llassert(mRef >= 1); - if ((--mRef) == 0) - { - // If we hit zero, the caller should be the only smart pointer owning the object and we can delete it. - // It is technically possible for a vanilla pointer to mess this up, or another thread to - // jump in, find this object, create another smart pointer and end up dangling, but if - // the code is that bad and not thread-safe, it's trouble already. - delete this; - } - } - - S32 getNumRefs() const - { - const S32 currentVal = mRef.CurrentValue(); - return currentVal; - } + LLThreadSafeRefCount(); + LLThreadSafeRefCount(const LLThreadSafeRefCount&); + LLThreadSafeRefCount& operator=(const LLThreadSafeRefCount& ref) + { + mRef = 0; + return *this; + } + + void ref() + { + mRef++; + } + + void unref() + { + llassert(mRef >= 1); + if ((--mRef) == 0) + { + // If we hit zero, the caller should be the only smart pointer owning the object and we can delete it. + // It is technically possible for a vanilla pointer to mess this up, or another thread to + // jump in, find this object, create another smart pointer and end up dangling, but if + // the code is that bad and not thread-safe, it's trouble already. + delete this; + } + } + + S32 getNumRefs() const + { + const S32 currentVal = mRef.CurrentValue(); + return currentVal; + } private: - LLAtomicS32 mRef; + LLAtomicS32 mRef; }; /** @@ -142,12 +142,12 @@ private: */ inline void intrusive_ptr_add_ref(LLThreadSafeRefCount* p) { - p->ref(); + p->ref(); } inline void intrusive_ptr_release(LLThreadSafeRefCount* p) { - p->unref(); + p->unref(); } /** @@ -156,12 +156,12 @@ inline void intrusive_ptr_release(LLThreadSafeRefCount* p) */ inline void intrusive_ptr_add_ref(LLRefCount* p) { - p->ref(); + p->ref(); } inline void intrusive_ptr_release(LLRefCount* p) { - p->unref(); + p->unref(); } #endif diff --git a/indra/llcommon/llregex.h b/indra/llcommon/llregex.h index 2b7f5e47c2..18da304aee 100644 --- a/indra/llcommon/llregex.h +++ b/indra/llcommon/llregex.h @@ -1,24 +1,24 @@ -/** +/** * @file llregex.h * * $LicenseInfo:firstyear=2021&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2021, 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$ */ @@ -30,60 +30,60 @@ template LL_COMMON_API bool ll_regex_match(const S& string, M& match, const R& regex) { - try - { - return boost::regex_match(string, match, regex); - } - catch (const std::runtime_error& e) - { - LL_WARNS() << "error matching with '" << regex.str() << "': " - << e.what() << ":\n'" << string << "'" << LL_ENDL; - return false; - } + try + { + return boost::regex_match(string, match, regex); + } + catch (const std::runtime_error& e) + { + LL_WARNS() << "error matching with '" << regex.str() << "': " + << e.what() << ":\n'" << string << "'" << LL_ENDL; + return false; + } } template LL_COMMON_API bool ll_regex_match(const S& string, const R& regex) { - try - { - return boost::regex_match(string, regex); - } - catch (const std::runtime_error& e) - { - LL_WARNS() << "error matching with '" << regex.str() << "': " - << e.what() << ":\n'" << string << "'" << LL_ENDL; - return false; - } + try + { + return boost::regex_match(string, regex); + } + catch (const std::runtime_error& e) + { + LL_WARNS() << "error matching with '" << regex.str() << "': " + << e.what() << ":\n'" << string << "'" << LL_ENDL; + return false; + } } template bool ll_regex_search(const S& string, M& match, const R& regex) { - try - { - return boost::regex_search(string, match, regex); - } - catch (const std::runtime_error& e) - { - LL_WARNS() << "error searching with '" << regex.str() << "': " - << e.what() << ":\n'" << string << "'" << LL_ENDL; - return false; - } + try + { + return boost::regex_search(string, match, regex); + } + catch (const std::runtime_error& e) + { + LL_WARNS() << "error searching with '" << regex.str() << "': " + << e.what() << ":\n'" << string << "'" << LL_ENDL; + return false; + } } template bool ll_regex_search(const S& string, const R& regex) { - try - { - return boost::regex_search(string, regex); - } - catch (const std::runtime_error& e) - { - LL_WARNS() << "error searching with '" << regex.str() << "': " - << e.what() << ":\n'" << string << "'" << LL_ENDL; - return false; - } + try + { + return boost::regex_search(string, regex); + } + catch (const std::runtime_error& e) + { + LL_WARNS() << "error searching with '" << regex.str() << "': " + << e.what() << ":\n'" << string << "'" << LL_ENDL; + return false; + } } #endif // LLREGEX_H diff --git a/indra/llcommon/llregistry.h b/indra/llcommon/llregistry.h index e272d7a9b8..55dabd57a2 100644 --- a/indra/llcommon/llregistry.h +++ b/indra/llcommon/llregistry.h @@ -1,25 +1,25 @@ -/** +/** * @file llregistry.h * @brief template classes for registering name, value pairs in nested scopes, statically, etc. * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -35,314 +35,314 @@ template struct LLRegistryDefaultComparator { - bool operator()(const T& lhs, const T& rhs) const - { - using std::less; - return less()(lhs, rhs); - } + bool operator()(const T& lhs, const T& rhs) const + { + using std::less; + return less()(lhs, rhs); + } }; template > class LLRegistry { public: - typedef LLRegistry registry_t; - typedef const KEY& ref_const_key_t; - typedef const VALUE& ref_const_value_t; - typedef const VALUE* ptr_const_value_t; - typedef VALUE* ptr_value_t; - - class Registrar - { - friend class LLRegistry; - public: - typedef std::map registry_map_t; - - bool add(ref_const_key_t key, ref_const_value_t value) - { - if (mMap.insert(std::make_pair(key, value)).second == false) - { - LL_WARNS() << "Tried to register " << key << " but it was already registered!" << LL_ENDL; - return false; - } - return true; - } - - void remove(ref_const_key_t key) - { - mMap.erase(key); - } - - void replace(ref_const_key_t key, ref_const_value_t value) - { - mMap[key] = value; - } - - typename registry_map_t::const_iterator beginItems() const - { - return mMap.begin(); - } - - typename registry_map_t::const_iterator endItems() const - { - return mMap.end(); - } - - protected: - ptr_value_t getValue(ref_const_key_t key) - { - typename registry_map_t::iterator found_it = mMap.find(key); - if (found_it != mMap.end()) - { - return &(found_it->second); - } - return NULL; - } - - ptr_const_value_t getValue(ref_const_key_t key) const - { - typename registry_map_t::const_iterator found_it = mMap.find(key); - if (found_it != mMap.end()) - { - return &(found_it->second); - } - return NULL; - } - - // if the registry is used to store pointers, and null values are valid entries - // then use this function to check the existence of an entry - bool exists(ref_const_key_t key) const - { - return mMap.find(key) != mMap.end(); - } - - bool empty() const - { - return mMap.empty(); - } - - protected: - // use currentRegistrar() or defaultRegistrar() - Registrar() {} - ~Registrar() {} - - private: - registry_map_t mMap; - }; - - typedef typename std::list scope_list_t; - typedef typename std::list::iterator scope_list_iterator_t; - typedef typename std::list::const_iterator scope_list_const_iterator_t; - - LLRegistry() - {} - - ~LLRegistry() {} - - ptr_value_t getValue(ref_const_key_t key) - { - for(Registrar* scope : mActiveScopes) - { - ptr_value_t valuep = scope->getValue(key); - if (valuep != NULL) return valuep; - } - return mDefaultRegistrar.getValue(key); - } - - ptr_const_value_t getValue(ref_const_key_t key) const - { - for(const Registrar* scope : mActiveScopes) - { - ptr_const_value_t valuep = scope->getValue(key); - if (valuep != NULL) return valuep; - } - return mDefaultRegistrar.getValue(key); - } - - bool exists(ref_const_key_t key) const - { - for(const Registrar* scope : mActiveScopes) - { - if (scope->exists(key)) return true; - } - - return mDefaultRegistrar.exists(key); - } - - bool empty() const - { - for(const Registrar* scope : mActiveScopes) - { - if (!scope->empty()) return false; - } - - return mDefaultRegistrar.empty(); - } - - - Registrar& defaultRegistrar() - { - return mDefaultRegistrar; - } - - const Registrar& defaultRegistrar() const - { - return mDefaultRegistrar; - } - - - Registrar& currentRegistrar() - { - if (!mActiveScopes.empty()) - { - return *mActiveScopes.front(); - } - - return mDefaultRegistrar; - } - - const Registrar& currentRegistrar() const - { - if (!mActiveScopes.empty()) - { - return *mActiveScopes.front(); - } - - return mDefaultRegistrar; - } + typedef LLRegistry registry_t; + typedef const KEY& ref_const_key_t; + typedef const VALUE& ref_const_value_t; + typedef const VALUE* ptr_const_value_t; + typedef VALUE* ptr_value_t; + + class Registrar + { + friend class LLRegistry; + public: + typedef std::map registry_map_t; + + bool add(ref_const_key_t key, ref_const_value_t value) + { + if (mMap.insert(std::make_pair(key, value)).second == false) + { + LL_WARNS() << "Tried to register " << key << " but it was already registered!" << LL_ENDL; + return false; + } + return true; + } + + void remove(ref_const_key_t key) + { + mMap.erase(key); + } + + void replace(ref_const_key_t key, ref_const_value_t value) + { + mMap[key] = value; + } + + typename registry_map_t::const_iterator beginItems() const + { + return mMap.begin(); + } + + typename registry_map_t::const_iterator endItems() const + { + return mMap.end(); + } + + protected: + ptr_value_t getValue(ref_const_key_t key) + { + typename registry_map_t::iterator found_it = mMap.find(key); + if (found_it != mMap.end()) + { + return &(found_it->second); + } + return NULL; + } + + ptr_const_value_t getValue(ref_const_key_t key) const + { + typename registry_map_t::const_iterator found_it = mMap.find(key); + if (found_it != mMap.end()) + { + return &(found_it->second); + } + return NULL; + } + + // if the registry is used to store pointers, and null values are valid entries + // then use this function to check the existence of an entry + bool exists(ref_const_key_t key) const + { + return mMap.find(key) != mMap.end(); + } + + bool empty() const + { + return mMap.empty(); + } + + protected: + // use currentRegistrar() or defaultRegistrar() + Registrar() {} + ~Registrar() {} + + private: + registry_map_t mMap; + }; + + typedef typename std::list scope_list_t; + typedef typename std::list::iterator scope_list_iterator_t; + typedef typename std::list::const_iterator scope_list_const_iterator_t; + + LLRegistry() + {} + + ~LLRegistry() {} + + ptr_value_t getValue(ref_const_key_t key) + { + for(Registrar* scope : mActiveScopes) + { + ptr_value_t valuep = scope->getValue(key); + if (valuep != NULL) return valuep; + } + return mDefaultRegistrar.getValue(key); + } + + ptr_const_value_t getValue(ref_const_key_t key) const + { + for(const Registrar* scope : mActiveScopes) + { + ptr_const_value_t valuep = scope->getValue(key); + if (valuep != NULL) return valuep; + } + return mDefaultRegistrar.getValue(key); + } + + bool exists(ref_const_key_t key) const + { + for(const Registrar* scope : mActiveScopes) + { + if (scope->exists(key)) return true; + } + + return mDefaultRegistrar.exists(key); + } + + bool empty() const + { + for(const Registrar* scope : mActiveScopes) + { + if (!scope->empty()) return false; + } + + return mDefaultRegistrar.empty(); + } + + + Registrar& defaultRegistrar() + { + return mDefaultRegistrar; + } + + const Registrar& defaultRegistrar() const + { + return mDefaultRegistrar; + } + + + Registrar& currentRegistrar() + { + if (!mActiveScopes.empty()) + { + return *mActiveScopes.front(); + } + + return mDefaultRegistrar; + } + + const Registrar& currentRegistrar() const + { + if (!mActiveScopes.empty()) + { + return *mActiveScopes.front(); + } + + return mDefaultRegistrar; + } protected: - void addScope(Registrar* scope) - { - // newer scopes go up front - mActiveScopes.insert(mActiveScopes.begin(), scope); - } - - void removeScope(Registrar* scope) - { - // O(N) but should be near the beggining and N should be small and this is safer than storing iterators - scope_list_iterator_t iter = std::find(mActiveScopes.begin(), mActiveScopes.end(), scope); - if (iter != mActiveScopes.end()) - { - mActiveScopes.erase(iter); - } - } + void addScope(Registrar* scope) + { + // newer scopes go up front + mActiveScopes.insert(mActiveScopes.begin(), scope); + } + + void removeScope(Registrar* scope) + { + // O(N) but should be near the beggining and N should be small and this is safer than storing iterators + scope_list_iterator_t iter = std::find(mActiveScopes.begin(), mActiveScopes.end(), scope); + if (iter != mActiveScopes.end()) + { + mActiveScopes.erase(iter); + } + } private: - scope_list_t mActiveScopes; - Registrar mDefaultRegistrar; + scope_list_t mActiveScopes; + Registrar mDefaultRegistrar; }; template > class LLRegistrySingleton - : public LLRegistry, - public LLSingleton + : public LLRegistry, + public LLSingleton { - // This LLRegistrySingleton doesn't use LLSINGLETON(LLRegistrySingleton) - // because the concrete class is actually DERIVED_TYPE, not - // LLRegistrySingleton. So each concrete subclass needs - // LLSINGLETON(whatever) -- not this intermediate base class. + // This LLRegistrySingleton doesn't use LLSINGLETON(LLRegistrySingleton) + // because the concrete class is actually DERIVED_TYPE, not + // LLRegistrySingleton. So each concrete subclass needs + // LLSINGLETON(whatever) -- not this intermediate base class. public: - typedef LLRegistry registry_t; - typedef const KEY& ref_const_key_t; - typedef const VALUE& ref_const_value_t; - typedef VALUE* ptr_value_t; - typedef const VALUE* ptr_const_value_t; - typedef LLSingleton singleton_t; - - class ScopedRegistrar : public registry_t::Registrar - { - public: - ScopedRegistrar(bool push_scope = true) - { - if (push_scope) - { - pushScope(); - } - } - - ~ScopedRegistrar() - { - if (singleton_t::instanceExists()) - { - popScope(); - } - } - - void pushScope() - { - singleton_t::instance().addScope(this); - } - - void popScope() - { - singleton_t::instance().removeScope(this); - } - - ptr_value_t getValueFromScope(ref_const_key_t key) - { - return getValue(key); - } - - ptr_const_value_t getValueFromScope(ref_const_key_t key) const - { - return getValue(key); - } - - private: - typename std::list::iterator mListIt; - }; - - class StaticRegistrar : public registry_t::Registrar - { - public: - virtual ~StaticRegistrar() {} - StaticRegistrar(ref_const_key_t key, ref_const_value_t value) - { - if (singleton_t::instance().exists(key)) - { - LL_ERRS() << "Duplicate registry entry under key \"" << key << "\"" << LL_ENDL; - } - singleton_t::instance().mStaticScope->add(key, value); - } - }; - - // convenience functions - typedef typename LLRegistry::Registrar& ref_registrar_t; - static ref_registrar_t currentRegistrar() - { - return singleton_t::instance().registry_t::currentRegistrar(); - } - - static ref_registrar_t defaultRegistrar() - { - return singleton_t::instance().registry_t::defaultRegistrar(); - } - - static ptr_value_t getValue(ref_const_key_t key) - { - return singleton_t::instance().registry_t::getValue(key); - } + typedef LLRegistry registry_t; + typedef const KEY& ref_const_key_t; + typedef const VALUE& ref_const_value_t; + typedef VALUE* ptr_value_t; + typedef const VALUE* ptr_const_value_t; + typedef LLSingleton singleton_t; + + class ScopedRegistrar : public registry_t::Registrar + { + public: + ScopedRegistrar(bool push_scope = true) + { + if (push_scope) + { + pushScope(); + } + } + + ~ScopedRegistrar() + { + if (singleton_t::instanceExists()) + { + popScope(); + } + } + + void pushScope() + { + singleton_t::instance().addScope(this); + } + + void popScope() + { + singleton_t::instance().removeScope(this); + } + + ptr_value_t getValueFromScope(ref_const_key_t key) + { + return getValue(key); + } + + ptr_const_value_t getValueFromScope(ref_const_key_t key) const + { + return getValue(key); + } + + private: + typename std::list::iterator mListIt; + }; + + class StaticRegistrar : public registry_t::Registrar + { + public: + virtual ~StaticRegistrar() {} + StaticRegistrar(ref_const_key_t key, ref_const_value_t value) + { + if (singleton_t::instance().exists(key)) + { + LL_ERRS() << "Duplicate registry entry under key \"" << key << "\"" << LL_ENDL; + } + singleton_t::instance().mStaticScope->add(key, value); + } + }; + + // convenience functions + typedef typename LLRegistry::Registrar& ref_registrar_t; + static ref_registrar_t currentRegistrar() + { + return singleton_t::instance().registry_t::currentRegistrar(); + } + + static ref_registrar_t defaultRegistrar() + { + return singleton_t::instance().registry_t::defaultRegistrar(); + } + + static ptr_value_t getValue(ref_const_key_t key) + { + return singleton_t::instance().registry_t::getValue(key); + } protected: - // DERIVED_TYPE needs to derive from LLRegistrySingleton - LLRegistrySingleton() - : mStaticScope(NULL) - {} + // DERIVED_TYPE needs to derive from LLRegistrySingleton + LLRegistrySingleton() + : mStaticScope(NULL) + {} - virtual void initSingleton() - { - mStaticScope = new ScopedRegistrar(); - } + virtual void initSingleton() + { + mStaticScope = new ScopedRegistrar(); + } - virtual ~LLRegistrySingleton() - { - delete mStaticScope; - } + virtual ~LLRegistrySingleton() + { + delete mStaticScope; + } private: - ScopedRegistrar* mStaticScope; + ScopedRegistrar* mStaticScope; }; // helper macro for doing static registration diff --git a/indra/llcommon/llrun.cpp b/indra/llcommon/llrun.cpp index a3b3fccf4b..82005b16bc 100644 --- a/indra/llcommon/llrun.cpp +++ b/indra/llcommon/llrun.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llrun.cpp * @author Phoenix * @date 2006-02-16 @@ -7,21 +7,21 @@ * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -33,136 +33,136 @@ static const LLRunner::run_handle_t INVALID_RUN_HANDLE = 0; -/** +/** * LLRunner */ LLRunner::LLRunner() : - mNextHandle(1) + mNextHandle(1) { } LLRunner::~LLRunner() { - mRunOnce.clear(); - mRunEvery.clear(); + mRunOnce.clear(); + mRunEvery.clear(); } size_t LLRunner::run() { - // We collect all of the runnables which should be run. Since the - // runnables are allowed to adjust the run list, we need to copy - // them into a temporary structure which then iterates over them - // to call out of this method into the runnables. - F64 now = LLFrameTimer::getTotalSeconds(); - run_list_t run_now; + // We collect all of the runnables which should be run. Since the + // runnables are allowed to adjust the run list, we need to copy + // them into a temporary structure which then iterates over them + // to call out of this method into the runnables. + F64 now = LLFrameTimer::getTotalSeconds(); + run_list_t run_now; - // Collect the run once. We erase the matching ones now because - // it's easier. If we find a reason to keep them around for a - // while, we can restructure this method. - LLRunner::run_list_t::iterator iter = mRunOnce.begin(); - for( ; iter != mRunOnce.end(); ) - { - if(now > (*iter).mNextRunAt) - { - run_now.push_back(*iter); - iter = mRunOnce.erase(iter); - } - else - { - ++iter; - } - } + // Collect the run once. We erase the matching ones now because + // it's easier. If we find a reason to keep them around for a + // while, we can restructure this method. + LLRunner::run_list_t::iterator iter = mRunOnce.begin(); + for( ; iter != mRunOnce.end(); ) + { + if(now > (*iter).mNextRunAt) + { + run_now.push_back(*iter); + iter = mRunOnce.erase(iter); + } + else + { + ++iter; + } + } - // Collect the ones that repeat. - iter = mRunEvery.begin(); - LLRunner::run_list_t::iterator end = mRunEvery.end(); - for( ; iter != end; ++iter ) - { - if(now > (*iter).mNextRunAt) - { - (*iter).mNextRunAt = now + (*iter).mIncrement; - run_now.push_back(*iter); - } - } + // Collect the ones that repeat. + iter = mRunEvery.begin(); + LLRunner::run_list_t::iterator end = mRunEvery.end(); + for( ; iter != end; ++iter ) + { + if(now > (*iter).mNextRunAt) + { + (*iter).mNextRunAt = now + (*iter).mIncrement; + run_now.push_back(*iter); + } + } - // Now, run them. - iter = run_now.begin(); - end = run_now.end(); - for( ; iter != end; ++iter ) - { - (*iter).mRunnable->run(this, (*iter).mHandle); - } - return run_now.size(); + // Now, run them. + iter = run_now.begin(); + end = run_now.end(); + for( ; iter != end; ++iter ) + { + (*iter).mRunnable->run(this, (*iter).mHandle); + } + return run_now.size(); } LLRunner::run_handle_t LLRunner::addRunnable( - run_ptr_t runnable, - ERunSchedule schedule, - F64 seconds) + run_ptr_t runnable, + ERunSchedule schedule, + F64 seconds) { - if(!runnable) return INVALID_RUN_HANDLE; - run_handle_t handle = mNextHandle++; - F64 next_run = LLFrameTimer::getTotalSeconds() + seconds; - LLRunInfo info(handle, runnable, schedule, next_run, seconds); - switch(schedule) - { - case RUN_IN: - // We could optimize this a bit by sorting this on entry. - mRunOnce.push_back(info); - break; - case RUN_EVERY: - mRunEvery.push_back(info); - break; - default: - handle = INVALID_RUN_HANDLE; - break; - } - return handle; + if(!runnable) return INVALID_RUN_HANDLE; + run_handle_t handle = mNextHandle++; + F64 next_run = LLFrameTimer::getTotalSeconds() + seconds; + LLRunInfo info(handle, runnable, schedule, next_run, seconds); + switch(schedule) + { + case RUN_IN: + // We could optimize this a bit by sorting this on entry. + mRunOnce.push_back(info); + break; + case RUN_EVERY: + mRunEvery.push_back(info); + break; + default: + handle = INVALID_RUN_HANDLE; + break; + } + return handle; } LLRunner::run_ptr_t LLRunner::removeRunnable(LLRunner::run_handle_t handle) { - LLRunner::run_ptr_t rv; - LLRunner::run_list_t::iterator iter = mRunOnce.begin(); - LLRunner::run_list_t::iterator end = mRunOnce.end(); - for( ; iter != end; ++iter) - { - if((*iter).mHandle == handle) - { - rv = (*iter).mRunnable; - mRunOnce.erase(iter); - return rv; - } - } + LLRunner::run_ptr_t rv; + LLRunner::run_list_t::iterator iter = mRunOnce.begin(); + LLRunner::run_list_t::iterator end = mRunOnce.end(); + for( ; iter != end; ++iter) + { + if((*iter).mHandle == handle) + { + rv = (*iter).mRunnable; + mRunOnce.erase(iter); + return rv; + } + } - iter = mRunEvery.begin(); - end = mRunEvery.end(); - for( ; iter != end; ++iter) - { - if((*iter).mHandle == handle) - { - rv = (*iter).mRunnable; - mRunEvery.erase(iter); - return rv; - } - } - return rv; + iter = mRunEvery.begin(); + end = mRunEvery.end(); + for( ; iter != end; ++iter) + { + if((*iter).mHandle == handle) + { + rv = (*iter).mRunnable; + mRunEvery.erase(iter); + return rv; + } + } + return rv; } -/** +/** * LLRunner::LLRunInfo */ LLRunner::LLRunInfo::LLRunInfo( - run_handle_t handle, - run_ptr_t runnable, - ERunSchedule schedule, - F64 next_run_after, - F64 increment) : - mHandle(handle), - mRunnable(runnable), - mSchedule(schedule), - mNextRunAt(next_run_after), - mIncrement(increment) + run_handle_t handle, + run_ptr_t runnable, + ERunSchedule schedule, + F64 next_run_after, + F64 increment) : + mHandle(handle), + mRunnable(runnable), + mSchedule(schedule), + mNextRunAt(next_run_after), + mIncrement(increment) { } diff --git a/indra/llcommon/llrun.h b/indra/llcommon/llrun.h index 42e3d9b47a..8061117ad5 100644 --- a/indra/llcommon/llrun.h +++ b/indra/llcommon/llrun.h @@ -1,4 +1,4 @@ -/** +/** * @file llrun.h * @author Phoenix * @date 2006-02-16 @@ -7,21 +7,21 @@ * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -34,7 +34,7 @@ class LLRunnable; -/** +/** * @class LLRunner * @brief This class manages a set of LLRunnable objects. * @@ -45,96 +45,96 @@ class LLRunnable; class LL_COMMON_API LLRunner { public: - /** - * @brief The pointer to a runnable. - */ - typedef std::shared_ptr run_ptr_t; - - /** - * @brief The handle for use in the API. - */ - typedef S64 run_handle_t; - - /** - * @brief Constructor. - */ - LLRunner(); - - /** - * @brief Destructor. - */ - ~LLRunner(); - - /** - * @brief Enumeration which specifies when to run. - */ - enum ERunSchedule - { - // The runnable will run in N seconds - RUN_IN, - - // The run every N seconds - RUN_EVERY, - - // A count of the run types - RUN_SCHEDULE_COUNT - }; - - /** - * @brief Run the runnables which are scheduled to run - * - * @return Returns the number of runnables run. - */ - size_t run(); - - /** - * @brief Add a runnable to the run list. - * - * The handle of the runnable is unique to each addition. If the - * same runnable is added a second time with the same or different - * schedule, this method will return a new handle. - * @param runnable The runnable to run() on schedule. - * @param schedule Specifies the run schedule. - * @param seconds When to run the runnable as interpreted by schedule. - * @return Returns the handle to the runnable. handle == 0 means failure. - */ - run_handle_t addRunnable( - run_ptr_t runnable, - ERunSchedule schedule, - F64 seconds); - - /** - * @brief Remove the specified runnable. - * - * @param handle The handle of the runnable to remove. - * @return Returns the pointer to the runnable removed which may - * be empty. - */ - run_ptr_t removeRunnable(run_handle_t handle); + /** + * @brief The pointer to a runnable. + */ + typedef std::shared_ptr run_ptr_t; + + /** + * @brief The handle for use in the API. + */ + typedef S64 run_handle_t; + + /** + * @brief Constructor. + */ + LLRunner(); + + /** + * @brief Destructor. + */ + ~LLRunner(); + + /** + * @brief Enumeration which specifies when to run. + */ + enum ERunSchedule + { + // The runnable will run in N seconds + RUN_IN, + + // The run every N seconds + RUN_EVERY, + + // A count of the run types + RUN_SCHEDULE_COUNT + }; + + /** + * @brief Run the runnables which are scheduled to run + * + * @return Returns the number of runnables run. + */ + size_t run(); + + /** + * @brief Add a runnable to the run list. + * + * The handle of the runnable is unique to each addition. If the + * same runnable is added a second time with the same or different + * schedule, this method will return a new handle. + * @param runnable The runnable to run() on schedule. + * @param schedule Specifies the run schedule. + * @param seconds When to run the runnable as interpreted by schedule. + * @return Returns the handle to the runnable. handle == 0 means failure. + */ + run_handle_t addRunnable( + run_ptr_t runnable, + ERunSchedule schedule, + F64 seconds); + + /** + * @brief Remove the specified runnable. + * + * @param handle The handle of the runnable to remove. + * @return Returns the pointer to the runnable removed which may + * be empty. + */ + run_ptr_t removeRunnable(run_handle_t handle); protected: - struct LLRunInfo - { - run_handle_t mHandle; - run_ptr_t mRunnable; - ERunSchedule mSchedule; - F64 mNextRunAt; - F64 mIncrement; - LLRunInfo( - run_handle_t handle, - run_ptr_t runnable, - ERunSchedule schedule, - F64 next_run_at, - F64 increment); - }; - typedef std::vector run_list_t; - run_list_t mRunOnce; - run_list_t mRunEvery; - run_handle_t mNextHandle; + struct LLRunInfo + { + run_handle_t mHandle; + run_ptr_t mRunnable; + ERunSchedule mSchedule; + F64 mNextRunAt; + F64 mIncrement; + LLRunInfo( + run_handle_t handle, + run_ptr_t runnable, + ERunSchedule schedule, + F64 next_run_at, + F64 increment); + }; + typedef std::vector run_list_t; + run_list_t mRunOnce; + run_list_t mRunEvery; + run_handle_t mNextHandle; }; -/** +/** * @class LLRunnable * @brief Abstract base class for running some scheduled process. * @@ -146,17 +146,17 @@ protected: class LL_COMMON_API LLRunnable { public: - LLRunnable(); - virtual ~LLRunnable(); - - /** - * @brief Do the process. - * - * This method will be called from the LLRunner according to - * @param runner The Runner which call run(). - * @param handle The handle this run instance is run under. - */ - virtual void run(LLRunner* runner, S64 handle) = 0; + LLRunnable(); + virtual ~LLRunnable(); + + /** + * @brief Do the process. + * + * This method will be called from the LLRunner according to + * @param runner The Runner which call run(). + * @param handle The handle this run instance is run under. + */ + virtual void run(LLRunner* runner, S64 handle) = 0; }; #endif // LL_LLRUN_H diff --git a/indra/llcommon/llsafehandle.h b/indra/llcommon/llsafehandle.h index 9550e6253e..1d7e4f8220 100644 --- a/indra/llcommon/llsafehandle.h +++ b/indra/llcommon/llsafehandle.h @@ -1,32 +1,32 @@ -/** +/** * @file llsafehandle.h * @brief Reference-counted object where Object() is valid, not NULL. * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ #ifndef LLSAFEHANDLE_H #define LLSAFEHANDLE_H -#include "llerror.h" // *TODO: consider eliminating this +#include "llerror.h" // *TODO: consider eliminating this #include "llsingleton.h" /*==========================================================================*| @@ -57,142 +57,142 @@ not ever affect subsequent computations. // when error checking occurs at a different granularity or in a different part of the code // than when referencing an object via a LLSafeHandle. -template +template class LLSafeHandle { public: - LLSafeHandle() : - mPointer(NULL) - { - } - - LLSafeHandle(Type* ptr) : - mPointer(NULL) - { - assign(ptr); - } - - LLSafeHandle(const LLSafeHandle& ptr) : - mPointer(NULL) - { - assign(ptr.mPointer); - } - - // support conversion up the type hierarchy. See Item 45 in Effective C++, 3rd Ed. - template - LLSafeHandle(const LLSafeHandle& ptr) : - mPointer(NULL) - { - assign(ptr.get()); - } - - ~LLSafeHandle() - { - unref(); - } - - const Type* operator->() const { return nonNull(mPointer); } - Type* operator->() { return nonNull(mPointer); } - - Type* get() const { return mPointer; } - void clear() { assign(NULL); } - // we disallow these operations as they expose our null objects to direct manipulation - // and bypass the reference counting semantics - //const Type& operator*() const { return *nonNull(mPointer); } - //Type& operator*() { return *nonNull(mPointer); } - - operator BOOL() const { return mPointer != NULL; } - operator bool() const { return mPointer != NULL; } - bool operator!() const { return mPointer == NULL; } - bool isNull() const { return mPointer == NULL; } - bool notNull() const { return mPointer != NULL; } - - - operator Type*() const { return mPointer; } - operator const Type*() const { return mPointer; } - bool operator !=(Type* ptr) const { return (mPointer != ptr); } - bool operator ==(Type* ptr) const { return (mPointer == ptr); } - bool operator ==(const LLSafeHandle& ptr) const { return (mPointer == ptr.mPointer); } - bool operator < (const LLSafeHandle& ptr) const { return (mPointer < ptr.mPointer); } - bool operator > (const LLSafeHandle& ptr) const { return (mPointer > ptr.mPointer); } - - LLSafeHandle& operator =(Type* ptr) - { - assign(ptr); - return *this; - } - - LLSafeHandle& operator =(const LLSafeHandle& ptr) - { - assign(ptr.mPointer); - return *this; - } - - // support assignment up the type hierarchy. See Item 45 in Effective C++, 3rd Ed. - template - LLSafeHandle& operator =(const LLSafeHandle& ptr) - { - assign(ptr.get()); - return *this; - } + LLSafeHandle() : + mPointer(NULL) + { + } + + LLSafeHandle(Type* ptr) : + mPointer(NULL) + { + assign(ptr); + } + + LLSafeHandle(const LLSafeHandle& ptr) : + mPointer(NULL) + { + assign(ptr.mPointer); + } + + // support conversion up the type hierarchy. See Item 45 in Effective C++, 3rd Ed. + template + LLSafeHandle(const LLSafeHandle& ptr) : + mPointer(NULL) + { + assign(ptr.get()); + } + + ~LLSafeHandle() + { + unref(); + } + + const Type* operator->() const { return nonNull(mPointer); } + Type* operator->() { return nonNull(mPointer); } + + Type* get() const { return mPointer; } + void clear() { assign(NULL); } + // we disallow these operations as they expose our null objects to direct manipulation + // and bypass the reference counting semantics + //const Type& operator*() const { return *nonNull(mPointer); } + //Type& operator*() { return *nonNull(mPointer); } + + operator BOOL() const { return mPointer != NULL; } + operator bool() const { return mPointer != NULL; } + bool operator!() const { return mPointer == NULL; } + bool isNull() const { return mPointer == NULL; } + bool notNull() const { return mPointer != NULL; } + + + operator Type*() const { return mPointer; } + operator const Type*() const { return mPointer; } + bool operator !=(Type* ptr) const { return (mPointer != ptr); } + bool operator ==(Type* ptr) const { return (mPointer == ptr); } + bool operator ==(const LLSafeHandle& ptr) const { return (mPointer == ptr.mPointer); } + bool operator < (const LLSafeHandle& ptr) const { return (mPointer < ptr.mPointer); } + bool operator > (const LLSafeHandle& ptr) const { return (mPointer > ptr.mPointer); } + + LLSafeHandle& operator =(Type* ptr) + { + assign(ptr); + return *this; + } + + LLSafeHandle& operator =(const LLSafeHandle& ptr) + { + assign(ptr.mPointer); + return *this; + } + + // support assignment up the type hierarchy. See Item 45 in Effective C++, 3rd Ed. + template + LLSafeHandle& operator =(const LLSafeHandle& ptr) + { + assign(ptr.get()); + return *this; + } protected: - void ref() - { - if (mPointer) - { - mPointer->ref(); - } - } - - void unref() - { - if (mPointer) - { - Type *tempp = mPointer; - mPointer = NULL; - tempp->unref(); - if (mPointer != NULL) - { - LL_WARNS() << "Unreference did assignment to non-NULL because of destructor" << LL_ENDL; - unref(); - } - } - } - - void assign(Type* ptr) - { - if( mPointer != ptr ) - { - unref(); - mPointer = ptr; - ref(); - } - } - - // Define an LLSingleton whose sole purpose is to hold a "null instance" - // of the subject Type: the canonical instance to dereference if this - // LLSafeHandle actually holds a null pointer. We use LLSingleton - // specifically so that the "null instance" can be cleaned up at a well- - // defined time, specifically LLSingletonBase::deleteAll(). - // Of course, as with any LLSingleton, the "null instance" is only - // instantiated on demand -- in this case, if you actually try to - // dereference an LLSafeHandle containing null. - class NullInstanceHolder: public LLSingleton - { - LLSINGLETON_EMPTY_CTOR(NullInstanceHolder); - ~NullInstanceHolder() {} - public: - Type mNullInstance; - }; - - static Type* nonNull(Type* ptr) - { - return ptr? ptr : &NullInstanceHolder::instance().mNullInstance; - } + void ref() + { + if (mPointer) + { + mPointer->ref(); + } + } + + void unref() + { + if (mPointer) + { + Type *tempp = mPointer; + mPointer = NULL; + tempp->unref(); + if (mPointer != NULL) + { + LL_WARNS() << "Unreference did assignment to non-NULL because of destructor" << LL_ENDL; + unref(); + } + } + } + + void assign(Type* ptr) + { + if( mPointer != ptr ) + { + unref(); + mPointer = ptr; + ref(); + } + } + + // Define an LLSingleton whose sole purpose is to hold a "null instance" + // of the subject Type: the canonical instance to dereference if this + // LLSafeHandle actually holds a null pointer. We use LLSingleton + // specifically so that the "null instance" can be cleaned up at a well- + // defined time, specifically LLSingletonBase::deleteAll(). + // Of course, as with any LLSingleton, the "null instance" is only + // instantiated on demand -- in this case, if you actually try to + // dereference an LLSafeHandle containing null. + class NullInstanceHolder: public LLSingleton + { + LLSINGLETON_EMPTY_CTOR(NullInstanceHolder); + ~NullInstanceHolder() {} + public: + Type mNullInstance; + }; + + static Type* nonNull(Type* ptr) + { + return ptr? ptr : &NullInstanceHolder::instance().mNullInstance; + } protected: - Type* mPointer; + Type* mPointer; }; #endif diff --git a/indra/llcommon/llsd.cpp b/indra/llcommon/llsd.cpp index 590915e9d2..663ceac22b 100644 --- a/indra/llcommon/llsd.cpp +++ b/indra/llcommon/llsd.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llsd.cpp * @brief LLSD flexible data system * * $LicenseInfo:firstyear=2005&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -53,13 +53,13 @@ bool was_negative(size_t i) #endif #ifdef NAME_UNNAMED_NAMESPACE -namespace LLSDUnnamedNamespace +namespace LLSDUnnamedNamespace #else -namespace +namespace #endif { - class ImplMap; - class ImplArray; + class ImplMap; + class ImplArray; } #ifdef NAME_UNNAMED_NAMESPACE @@ -70,740 +70,740 @@ namespace llsd { // statics -S32 sLLSDAllocationCount = 0; +S32 sLLSDAllocationCount = 0; S32 sLLSDNetObjects = 0; } // namespace llsd -#define ALLOC_LLSD_OBJECT { llsd::sLLSDNetObjects++; llsd::sLLSDAllocationCount++; } -#define FREE_LLSD_OBJECT { llsd::sLLSDNetObjects--; } +#define ALLOC_LLSD_OBJECT { llsd::sLLSDNetObjects++; llsd::sLLSDAllocationCount++; } +#define FREE_LLSD_OBJECT { llsd::sLLSDNetObjects--; } class LLSD::Impl - /**< This class is the abstract base class of the implementation of LLSD - It provides the reference counting implementation, and the default - implementation of most methods for most data types. It also serves - as a working implementation of the Undefined type. - - */ + /**< This class is the abstract base class of the implementation of LLSD + It provides the reference counting implementation, and the default + implementation of most methods for most data types. It also serves + as a working implementation of the Undefined type. + + */ { protected: - Impl(); - - enum StaticAllocationMarker { STATIC_USAGE_COUNT = 0xFFFFFFFF }; - Impl(StaticAllocationMarker); - ///< This constructor is used for static objects and causes the - // suppresses adjusting the debugging counters when they are - // finally initialized. - - virtual ~Impl(); - - bool shared() const { return (mUseCount > 1) && (mUseCount != STATIC_USAGE_COUNT); } - - U32 mUseCount; + Impl(); + + enum StaticAllocationMarker { STATIC_USAGE_COUNT = 0xFFFFFFFF }; + Impl(StaticAllocationMarker); + ///< This constructor is used for static objects and causes the + // suppresses adjusting the debugging counters when they are + // finally initialized. + + virtual ~Impl(); + + bool shared() const { return (mUseCount > 1) && (mUseCount != STATIC_USAGE_COUNT); } + + U32 mUseCount; public: - static void reset(Impl*& var, Impl* impl); - ///< safely set var to refer to the new impl (possibly shared) - - static Impl& safe( Impl*); - static const Impl& safe(const Impl*); - ///< since a NULL Impl* is used for undefined, this ensures there is - // always an object you call virtual member functions on - - virtual ImplMap& makeMap(Impl*& var); - virtual ImplArray& makeArray(Impl*& var); - ///< sure var is a modifiable, non-shared map or array - - virtual LLSD::Type type() const { return LLSD::TypeUndefined; } - - static void assignUndefined(LLSD::Impl*& var); - static void assign(LLSD::Impl*& var, const LLSD::Impl* other); - - virtual void assign(Impl*& var, LLSD::Boolean); - virtual void assign(Impl*& var, LLSD::Integer); - virtual void assign(Impl*& var, LLSD::Real); - virtual void assign(Impl*& var, const LLSD::String&); - virtual void assign(Impl*& var, const LLSD::UUID&); - virtual void assign(Impl*& var, const LLSD::Date&); - virtual void assign(Impl*& var, const LLSD::URI&); - virtual void assign(Impl*& var, const LLSD::Binary&); - ///< If the receiver is the right type and unshared, these are simple - // data assignments, othewise the default implementation handless - // constructing the proper Impl subclass - - virtual Boolean asBoolean() const { return false; } - virtual Integer asInteger() const { return 0; } - virtual Real asReal() const { return 0.0; } - virtual String asString() const { return std::string(); } - virtual UUID asUUID() const { return LLUUID(); } - virtual Date asDate() const { return LLDate(); } - virtual URI asURI() const { return LLURI(); } - virtual const Binary& asBinary() const { static const std::vector empty; return empty; } - - virtual const String& asStringRef() const { static const std::string empty; return empty; } - - virtual bool has(const String&) const { return false; } - virtual LLSD get(const String&) const { return LLSD(); } - virtual LLSD getKeys() const { return LLSD::emptyArray(); } - virtual void erase(const String&) { } - virtual const LLSD& ref(const String&) const{ return undef(); } - - virtual size_t size() const { return 0; } - virtual LLSD get(size_t) const { return LLSD(); } - virtual void erase(size_t) { } - virtual const LLSD& ref(size_t) const { return undef(); } - - virtual LLSD::map_const_iterator beginMap() const { return endMap(); } - virtual LLSD::map_const_iterator endMap() const { static const std::map empty; return empty.end(); } - virtual LLSD::array_const_iterator beginArray() const { return endArray(); } - virtual LLSD::array_const_iterator endArray() const { static const std::vector empty; return empty.end(); } - - virtual void dumpStats() const; - virtual void calcStats(S32 type_counts[], S32 share_counts[]) const; - // Container subclasses contain LLSD objects, rather than directly - // containing Impl objects. This helper forwards through LLSD. - void calcStats(const LLSD& llsd, S32 type_counts[], S32 share_counts[]) const - { - safe(llsd.impl).calcStats(type_counts, share_counts); - } - - static const Impl& getImpl(const LLSD& llsd) { return safe(llsd.impl); } - static Impl& getImpl(LLSD& llsd) { return safe(llsd.impl); } - - static const LLSD& undef(); - - static U32 sAllocationCount; - static U32 sOutstandingCount; + static void reset(Impl*& var, Impl* impl); + ///< safely set var to refer to the new impl (possibly shared) + + static Impl& safe( Impl*); + static const Impl& safe(const Impl*); + ///< since a NULL Impl* is used for undefined, this ensures there is + // always an object you call virtual member functions on + + virtual ImplMap& makeMap(Impl*& var); + virtual ImplArray& makeArray(Impl*& var); + ///< sure var is a modifiable, non-shared map or array + + virtual LLSD::Type type() const { return LLSD::TypeUndefined; } + + static void assignUndefined(LLSD::Impl*& var); + static void assign(LLSD::Impl*& var, const LLSD::Impl* other); + + virtual void assign(Impl*& var, LLSD::Boolean); + virtual void assign(Impl*& var, LLSD::Integer); + virtual void assign(Impl*& var, LLSD::Real); + virtual void assign(Impl*& var, const LLSD::String&); + virtual void assign(Impl*& var, const LLSD::UUID&); + virtual void assign(Impl*& var, const LLSD::Date&); + virtual void assign(Impl*& var, const LLSD::URI&); + virtual void assign(Impl*& var, const LLSD::Binary&); + ///< If the receiver is the right type and unshared, these are simple + // data assignments, othewise the default implementation handless + // constructing the proper Impl subclass + + virtual Boolean asBoolean() const { return false; } + virtual Integer asInteger() const { return 0; } + virtual Real asReal() const { return 0.0; } + virtual String asString() const { return std::string(); } + virtual UUID asUUID() const { return LLUUID(); } + virtual Date asDate() const { return LLDate(); } + virtual URI asURI() const { return LLURI(); } + virtual const Binary& asBinary() const { static const std::vector empty; return empty; } + + virtual const String& asStringRef() const { static const std::string empty; return empty; } + + virtual bool has(const String&) const { return false; } + virtual LLSD get(const String&) const { return LLSD(); } + virtual LLSD getKeys() const { return LLSD::emptyArray(); } + virtual void erase(const String&) { } + virtual const LLSD& ref(const String&) const{ return undef(); } + + virtual size_t size() const { return 0; } + virtual LLSD get(size_t) const { return LLSD(); } + virtual void erase(size_t) { } + virtual const LLSD& ref(size_t) const { return undef(); } + + virtual LLSD::map_const_iterator beginMap() const { return endMap(); } + virtual LLSD::map_const_iterator endMap() const { static const std::map empty; return empty.end(); } + virtual LLSD::array_const_iterator beginArray() const { return endArray(); } + virtual LLSD::array_const_iterator endArray() const { static const std::vector empty; return empty.end(); } + + virtual void dumpStats() const; + virtual void calcStats(S32 type_counts[], S32 share_counts[]) const; + // Container subclasses contain LLSD objects, rather than directly + // containing Impl objects. This helper forwards through LLSD. + void calcStats(const LLSD& llsd, S32 type_counts[], S32 share_counts[]) const + { + safe(llsd.impl).calcStats(type_counts, share_counts); + } + + static const Impl& getImpl(const LLSD& llsd) { return safe(llsd.impl); } + static Impl& getImpl(LLSD& llsd) { return safe(llsd.impl); } + + static const LLSD& undef(); + + static U32 sAllocationCount; + static U32 sOutstandingCount; }; #ifdef NAME_UNNAMED_NAMESPACE -namespace LLSDUnnamedNamespace +namespace LLSDUnnamedNamespace #else -namespace +namespace #endif { - template - class ImplBase : public LLSD::Impl - ///< This class handles most of the work for a subclass of Impl - // for a given simple data type. Subclasses of this provide the - // conversion functions and a constructor. - { - protected: - Data mValue; - - typedef ImplBase Base; - - public: - ImplBase(DataRef value) : mValue(value) { } - - virtual LLSD::Type type() const { return T; } - - using LLSD::Impl::assign; // Unhiding base class virtuals... - virtual void assign(LLSD::Impl*& var, DataRef value) { - if (shared()) - { - Impl::assign(var, value); - } - else - { - mValue = value; - } - } - }; - - - class ImplBoolean - : public ImplBase - { - public: - ImplBoolean(LLSD::Boolean v) : Base(v) { } - - virtual LLSD::Boolean asBoolean() const { return mValue; } - virtual LLSD::Integer asInteger() const { return mValue ? 1 : 0; } - virtual LLSD::Real asReal() const { return mValue ? 1 : 0; } - virtual LLSD::String asString() const; - }; - - LLSD::String ImplBoolean::asString() const - // *NOTE: The reason that false is not converted to "false" is - // because that would break roundtripping, - // e.g. LLSD(false).asString().asBoolean(). There are many - // reasons for wanting LLSD("false").asBoolean() == true, such - // as "everything else seems to work that way". - { return mValue ? "true" : ""; } - - - class ImplInteger - : public ImplBase - { - public: - ImplInteger(LLSD::Integer v) : Base(v) { } - - virtual LLSD::Boolean asBoolean() const { return mValue != 0; } - virtual LLSD::Integer asInteger() const { return mValue; } - virtual LLSD::Real asReal() const { return mValue; } - virtual LLSD::String asString() const; - }; - - LLSD::String ImplInteger::asString() const - { return llformat("%d", mValue); } - - - class ImplReal - : public ImplBase - { - public: - ImplReal(LLSD::Real v) : Base(v) { } - - virtual LLSD::Boolean asBoolean() const; - virtual LLSD::Integer asInteger() const; - virtual LLSD::Real asReal() const { return mValue; } - virtual LLSD::String asString() const; - }; - - LLSD::Boolean ImplReal::asBoolean() const - { return !llisnan(mValue) && mValue != 0.0; } - - LLSD::Integer ImplReal::asInteger() const - { return !llisnan(mValue) ? (LLSD::Integer)mValue : 0; } - - LLSD::String ImplReal::asString() const - { return llformat("%lg", mValue); } - - - class ImplString - : public ImplBase - { - public: - ImplString(const LLSD::String& v) : Base(v) { } - - virtual LLSD::Boolean asBoolean() const { return !mValue.empty(); } - virtual LLSD::Integer asInteger() const; - virtual LLSD::Real asReal() const; - virtual LLSD::String asString() const { return mValue; } - virtual LLSD::UUID asUUID() const { return LLUUID(mValue); } - virtual LLSD::Date asDate() const { return LLDate(mValue); } - virtual LLSD::URI asURI() const { return LLURI(mValue); } - virtual size_t size() const { return mValue.size(); } - virtual const LLSD::String& asStringRef() const { return mValue; } - }; - - LLSD::Integer ImplString::asInteger() const - { - // This must treat "1.23" not as an error, but as a number, which is - // then truncated down to an integer. Hence, this code doesn't call - // std::istringstream::operator>>(int&), which would not consume the - // ".23" portion. - - return (int)asReal(); - } - - LLSD::Real ImplString::asReal() const - { - F64 v = 0.0; - std::istringstream i_stream(mValue); - i_stream >> v; - - // we would probably like to ignore all trailing whitespace as - // well, but for now, simply eat the next character, and make - // sure we reached the end of the string. - // *NOTE: gcc 2.95 does not generate an eof() event on the - // stream operation above, so we manually get here to force it - // across platforms. - int c = i_stream.get(); - return ((EOF ==c) ? v : 0.0); - } - - - class ImplUUID - : public ImplBase - { - public: - ImplUUID(const LLSD::UUID& v) : Base(v) { } - - virtual LLSD::String asString() const{ return mValue.asString(); } - virtual LLSD::UUID asUUID() const { return mValue; } - }; - - - class ImplDate - : public ImplBase - { - public: - ImplDate(const LLSD::Date& v) - : ImplBase(v) - { } - - virtual LLSD::Integer asInteger() const - { - return (LLSD::Integer)(mValue.secondsSinceEpoch()); - } - virtual LLSD::Real asReal() const - { - return mValue.secondsSinceEpoch(); - } - virtual LLSD::String asString() const{ return mValue.asString(); } - virtual LLSD::Date asDate() const { return mValue; } - }; - - - class ImplURI - : public ImplBase - { - public: - ImplURI(const LLSD::URI& v) : Base(v) { } - - virtual LLSD::String asString() const{ return mValue.asString(); } - virtual LLSD::URI asURI() const { return mValue; } - }; - - - class ImplBinary - : public ImplBase - { - public: - ImplBinary(const LLSD::Binary& v) : Base(v) { } - - virtual const LLSD::Binary& asBinary() const{ return mValue; } - }; - - - class ImplMap : public LLSD::Impl - { - private: - typedef std::map DataMap; - - DataMap mData; - - protected: - ImplMap(const DataMap& data) : mData(data) { } - - public: - ImplMap() { } - - virtual ImplMap& makeMap(LLSD::Impl*&); - - virtual LLSD::Type type() const { return LLSD::TypeMap; } - - virtual LLSD::Boolean asBoolean() const { return !mData.empty(); } - - virtual bool has(const LLSD::String&) const; - - using LLSD::Impl::get; // Unhiding get(size_t) - using LLSD::Impl::erase; // Unhiding erase(size_t) - using LLSD::Impl::ref; // Unhiding ref(size_t) - virtual LLSD get(const LLSD::String&) const; - virtual LLSD getKeys() const; - void insert(const LLSD::String& k, const LLSD& v); - virtual void erase(const LLSD::String&); - LLSD& ref(const LLSD::String&); - virtual const LLSD& ref(const LLSD::String&) const; - - virtual size_t size() const { return mData.size(); } - - LLSD::map_iterator beginMap() { return mData.begin(); } - LLSD::map_iterator endMap() { return mData.end(); } - virtual LLSD::map_const_iterator beginMap() const { return mData.begin(); } - virtual LLSD::map_const_iterator endMap() const { return mData.end(); } - - virtual void dumpStats() const; - virtual void calcStats(S32 type_counts[], S32 share_counts[]) const; - }; - - ImplMap& ImplMap::makeMap(LLSD::Impl*& var) - { + template + class ImplBase : public LLSD::Impl + ///< This class handles most of the work for a subclass of Impl + // for a given simple data type. Subclasses of this provide the + // conversion functions and a constructor. + { + protected: + Data mValue; + + typedef ImplBase Base; + + public: + ImplBase(DataRef value) : mValue(value) { } + + virtual LLSD::Type type() const { return T; } + + using LLSD::Impl::assign; // Unhiding base class virtuals... + virtual void assign(LLSD::Impl*& var, DataRef value) { + if (shared()) + { + Impl::assign(var, value); + } + else + { + mValue = value; + } + } + }; + + + class ImplBoolean + : public ImplBase + { + public: + ImplBoolean(LLSD::Boolean v) : Base(v) { } + + virtual LLSD::Boolean asBoolean() const { return mValue; } + virtual LLSD::Integer asInteger() const { return mValue ? 1 : 0; } + virtual LLSD::Real asReal() const { return mValue ? 1 : 0; } + virtual LLSD::String asString() const; + }; + + LLSD::String ImplBoolean::asString() const + // *NOTE: The reason that false is not converted to "false" is + // because that would break roundtripping, + // e.g. LLSD(false).asString().asBoolean(). There are many + // reasons for wanting LLSD("false").asBoolean() == true, such + // as "everything else seems to work that way". + { return mValue ? "true" : ""; } + + + class ImplInteger + : public ImplBase + { + public: + ImplInteger(LLSD::Integer v) : Base(v) { } + + virtual LLSD::Boolean asBoolean() const { return mValue != 0; } + virtual LLSD::Integer asInteger() const { return mValue; } + virtual LLSD::Real asReal() const { return mValue; } + virtual LLSD::String asString() const; + }; + + LLSD::String ImplInteger::asString() const + { return llformat("%d", mValue); } + + + class ImplReal + : public ImplBase + { + public: + ImplReal(LLSD::Real v) : Base(v) { } + + virtual LLSD::Boolean asBoolean() const; + virtual LLSD::Integer asInteger() const; + virtual LLSD::Real asReal() const { return mValue; } + virtual LLSD::String asString() const; + }; + + LLSD::Boolean ImplReal::asBoolean() const + { return !llisnan(mValue) && mValue != 0.0; } + + LLSD::Integer ImplReal::asInteger() const + { return !llisnan(mValue) ? (LLSD::Integer)mValue : 0; } + + LLSD::String ImplReal::asString() const + { return llformat("%lg", mValue); } + + + class ImplString + : public ImplBase + { + public: + ImplString(const LLSD::String& v) : Base(v) { } + + virtual LLSD::Boolean asBoolean() const { return !mValue.empty(); } + virtual LLSD::Integer asInteger() const; + virtual LLSD::Real asReal() const; + virtual LLSD::String asString() const { return mValue; } + virtual LLSD::UUID asUUID() const { return LLUUID(mValue); } + virtual LLSD::Date asDate() const { return LLDate(mValue); } + virtual LLSD::URI asURI() const { return LLURI(mValue); } + virtual size_t size() const { return mValue.size(); } + virtual const LLSD::String& asStringRef() const { return mValue; } + }; + + LLSD::Integer ImplString::asInteger() const + { + // This must treat "1.23" not as an error, but as a number, which is + // then truncated down to an integer. Hence, this code doesn't call + // std::istringstream::operator>>(int&), which would not consume the + // ".23" portion. + + return (int)asReal(); + } + + LLSD::Real ImplString::asReal() const + { + F64 v = 0.0; + std::istringstream i_stream(mValue); + i_stream >> v; + + // we would probably like to ignore all trailing whitespace as + // well, but for now, simply eat the next character, and make + // sure we reached the end of the string. + // *NOTE: gcc 2.95 does not generate an eof() event on the + // stream operation above, so we manually get here to force it + // across platforms. + int c = i_stream.get(); + return ((EOF ==c) ? v : 0.0); + } + + + class ImplUUID + : public ImplBase + { + public: + ImplUUID(const LLSD::UUID& v) : Base(v) { } + + virtual LLSD::String asString() const{ return mValue.asString(); } + virtual LLSD::UUID asUUID() const { return mValue; } + }; + + + class ImplDate + : public ImplBase + { + public: + ImplDate(const LLSD::Date& v) + : ImplBase(v) + { } + + virtual LLSD::Integer asInteger() const + { + return (LLSD::Integer)(mValue.secondsSinceEpoch()); + } + virtual LLSD::Real asReal() const + { + return mValue.secondsSinceEpoch(); + } + virtual LLSD::String asString() const{ return mValue.asString(); } + virtual LLSD::Date asDate() const { return mValue; } + }; + + + class ImplURI + : public ImplBase + { + public: + ImplURI(const LLSD::URI& v) : Base(v) { } + + virtual LLSD::String asString() const{ return mValue.asString(); } + virtual LLSD::URI asURI() const { return mValue; } + }; + + + class ImplBinary + : public ImplBase + { + public: + ImplBinary(const LLSD::Binary& v) : Base(v) { } + + virtual const LLSD::Binary& asBinary() const{ return mValue; } + }; + + + class ImplMap : public LLSD::Impl + { + private: + typedef std::map DataMap; + + DataMap mData; + + protected: + ImplMap(const DataMap& data) : mData(data) { } + + public: + ImplMap() { } + + virtual ImplMap& makeMap(LLSD::Impl*&); + + virtual LLSD::Type type() const { return LLSD::TypeMap; } + + virtual LLSD::Boolean asBoolean() const { return !mData.empty(); } + + virtual bool has(const LLSD::String&) const; + + using LLSD::Impl::get; // Unhiding get(size_t) + using LLSD::Impl::erase; // Unhiding erase(size_t) + using LLSD::Impl::ref; // Unhiding ref(size_t) + virtual LLSD get(const LLSD::String&) const; + virtual LLSD getKeys() const; + void insert(const LLSD::String& k, const LLSD& v); + virtual void erase(const LLSD::String&); + LLSD& ref(const LLSD::String&); + virtual const LLSD& ref(const LLSD::String&) const; + + virtual size_t size() const { return mData.size(); } + + LLSD::map_iterator beginMap() { return mData.begin(); } + LLSD::map_iterator endMap() { return mData.end(); } + virtual LLSD::map_const_iterator beginMap() const { return mData.begin(); } + virtual LLSD::map_const_iterator endMap() const { return mData.end(); } + + virtual void dumpStats() const; + virtual void calcStats(S32 type_counts[], S32 share_counts[]) const; + }; + + ImplMap& ImplMap::makeMap(LLSD::Impl*& var) + { LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD; - if (shared()) - { - ImplMap* i = new ImplMap(mData); - Impl::assign(var, i); - return *i; - } - else - { - return *this; - } - } - - bool ImplMap::has(const LLSD::String& k) const - { + if (shared()) + { + ImplMap* i = new ImplMap(mData); + Impl::assign(var, i); + return *i; + } + else + { + return *this; + } + } + + bool ImplMap::has(const LLSD::String& k) const + { LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD; - DataMap::const_iterator i = mData.find(k); - return i != mData.end(); - } - - LLSD ImplMap::get(const LLSD::String& k) const - { + DataMap::const_iterator i = mData.find(k); + return i != mData.end(); + } + + LLSD ImplMap::get(const LLSD::String& k) const + { LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD; - DataMap::const_iterator i = mData.find(k); - return (i != mData.end()) ? i->second : LLSD(); - } + DataMap::const_iterator i = mData.find(k); + return (i != mData.end()) ? i->second : LLSD(); + } - LLSD ImplMap::getKeys() const - { + LLSD ImplMap::getKeys() const + { LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD; - LLSD keys = LLSD::emptyArray(); - DataMap::const_iterator iter = mData.begin(); - while (iter != mData.end()) - { - keys.append((*iter).first); - iter++; - } - return keys; - } - - void ImplMap::insert(const LLSD::String& k, const LLSD& v) - { + LLSD keys = LLSD::emptyArray(); + DataMap::const_iterator iter = mData.begin(); + while (iter != mData.end()) + { + keys.append((*iter).first); + iter++; + } + return keys; + } + + void ImplMap::insert(const LLSD::String& k, const LLSD& v) + { LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD; - mData.insert(DataMap::value_type(k, v)); - } - - void ImplMap::erase(const LLSD::String& k) - { + mData.insert(DataMap::value_type(k, v)); + } + + void ImplMap::erase(const LLSD::String& k) + { LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD; - mData.erase(k); - } - - LLSD& ImplMap::ref(const LLSD::String& k) - { - return mData[k]; - } - - const LLSD& ImplMap::ref(const LLSD::String& k) const - { - DataMap::const_iterator i = mData.lower_bound(k); - if (i == mData.end() || mData.key_comp()(k, i->first)) - { - return undef(); - } - - return i->second; - } - - void ImplMap::dumpStats() const - { - std::cout << "Map size: " << mData.size() << std::endl; - - std::cout << "LLSD Net Objects: " << llsd::sLLSDNetObjects << std::endl; - std::cout << "LLSD allocations: " << llsd::sLLSDAllocationCount << std::endl; - - std::cout << "LLSD::Impl Net Objects: " << sOutstandingCount << std::endl; - std::cout << "LLSD::Impl allocations: " << sAllocationCount << std::endl; - - Impl::dumpStats(); - } - - void ImplMap::calcStats(S32 type_counts[], S32 share_counts[]) const - { - LLSD::map_const_iterator iter = beginMap(); - while (iter != endMap()) - { - //std::cout << " " << (*iter).first << ": " << (*iter).second << std::endl; - Impl::calcStats((*iter).second, type_counts, share_counts); - iter++; - } - - // Add in the values for this map - Impl::calcStats(type_counts, share_counts); - } - - - class ImplArray : public LLSD::Impl - { - private: - typedef std::vector DataVector; - - DataVector mData; - - protected: - ImplArray(const DataVector& data) : mData(data) { } - - public: - ImplArray() { } - - virtual ImplArray& makeArray(Impl*&); - - virtual LLSD::Type type() const { return LLSD::TypeArray; } - - virtual LLSD::Boolean asBoolean() const { return !mData.empty(); } - - using LLSD::Impl::get; // Unhiding get(LLSD::String) - using LLSD::Impl::erase; // Unhiding erase(LLSD::String) - using LLSD::Impl::ref; // Unhiding ref(LLSD::String) - virtual size_t size() const; - virtual LLSD get(size_t) const; - void set(size_t, const LLSD&); - void insert(size_t, const LLSD&); - LLSD& append(const LLSD&); - virtual void erase(size_t); - LLSD& ref(size_t); - virtual const LLSD& ref(size_t) const; - - LLSD::array_iterator beginArray() { return mData.begin(); } - LLSD::array_iterator endArray() { return mData.end(); } - LLSD::reverse_array_iterator rbeginArray() { return mData.rbegin(); } - LLSD::reverse_array_iterator rendArray() { return mData.rend(); } - virtual LLSD::array_const_iterator beginArray() const { return mData.begin(); } - virtual LLSD::array_const_iterator endArray() const { return mData.end(); } - - virtual void calcStats(S32 type_counts[], S32 share_counts[]) const; - }; - - ImplArray& ImplArray::makeArray(Impl*& var) - { - if (shared()) - { - ImplArray* i = new ImplArray(mData); - Impl::assign(var, i); - return *i; - } - else - { - return *this; - } - } - - size_t ImplArray::size() const { return mData.size(); } - - LLSD ImplArray::get(size_t i) const - { - NEGATIVE_RETURN(i, LLSD()); - DataVector::size_type index = i; - - return (index < mData.size()) ? mData[index] : LLSD(); - } - - void ImplArray::set(size_t i, const LLSD& v) - { - NEGATIVE_EXIT(i); - DataVector::size_type index = i; - - if (index >= mData.size()) - { - mData.resize(index + 1); - } - - mData[index] = v; - } - - void ImplArray::insert(size_t i, const LLSD& v) - { - NEGATIVE_EXIT(i); - DataVector::size_type index = i; - - if (index >= mData.size()) // tbd - sanity check limit for index ? - { - mData.resize(index + 1); - } - - mData.insert(mData.begin() + index, v); - } - - LLSD& ImplArray::append(const LLSD& v) - { - mData.push_back(v); - return mData.back(); - } - - void ImplArray::erase(size_t i) - { - NEGATIVE_EXIT(i); - DataVector::size_type index = i; - - if (index < mData.size()) - { - mData.erase(mData.begin() + index); - } - } - - LLSD& ImplArray::ref(size_t i) - { - DataVector::size_type index = was_negative(i)? 0 : i; - - if (index >= mData.size()) - { - mData.resize(index + 1); - } - - return mData[index]; - } - - const LLSD& ImplArray::ref(size_t i) const - { - NEGATIVE_RETURN(i, undef()); - DataVector::size_type index = i; - - if (index >= mData.size()) - { - return undef(); - } - - return mData[index]; - } - - void ImplArray::calcStats(S32 type_counts[], S32 share_counts[]) const - { - LLSD::array_const_iterator iter = beginArray(); - while (iter != endArray()) - { // Add values for all items held in the array - Impl::calcStats((*iter), type_counts, share_counts); - iter++; - } - - // Add in the values for this array - Impl::calcStats(type_counts, share_counts); - } + mData.erase(k); + } + + LLSD& ImplMap::ref(const LLSD::String& k) + { + return mData[k]; + } + + const LLSD& ImplMap::ref(const LLSD::String& k) const + { + DataMap::const_iterator i = mData.lower_bound(k); + if (i == mData.end() || mData.key_comp()(k, i->first)) + { + return undef(); + } + + return i->second; + } + + void ImplMap::dumpStats() const + { + std::cout << "Map size: " << mData.size() << std::endl; + + std::cout << "LLSD Net Objects: " << llsd::sLLSDNetObjects << std::endl; + std::cout << "LLSD allocations: " << llsd::sLLSDAllocationCount << std::endl; + + std::cout << "LLSD::Impl Net Objects: " << sOutstandingCount << std::endl; + std::cout << "LLSD::Impl allocations: " << sAllocationCount << std::endl; + + Impl::dumpStats(); + } + + void ImplMap::calcStats(S32 type_counts[], S32 share_counts[]) const + { + LLSD::map_const_iterator iter = beginMap(); + while (iter != endMap()) + { + //std::cout << " " << (*iter).first << ": " << (*iter).second << std::endl; + Impl::calcStats((*iter).second, type_counts, share_counts); + iter++; + } + + // Add in the values for this map + Impl::calcStats(type_counts, share_counts); + } + + + class ImplArray : public LLSD::Impl + { + private: + typedef std::vector DataVector; + + DataVector mData; + + protected: + ImplArray(const DataVector& data) : mData(data) { } + + public: + ImplArray() { } + + virtual ImplArray& makeArray(Impl*&); + + virtual LLSD::Type type() const { return LLSD::TypeArray; } + + virtual LLSD::Boolean asBoolean() const { return !mData.empty(); } + + using LLSD::Impl::get; // Unhiding get(LLSD::String) + using LLSD::Impl::erase; // Unhiding erase(LLSD::String) + using LLSD::Impl::ref; // Unhiding ref(LLSD::String) + virtual size_t size() const; + virtual LLSD get(size_t) const; + void set(size_t, const LLSD&); + void insert(size_t, const LLSD&); + LLSD& append(const LLSD&); + virtual void erase(size_t); + LLSD& ref(size_t); + virtual const LLSD& ref(size_t) const; + + LLSD::array_iterator beginArray() { return mData.begin(); } + LLSD::array_iterator endArray() { return mData.end(); } + LLSD::reverse_array_iterator rbeginArray() { return mData.rbegin(); } + LLSD::reverse_array_iterator rendArray() { return mData.rend(); } + virtual LLSD::array_const_iterator beginArray() const { return mData.begin(); } + virtual LLSD::array_const_iterator endArray() const { return mData.end(); } + + virtual void calcStats(S32 type_counts[], S32 share_counts[]) const; + }; + + ImplArray& ImplArray::makeArray(Impl*& var) + { + if (shared()) + { + ImplArray* i = new ImplArray(mData); + Impl::assign(var, i); + return *i; + } + else + { + return *this; + } + } + + size_t ImplArray::size() const { return mData.size(); } + + LLSD ImplArray::get(size_t i) const + { + NEGATIVE_RETURN(i, LLSD()); + DataVector::size_type index = i; + + return (index < mData.size()) ? mData[index] : LLSD(); + } + + void ImplArray::set(size_t i, const LLSD& v) + { + NEGATIVE_EXIT(i); + DataVector::size_type index = i; + + if (index >= mData.size()) + { + mData.resize(index + 1); + } + + mData[index] = v; + } + + void ImplArray::insert(size_t i, const LLSD& v) + { + NEGATIVE_EXIT(i); + DataVector::size_type index = i; + + if (index >= mData.size()) // tbd - sanity check limit for index ? + { + mData.resize(index + 1); + } + + mData.insert(mData.begin() + index, v); + } + + LLSD& ImplArray::append(const LLSD& v) + { + mData.push_back(v); + return mData.back(); + } + + void ImplArray::erase(size_t i) + { + NEGATIVE_EXIT(i); + DataVector::size_type index = i; + + if (index < mData.size()) + { + mData.erase(mData.begin() + index); + } + } + + LLSD& ImplArray::ref(size_t i) + { + DataVector::size_type index = was_negative(i)? 0 : i; + + if (index >= mData.size()) + { + mData.resize(index + 1); + } + + return mData[index]; + } + + const LLSD& ImplArray::ref(size_t i) const + { + NEGATIVE_RETURN(i, undef()); + DataVector::size_type index = i; + + if (index >= mData.size()) + { + return undef(); + } + + return mData[index]; + } + + void ImplArray::calcStats(S32 type_counts[], S32 share_counts[]) const + { + LLSD::array_const_iterator iter = beginArray(); + while (iter != endArray()) + { // Add values for all items held in the array + Impl::calcStats((*iter), type_counts, share_counts); + iter++; + } + + // Add in the values for this array + Impl::calcStats(type_counts, share_counts); + } } LLSD::Impl::Impl() - : mUseCount(0) + : mUseCount(0) { - ++sAllocationCount; - ++sOutstandingCount; + ++sAllocationCount; + ++sOutstandingCount; } LLSD::Impl::Impl(StaticAllocationMarker) - : mUseCount(0) + : mUseCount(0) { } LLSD::Impl::~Impl() { - --sOutstandingCount; + --sOutstandingCount; } void LLSD::Impl::reset(Impl*& var, Impl* impl) { - if (impl && impl->mUseCount != STATIC_USAGE_COUNT) - { - ++impl->mUseCount; - } - if (var && var->mUseCount != STATIC_USAGE_COUNT && --var->mUseCount == 0) - { - delete var; - } - var = impl; + if (impl && impl->mUseCount != STATIC_USAGE_COUNT) + { + ++impl->mUseCount; + } + if (var && var->mUseCount != STATIC_USAGE_COUNT && --var->mUseCount == 0) + { + delete var; + } + var = impl; } LLSD::Impl& LLSD::Impl::safe(Impl* impl) { - static Impl theUndefined(STATIC_USAGE_COUNT); - return impl ? *impl : theUndefined; + static Impl theUndefined(STATIC_USAGE_COUNT); + return impl ? *impl : theUndefined; } const LLSD::Impl& LLSD::Impl::safe(const Impl* impl) { - static Impl theUndefined(STATIC_USAGE_COUNT); - return impl ? *impl : theUndefined; + static Impl theUndefined(STATIC_USAGE_COUNT); + return impl ? *impl : theUndefined; } ImplMap& LLSD::Impl::makeMap(Impl*& var) { LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD; - ImplMap* im = new ImplMap; - reset(var, im); - return *im; + ImplMap* im = new ImplMap; + reset(var, im); + return *im; } ImplArray& LLSD::Impl::makeArray(Impl*& var) { - ImplArray* ia = new ImplArray; - reset(var, ia); - return *ia; + ImplArray* ia = new ImplArray; + reset(var, ia); + return *ia; } void LLSD::Impl::assign(Impl*& var, const Impl* other) { - reset(var, const_cast(other)); + reset(var, const_cast(other)); } void LLSD::Impl::assignUndefined(Impl*& var) { - reset(var, 0); + reset(var, 0); } void LLSD::Impl::assign(Impl*& var, LLSD::Boolean v) { - reset(var, new ImplBoolean(v)); + reset(var, new ImplBoolean(v)); } void LLSD::Impl::assign(Impl*& var, LLSD::Integer v) { - reset(var, new ImplInteger(v)); + reset(var, new ImplInteger(v)); } void LLSD::Impl::assign(Impl*& var, LLSD::Real v) { - reset(var, new ImplReal(v)); + reset(var, new ImplReal(v)); } void LLSD::Impl::assign(Impl*& var, const LLSD::String& v) { - reset(var, new ImplString(v)); + reset(var, new ImplString(v)); } void LLSD::Impl::assign(Impl*& var, const LLSD::UUID& v) { - reset(var, new ImplUUID(v)); + reset(var, new ImplUUID(v)); } void LLSD::Impl::assign(Impl*& var, const LLSD::Date& v) { - reset(var, new ImplDate(v)); + reset(var, new ImplDate(v)); } void LLSD::Impl::assign(Impl*& var, const LLSD::URI& v) { - reset(var, new ImplURI(v)); + reset(var, new ImplURI(v)); } void LLSD::Impl::assign(Impl*& var, const LLSD::Binary& v) { - reset(var, new ImplBinary(v)); + reset(var, new ImplBinary(v)); } const LLSD& LLSD::Impl::undef() { - static const LLSD immutableUndefined; - return immutableUndefined; + static const LLSD immutableUndefined; + return immutableUndefined; } void LLSD::Impl::dumpStats() const { - S32 type_counts[LLSD::TypeLLSDNumTypes + 1]; - memset(&type_counts, 0, sizeof(type_counts)); - - S32 share_counts[LLSD::TypeLLSDNumTypes + 1]; - memset(&share_counts, 0, sizeof(share_counts)); - - // Add info from all the values this object has - calcStats(type_counts, share_counts); - - S32 type_index = LLSD::TypeLLSDTypeBegin; - while (type_index != LLSD::TypeLLSDTypeEnd) - { - std::cout << LLSD::typeString((LLSD::Type)type_index) << " type " - << type_counts[type_index] << " objects, " - << share_counts[type_index] << " shared" - << std::endl; - type_index++; - } + S32 type_counts[LLSD::TypeLLSDNumTypes + 1]; + memset(&type_counts, 0, sizeof(type_counts)); + + S32 share_counts[LLSD::TypeLLSDNumTypes + 1]; + memset(&share_counts, 0, sizeof(share_counts)); + + // Add info from all the values this object has + calcStats(type_counts, share_counts); + + S32 type_index = LLSD::TypeLLSDTypeBegin; + while (type_index != LLSD::TypeLLSDTypeEnd) + { + std::cout << LLSD::typeString((LLSD::Type)type_index) << " type " + << type_counts[type_index] << " objects, " + << share_counts[type_index] << " shared" + << std::endl; + type_index++; + } } void LLSD::Impl::calcStats(S32 type_counts[], S32 share_counts[]) const { - S32 tp = S32(type()); - if (0 <= tp && tp < LLSD::TypeLLSDNumTypes) - { - type_counts[tp]++; - if (shared()) - { - share_counts[tp]++; - } - } + S32 tp = S32(type()); + if (0 <= tp && tp < LLSD::TypeLLSDNumTypes) + { + type_counts[tp]++; + if (shared()) + { + share_counts[tp]++; + } + } } @@ -813,218 +813,218 @@ U32 LLSD::Impl::sOutstandingCount = 0; #ifdef NAME_UNNAMED_NAMESPACE -namespace LLSDUnnamedNamespace +namespace LLSDUnnamedNamespace #else -namespace +namespace #endif { - inline LLSD::Impl& safe(LLSD::Impl* impl) - { return LLSD::Impl::safe(impl); } - - inline ImplMap& makeMap(LLSD::Impl*& var) - { return safe(var).makeMap(var); } - - inline ImplArray& makeArray(LLSD::Impl*& var) - { return safe(var).makeArray(var); } + inline LLSD::Impl& safe(LLSD::Impl* impl) + { return LLSD::Impl::safe(impl); } + + inline ImplMap& makeMap(LLSD::Impl*& var) + { return safe(var).makeMap(var); } + + inline ImplArray& makeArray(LLSD::Impl*& var) + { return safe(var).makeArray(var); } } -LLSD::LLSD() : impl(0) { ALLOC_LLSD_OBJECT; } -LLSD::~LLSD() { FREE_LLSD_OBJECT; Impl::reset(impl, 0); } +LLSD::LLSD() : impl(0) { ALLOC_LLSD_OBJECT; } +LLSD::~LLSD() { FREE_LLSD_OBJECT; Impl::reset(impl, 0); } LLSD::LLSD(const LLSD& other) : impl(0) { ALLOC_LLSD_OBJECT; assign(other); } -void LLSD::assign(const LLSD& other) { Impl::assign(impl, other.impl); } +void LLSD::assign(const LLSD& other) { Impl::assign(impl, other.impl); } -void LLSD::clear() { Impl::assignUndefined(impl); } +void LLSD::clear() { Impl::assignUndefined(impl); } -LLSD::Type LLSD::type() const { return safe(impl).type(); } +LLSD::Type LLSD::type() const { return safe(impl).type(); } // Scalar Constructors -LLSD::LLSD(Boolean v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); } -LLSD::LLSD(Integer v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); } -LLSD::LLSD(Real v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); } -LLSD::LLSD(const UUID& v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); } -LLSD::LLSD(const String& v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); } -LLSD::LLSD(const Date& v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); } -LLSD::LLSD(const URI& v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); } -LLSD::LLSD(const Binary& v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); } +LLSD::LLSD(Boolean v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); } +LLSD::LLSD(Integer v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); } +LLSD::LLSD(Real v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); } +LLSD::LLSD(const UUID& v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); } +LLSD::LLSD(const String& v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); } +LLSD::LLSD(const Date& v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); } +LLSD::LLSD(const URI& v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); } +LLSD::LLSD(const Binary& v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); } // Scalar Assignment -void LLSD::assign(Boolean v) { safe(impl).assign(impl, v); } -void LLSD::assign(Integer v) { safe(impl).assign(impl, v); } -void LLSD::assign(Real v) { safe(impl).assign(impl, v); } -void LLSD::assign(const String& v) { safe(impl).assign(impl, v); } -void LLSD::assign(const UUID& v) { safe(impl).assign(impl, v); } -void LLSD::assign(const Date& v) { safe(impl).assign(impl, v); } -void LLSD::assign(const URI& v) { safe(impl).assign(impl, v); } -void LLSD::assign(const Binary& v) { safe(impl).assign(impl, v); } +void LLSD::assign(Boolean v) { safe(impl).assign(impl, v); } +void LLSD::assign(Integer v) { safe(impl).assign(impl, v); } +void LLSD::assign(Real v) { safe(impl).assign(impl, v); } +void LLSD::assign(const String& v) { safe(impl).assign(impl, v); } +void LLSD::assign(const UUID& v) { safe(impl).assign(impl, v); } +void LLSD::assign(const Date& v) { safe(impl).assign(impl, v); } +void LLSD::assign(const URI& v) { safe(impl).assign(impl, v); } +void LLSD::assign(const Binary& v) { safe(impl).assign(impl, v); } // Scalar Accessors -LLSD::Boolean LLSD::asBoolean() const { return safe(impl).asBoolean(); } -LLSD::Integer LLSD::asInteger() const { return safe(impl).asInteger(); } -LLSD::Real LLSD::asReal() const { return safe(impl).asReal(); } -LLSD::String LLSD::asString() const { return safe(impl).asString(); } -LLSD::UUID LLSD::asUUID() const { return safe(impl).asUUID(); } -LLSD::Date LLSD::asDate() const { return safe(impl).asDate(); } -LLSD::URI LLSD::asURI() const { return safe(impl).asURI(); } -const LLSD::Binary& LLSD::asBinary() const { return safe(impl).asBinary(); } +LLSD::Boolean LLSD::asBoolean() const { return safe(impl).asBoolean(); } +LLSD::Integer LLSD::asInteger() const { return safe(impl).asInteger(); } +LLSD::Real LLSD::asReal() const { return safe(impl).asReal(); } +LLSD::String LLSD::asString() const { return safe(impl).asString(); } +LLSD::UUID LLSD::asUUID() const { return safe(impl).asUUID(); } +LLSD::Date LLSD::asDate() const { return safe(impl).asDate(); } +LLSD::URI LLSD::asURI() const { return safe(impl).asURI(); } +const LLSD::Binary& LLSD::asBinary() const { return safe(impl).asBinary(); } const LLSD::String& LLSD::asStringRef() const { return safe(impl).asStringRef(); } // const char * helpers -LLSD::LLSD(const char* v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); } +LLSD::LLSD(const char* v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); } void LLSD::assign(const char* v) { - if(v) assign(std::string(v)); - else assign(std::string()); + if(v) assign(std::string(v)); + else assign(std::string()); } LLSD LLSD::emptyMap() { - LLSD v; - makeMap(v.impl); - return v; + LLSD v; + makeMap(v.impl); + return v; } -bool LLSD::has(const String& k) const { return safe(impl).has(k); } -LLSD LLSD::get(const String& k) const { return safe(impl).get(k); } -LLSD LLSD::getKeys() const { return safe(impl).getKeys(); } -void LLSD::insert(const String& k, const LLSD& v) { makeMap(impl).insert(k, v); } +bool LLSD::has(const String& k) const { return safe(impl).has(k); } +LLSD LLSD::get(const String& k) const { return safe(impl).get(k); } +LLSD LLSD::getKeys() const { return safe(impl).getKeys(); } +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); - return *this; - } -void LLSD::erase(const String& k) { makeMap(impl).erase(k); } + { + makeMap(impl).insert(k, v); + return *this; + } +void LLSD::erase(const String& k) { makeMap(impl).erase(k); } LLSD& LLSD::operator[](const String& k) -{ +{ LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD; - return makeMap(impl).ref(k); + return makeMap(impl).ref(k); } const LLSD& LLSD::operator[](const String& k) const -{ +{ LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD; - return safe(impl).ref(k); + return safe(impl).ref(k); } LLSD LLSD::emptyArray() { - LLSD v; - makeArray(v.impl); - return v; + LLSD v; + makeArray(v.impl); + return v; } -size_t LLSD::size() const { return safe(impl).size(); } - -LLSD LLSD::get(Integer i) const { return safe(impl).get(i); } +size_t LLSD::size() const { return safe(impl).size(); } + +LLSD LLSD::get(Integer i) const { return safe(impl).get(i); } void LLSD::set(Integer i, const LLSD& v){ makeArray(impl).set(i, v); } 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); - return *this; - } -LLSD& LLSD::append(const LLSD& v) { return makeArray(impl).append(v); } -void LLSD::erase(Integer i) { makeArray(impl).erase(i); } + { + makeArray(impl).insert(i, v); + return *this; + } +LLSD& LLSD::append(const LLSD& v) { return makeArray(impl).append(v); } +void LLSD::erase(Integer i) { makeArray(impl).erase(i); } LLSD& LLSD::operator[](size_t i) -{ +{ LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD; - return makeArray(impl).ref(i); + return makeArray(impl).ref(i); } const LLSD& LLSD::operator[](size_t i) const -{ +{ LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD; return safe(impl).ref(i); } static const char *llsd_dump(const LLSD &llsd, bool useXMLFormat) { - // sStorage is used to hold the string representation of the llsd last - // passed into this function. If this function is never called (the - // normal case when not debugging), nothing is allocated. Otherwise - // sStorage will point to the result of the last call. This will actually - // be one leak, but since this is used only when running under the - // debugger, it should not be an issue. - static char *sStorage = NULL; - delete[] sStorage; - std::string out_string; - { - std::ostringstream out; - if (useXMLFormat) - out << LLSDXMLStreamer(llsd); - else - out << LLSDNotationStreamer(llsd); - out_string = out.str(); - } - auto len = out_string.length(); - sStorage = new char[len + 1]; - memcpy(sStorage, out_string.c_str(), len); - sStorage[len] = '\0'; - return sStorage; + // sStorage is used to hold the string representation of the llsd last + // passed into this function. If this function is never called (the + // normal case when not debugging), nothing is allocated. Otherwise + // sStorage will point to the result of the last call. This will actually + // be one leak, but since this is used only when running under the + // debugger, it should not be an issue. + static char *sStorage = NULL; + delete[] sStorage; + std::string out_string; + { + std::ostringstream out; + if (useXMLFormat) + out << LLSDXMLStreamer(llsd); + else + out << LLSDNotationStreamer(llsd); + out_string = out.str(); + } + auto len = out_string.length(); + sStorage = new char[len + 1]; + memcpy(sStorage, out_string.c_str(), len); + sStorage[len] = '\0'; + return sStorage; } /// Returns XML version of llsd -- only to be called from debugger const char *LLSD::dumpXML(const LLSD &llsd) { - return llsd_dump(llsd, true); + return llsd_dump(llsd, true); } /// Returns Notation version of llsd -- only to be called from debugger const char *LLSD::dump(const LLSD &llsd) { - return llsd_dump(llsd, false); + return llsd_dump(llsd, false); } -LLSD::map_iterator LLSD::beginMap() { return makeMap(impl).beginMap(); } -LLSD::map_iterator LLSD::endMap() { return makeMap(impl).endMap(); } -LLSD::map_const_iterator LLSD::beginMap() const { return safe(impl).beginMap(); } -LLSD::map_const_iterator LLSD::endMap() const { return safe(impl).endMap(); } +LLSD::map_iterator LLSD::beginMap() { return makeMap(impl).beginMap(); } +LLSD::map_iterator LLSD::endMap() { return makeMap(impl).endMap(); } +LLSD::map_const_iterator LLSD::beginMap() const { return safe(impl).beginMap(); } +LLSD::map_const_iterator LLSD::endMap() const { return safe(impl).endMap(); } -LLSD::array_iterator LLSD::beginArray() { return makeArray(impl).beginArray(); } -LLSD::array_iterator LLSD::endArray() { return makeArray(impl).endArray(); } -LLSD::array_const_iterator LLSD::beginArray() const{ return safe(impl).beginArray(); } -LLSD::array_const_iterator LLSD::endArray() const { return safe(impl).endArray(); } +LLSD::array_iterator LLSD::beginArray() { return makeArray(impl).beginArray(); } +LLSD::array_iterator LLSD::endArray() { return makeArray(impl).endArray(); } +LLSD::array_const_iterator LLSD::beginArray() const{ return safe(impl).beginArray(); } +LLSD::array_const_iterator LLSD::endArray() const { return safe(impl).endArray(); } -LLSD::reverse_array_iterator LLSD::rbeginArray() { return makeArray(impl).rbeginArray(); } -LLSD::reverse_array_iterator LLSD::rendArray() { return makeArray(impl).rendArray(); } +LLSD::reverse_array_iterator LLSD::rbeginArray() { return makeArray(impl).rbeginArray(); } +LLSD::reverse_array_iterator LLSD::rendArray() { return makeArray(impl).rendArray(); } namespace llsd { -U32 allocationCount() { return LLSD::Impl::sAllocationCount; } -U32 outstandingCount() { return LLSD::Impl::sOutstandingCount; } +U32 allocationCount() { return LLSD::Impl::sAllocationCount; } +U32 outstandingCount() { return LLSD::Impl::sOutstandingCount; } // Diagnostic dump of contents in an LLSD object -void dumpStats(const LLSD& llsd) { LLSD::Impl::getImpl(llsd).dumpStats(); } +void dumpStats(const LLSD& llsd) { LLSD::Impl::getImpl(llsd).dumpStats(); } } // namespace llsd // static -std::string LLSD::typeString(Type type) +std::string LLSD::typeString(Type type) { - static const char * sTypeNameArray[] = { - "Undefined", - "Boolean", - "Integer", - "Real", - "String", - "UUID", - "Date", - "URI", - "Binary", - "Map", - "Array" - }; - - if (0 <= type && type < LL_ARRAY_SIZE(sTypeNameArray)) - { - return sTypeNameArray[type]; - } - return STRINGIZE("** invalid type value " << type); + static const char * sTypeNameArray[] = { + "Undefined", + "Boolean", + "Integer", + "Real", + "String", + "UUID", + "Date", + "URI", + "Binary", + "Map", + "Array" + }; + + if (0 <= type && type < LL_ARRAY_SIZE(sTypeNameArray)) + { + return sTypeNameArray[type]; + } + return STRINGIZE("** invalid type value " << type); } diff --git a/indra/llcommon/llsd.h b/indra/llcommon/llsd.h index 8ed254919c..a5e735b561 100644 --- a/indra/llcommon/llsd.h +++ b/indra/llcommon/llsd.h @@ -1,25 +1,25 @@ -/** +/** * @file llsd.h * @brief LLSD flexible data system. * * $LicenseInfo:firstyear=2005&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -38,450 +38,450 @@ #include "lluuid.h" /** - LLSD provides a flexible data system similar to the data facilities of - dynamic languages like Perl and Python. It is created to support exchange - of structured data between loosely coupled systems. (Here, "loosely coupled" - means not compiled together into the same module.) - - Data in such exchanges must be highly tolerant of changes on either side - such as: - - recompilation - - implementation in a different langauge - - addition of extra parameters - - execution of older versions (with fewer parameters) - - To this aim, the C++ API of LLSD strives to be very easy to use, and to - default to "the right thing" wherever possible. It is extremely tolerant - of errors and unexpected situations. - - The fundamental class is LLSD. LLSD is a value holding object. It holds - one value that is either undefined, one of the scalar types, or a map or an - array. LLSD objects have value semantics (copying them copies the value, - though it can be considered efficient, due to sharing), and mutable. - - Undefined is the singular value given to LLSD objects that are not - initialized with any data. It is also used as the return value for - operations that return an LLSD. - - The scalar data types are: - - Boolean - true or false - - Integer - a 32 bit signed integer - - Real - a 64 IEEE 754 floating point value - - UUID - a 128 unique value - - String - a sequence of zero or more Unicode chracters - - Date - an absolute point in time, UTC, - with resolution to the second - - URI - a String that is a URI - - Binary - a sequence of zero or more octets (unsigned bytes) - - A map is a dictionary mapping String keys to LLSD values. The keys are - unique within a map, and have only one value (though that value could be - an LLSD array). - - An array is a sequence of zero or more LLSD values. - - Thread Safety - - In general, these LLSD classes offer *less* safety than STL container - classes. Implementations prior to this one were unsafe even when - completely unrelated LLSD trees were in two threads due to reference - sharing of special 'undefined' values that participated in the reference - counting mechanism. - - The dereference-before-refcount and aggressive tree sharing also make - it impractical to share an LLSD across threads. A strategy of passing - ownership or a copy to another thread is still difficult due to a lack - of a cloning interface but it can be done with some care. - - One way of transferring ownership is as follows: - - void method(const LLSD input) { - ... - LLSD * xfer_tree = new LLSD(); - { - // Top-level values - (* xfer_tree)['label'] = "Some text"; - (* xfer_tree)['mode'] = APP_MODE_CONSTANT; - - // There will be a second-level - LLSD subtree(LLSD::emptyMap()); - (* xfer_tree)['subtree'] = subtree; - - // Do *not* copy from LLSD objects via LLSD - // intermediaries. Only use plain-old-data - // types as intermediaries to prevent reference - // sharing. - subtree['value1'] = input['value1'].asInteger(); - subtree['value2'] = input['value2'].asString(); - - // Close scope and drop 'subtree's reference. - // Only xfer_tree has a reference to the second - // level data. - } - ... - // Transfer the LLSD pointer to another thread. Ownership - // transfers, this thread no longer has a reference to any - // part of the xfer_tree and there's nothing to free or - // release here. Receiving thread does need to delete the - // pointer when it is done with the LLSD. Transfer - // mechanism must perform correct data ordering operations - // as dictated by architecture. - other_thread.sendMessageAndPointer("Take This", xfer_tree); - xfer_tree = NULL; - - - Avoid this pattern which provides half of a race condition: - - void method(const LLSD input) { - ... - LLSD xfer_tree(LLSD::emptyMap()); - xfer_tree['label'] = "Some text"; - xfer_tree['mode'] = APP_MODE_CONSTANT; - ... - other_thread.sendMessageAndPointer("Take This", xfer_tree); - - - @nosubgrouping + LLSD provides a flexible data system similar to the data facilities of + dynamic languages like Perl and Python. It is created to support exchange + of structured data between loosely coupled systems. (Here, "loosely coupled" + means not compiled together into the same module.) + + Data in such exchanges must be highly tolerant of changes on either side + such as: + - recompilation + - implementation in a different langauge + - addition of extra parameters + - execution of older versions (with fewer parameters) + + To this aim, the C++ API of LLSD strives to be very easy to use, and to + default to "the right thing" wherever possible. It is extremely tolerant + of errors and unexpected situations. + + The fundamental class is LLSD. LLSD is a value holding object. It holds + one value that is either undefined, one of the scalar types, or a map or an + array. LLSD objects have value semantics (copying them copies the value, + though it can be considered efficient, due to sharing), and mutable. + + Undefined is the singular value given to LLSD objects that are not + initialized with any data. It is also used as the return value for + operations that return an LLSD. + + The scalar data types are: + - Boolean - true or false + - Integer - a 32 bit signed integer + - Real - a 64 IEEE 754 floating point value + - UUID - a 128 unique value + - String - a sequence of zero or more Unicode chracters + - Date - an absolute point in time, UTC, + with resolution to the second + - URI - a String that is a URI + - Binary - a sequence of zero or more octets (unsigned bytes) + + A map is a dictionary mapping String keys to LLSD values. The keys are + unique within a map, and have only one value (though that value could be + an LLSD array). + + An array is a sequence of zero or more LLSD values. + + Thread Safety + + In general, these LLSD classes offer *less* safety than STL container + classes. Implementations prior to this one were unsafe even when + completely unrelated LLSD trees were in two threads due to reference + sharing of special 'undefined' values that participated in the reference + counting mechanism. + + The dereference-before-refcount and aggressive tree sharing also make + it impractical to share an LLSD across threads. A strategy of passing + ownership or a copy to another thread is still difficult due to a lack + of a cloning interface but it can be done with some care. + + One way of transferring ownership is as follows: + + void method(const LLSD input) { + ... + LLSD * xfer_tree = new LLSD(); + { + // Top-level values + (* xfer_tree)['label'] = "Some text"; + (* xfer_tree)['mode'] = APP_MODE_CONSTANT; + + // There will be a second-level + LLSD subtree(LLSD::emptyMap()); + (* xfer_tree)['subtree'] = subtree; + + // Do *not* copy from LLSD objects via LLSD + // intermediaries. Only use plain-old-data + // types as intermediaries to prevent reference + // sharing. + subtree['value1'] = input['value1'].asInteger(); + subtree['value2'] = input['value2'].asString(); + + // Close scope and drop 'subtree's reference. + // Only xfer_tree has a reference to the second + // level data. + } + ... + // Transfer the LLSD pointer to another thread. Ownership + // transfers, this thread no longer has a reference to any + // part of the xfer_tree and there's nothing to free or + // release here. Receiving thread does need to delete the + // pointer when it is done with the LLSD. Transfer + // mechanism must perform correct data ordering operations + // as dictated by architecture. + other_thread.sendMessageAndPointer("Take This", xfer_tree); + xfer_tree = NULL; + + + Avoid this pattern which provides half of a race condition: + + void method(const LLSD input) { + ... + LLSD xfer_tree(LLSD::emptyMap()); + xfer_tree['label'] = "Some text"; + xfer_tree['mode'] = APP_MODE_CONSTANT; + ... + other_thread.sendMessageAndPointer("Take This", xfer_tree); + + + @nosubgrouping */ // Normally undefined, used for diagnostics -//#define LLSD_DEBUG_INFO 1 +//#define LLSD_DEBUG_INFO 1 class LL_COMMON_API LLSD { public: - LLSD(); ///< initially Undefined - ~LLSD(); ///< this class may NOT be subclassed - - /** @name Copyable and Assignable */ - //@{ - LLSD(const LLSD&); - void assign(const LLSD& other); - LLSD& operator=(const LLSD& other) { assign(other); return *this; } - - //@} - - void clear(); ///< resets to Undefined - - - /** @name Scalar Types - The scalar types, and how they map onto C++ - */ - //@{ - typedef bool Boolean; - typedef S32 Integer; - typedef F64 Real; - typedef std::string String; - typedef LLUUID UUID; - typedef LLDate Date; - typedef LLURI URI; - typedef std::vector Binary; - //@} - - /** @name Scalar Constructors */ - //@{ - LLSD(Boolean); - LLSD(Integer); - LLSD(Real); - LLSD(const String&); - LLSD(const UUID&); - LLSD(const Date&); - LLSD(const URI&); - LLSD(const Binary&); - //@} - - /** @name Convenience Constructors */ - //@{ - // support construction from size_t et al. - template ::value && - ! std::is_same::value, - bool>::type = true> - LLSD(VALUE v): LLSD(Integer(narrow(v))) {} - // support construction from F32 et al. - template ::value, - bool>::type = true> - LLSD(VALUE v): LLSD(Real(narrow(v))) {} - //@} - - /** @name Scalar Assignment */ - //@{ - void assign(Boolean); - void assign(Integer); - void assign(Real); - void assign(const String&); - void assign(const UUID&); - void assign(const Date&); - void assign(const URI&); - void assign(const Binary&); - - LLSD& operator=(Boolean v) { assign(v); return *this; } - LLSD& operator=(Integer v) { assign(v); return *this; } - LLSD& operator=(Real v) { assign(v); return *this; } - LLSD& operator=(const String& v) { assign(v); return *this; } - LLSD& operator=(const UUID& v) { assign(v); return *this; } - LLSD& operator=(const Date& v) { assign(v); return *this; } - LLSD& operator=(const URI& v) { assign(v); return *this; } - LLSD& operator=(const Binary& v) { assign(v); return *this; } - //@} - - /** - @name Scalar Accessors - @brief Fetch a scalar value, converting if needed and possible - - Conversion among the basic types, Boolean, Integer, Real and String, is - fully defined. Each type can be converted to another with a reasonable - interpretation. These conversions can be used as a convenience even - when you know the data is in one format, but you want it in another. Of - course, many of these conversions lose information. - - Note: These conversions are not the same as Perl's. In particular, when - converting a String to a Boolean, only the empty string converts to - false. Converting the String "0" to Boolean results in true. - - Conversion to and from UUID, Date, and URI is only defined to and from - String. Conversion is defined to be information preserving for valid - values of those types. These conversions can be used when one needs to - convert data to or from another system that cannot handle these types - natively, but can handle strings. - - Conversion to and from Binary isn't defined. - - Conversion of the Undefined value to any scalar type results in a - reasonable null or zero value for the type. - */ - //@{ - Boolean asBoolean() const; - Integer asInteger() const; - Real asReal() const; - String asString() const; - UUID asUUID() const; - Date asDate() const; - URI asURI() const; - const Binary& asBinary() const; - - // asStringRef on any non-string type will return a ref to an empty string. - const String& asStringRef() const; - - operator Boolean() const { return asBoolean(); } - operator Integer() const { return asInteger(); } - operator Real() const { return asReal(); } - operator String() const { return asString(); } - operator UUID() const { return asUUID(); } - operator Date() const { return asDate(); } - operator URI() const { return asURI(); } - operator Binary() const { return asBinary(); } - - // This is needed because most platforms do not automatically - // convert the boolean negation as a bool in an if statement. - bool operator!() const {return !asBoolean();} - //@} - - /** @name Character Pointer Helpers - These are helper routines to make working with char* as easy as - working with strings. - */ - //@{ - LLSD(const char*); - void assign(const char*); - LLSD& operator=(const char* v) { assign(v); return *this; } - //@} - - /** @name Map Values */ - //@{ - static LLSD emptyMap(); - - bool has(const String&) const; - LLSD get(const String&) const; - LLSD getKeys() const; // Return an LLSD array with keys as strings - void insert(const String&, const LLSD&); - void erase(const String&); - LLSD& with(const String&, const LLSD&); - - LLSD& operator[](const String&); - LLSD& operator[](const char* c) + LLSD(); ///< initially Undefined + ~LLSD(); ///< this class may NOT be subclassed + + /** @name Copyable and Assignable */ + //@{ + LLSD(const LLSD&); + void assign(const LLSD& other); + LLSD& operator=(const LLSD& other) { assign(other); return *this; } + + //@} + + void clear(); ///< resets to Undefined + + + /** @name Scalar Types + The scalar types, and how they map onto C++ + */ + //@{ + typedef bool Boolean; + typedef S32 Integer; + typedef F64 Real; + typedef std::string String; + typedef LLUUID UUID; + typedef LLDate Date; + typedef LLURI URI; + typedef std::vector Binary; + //@} + + /** @name Scalar Constructors */ + //@{ + LLSD(Boolean); + LLSD(Integer); + LLSD(Real); + LLSD(const String&); + LLSD(const UUID&); + LLSD(const Date&); + LLSD(const URI&); + LLSD(const Binary&); + //@} + + /** @name Convenience Constructors */ + //@{ + // support construction from size_t et al. + template ::value && + ! std::is_same::value, + bool>::type = true> + LLSD(VALUE v): LLSD(Integer(narrow(v))) {} + // support construction from F32 et al. + template ::value, + bool>::type = true> + LLSD(VALUE v): LLSD(Real(narrow(v))) {} + //@} + + /** @name Scalar Assignment */ + //@{ + void assign(Boolean); + void assign(Integer); + void assign(Real); + void assign(const String&); + void assign(const UUID&); + void assign(const Date&); + void assign(const URI&); + void assign(const Binary&); + + LLSD& operator=(Boolean v) { assign(v); return *this; } + LLSD& operator=(Integer v) { assign(v); return *this; } + LLSD& operator=(Real v) { assign(v); return *this; } + LLSD& operator=(const String& v) { assign(v); return *this; } + LLSD& operator=(const UUID& v) { assign(v); return *this; } + LLSD& operator=(const Date& v) { assign(v); return *this; } + LLSD& operator=(const URI& v) { assign(v); return *this; } + LLSD& operator=(const Binary& v) { assign(v); return *this; } + //@} + + /** + @name Scalar Accessors + @brief Fetch a scalar value, converting if needed and possible + + Conversion among the basic types, Boolean, Integer, Real and String, is + fully defined. Each type can be converted to another with a reasonable + interpretation. These conversions can be used as a convenience even + when you know the data is in one format, but you want it in another. Of + course, many of these conversions lose information. + + Note: These conversions are not the same as Perl's. In particular, when + converting a String to a Boolean, only the empty string converts to + false. Converting the String "0" to Boolean results in true. + + Conversion to and from UUID, Date, and URI is only defined to and from + String. Conversion is defined to be information preserving for valid + values of those types. These conversions can be used when one needs to + convert data to or from another system that cannot handle these types + natively, but can handle strings. + + Conversion to and from Binary isn't defined. + + Conversion of the Undefined value to any scalar type results in a + reasonable null or zero value for the type. + */ + //@{ + Boolean asBoolean() const; + Integer asInteger() const; + Real asReal() const; + String asString() const; + UUID asUUID() const; + Date asDate() const; + URI asURI() const; + const Binary& asBinary() const; + + // asStringRef on any non-string type will return a ref to an empty string. + const String& asStringRef() const; + + operator Boolean() const { return asBoolean(); } + operator Integer() const { return asInteger(); } + operator Real() const { return asReal(); } + operator String() const { return asString(); } + operator UUID() const { return asUUID(); } + operator Date() const { return asDate(); } + operator URI() const { return asURI(); } + operator Binary() const { return asBinary(); } + + // This is needed because most platforms do not automatically + // convert the boolean negation as a bool in an if statement. + bool operator!() const {return !asBoolean();} + //@} + + /** @name Character Pointer Helpers + These are helper routines to make working with char* as easy as + working with strings. + */ + //@{ + LLSD(const char*); + void assign(const char*); + LLSD& operator=(const char* v) { assign(v); return *this; } + //@} + + /** @name Map Values */ + //@{ + static LLSD emptyMap(); + + bool has(const String&) const; + LLSD get(const String&) const; + LLSD getKeys() const; // Return an LLSD array with keys as strings + void insert(const String&, const LLSD&); + void erase(const String&); + LLSD& with(const String&, const LLSD&); + + LLSD& operator[](const String&); + LLSD& operator[](const char* c) { LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD; return (*this)[String(c)]; } - const LLSD& operator[](const String&) const; - const LLSD& operator[](const char* c) const + const LLSD& operator[](const String&) const; + const LLSD& operator[](const char* c) const { LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD; return (*this)[String(c)]; } - //@} - - /** @name Array Values */ - //@{ - static LLSD emptyArray(); - - LLSD get(Integer) const; - void set(Integer, const LLSD&); - void insert(Integer, const LLSD&); - LLSD& append(const LLSD&); - void erase(Integer); - LLSD& with(Integer, const LLSD&); - - // accept size_t so we can index relative to size() - const LLSD& operator[](size_t) const; - LLSD& operator[](size_t); - // template overloads to support int literals, U32 et al. - template ::value, - bool>::type = true> - const LLSD& operator[](IDX i) const { return (*this)[size_t(i)]; } - template ::value, - bool>::type = true> - LLSD& operator[](IDX i) { return (*this)[size_t(i)]; } - //@} - - /** @name Iterators */ - //@{ - size_t size() const; - - typedef std::map::iterator map_iterator; - typedef std::map::const_iterator map_const_iterator; - - map_iterator beginMap(); - map_iterator endMap(); - map_const_iterator beginMap() const; - map_const_iterator endMap() const; - - typedef std::vector::iterator array_iterator; - typedef std::vector::const_iterator array_const_iterator; - typedef std::vector::reverse_iterator reverse_array_iterator; - - array_iterator beginArray(); - array_iterator endArray(); - array_const_iterator beginArray() const; - array_const_iterator endArray() const; - - reverse_array_iterator rbeginArray(); - reverse_array_iterator rendArray(); - //@} - - /** @name Type Testing */ - //@{ - enum Type { - TypeUndefined = 0, - TypeBoolean, - TypeInteger, - TypeReal, - TypeString, - TypeUUID, - TypeDate, - TypeURI, - TypeBinary, - TypeMap, - TypeArray, - TypeLLSDTypeEnd, - TypeLLSDTypeBegin = TypeUndefined, - TypeLLSDNumTypes = (TypeLLSDTypeEnd - TypeLLSDTypeBegin) - }; - - Type type() const; - - bool isUndefined() const { return type() == TypeUndefined; } - bool isDefined() const { return type() != TypeUndefined; } - bool isBoolean() const { return type() == TypeBoolean; } - bool isInteger() const { return type() == TypeInteger; } - bool isReal() const { return type() == TypeReal; } - bool isString() const { return type() == TypeString; } - bool isUUID() const { return type() == TypeUUID; } - bool isDate() const { return type() == TypeDate; } - bool isURI() const { return type() == TypeURI; } - bool isBinary() const { return type() == TypeBinary; } - bool isMap() const { return type() == TypeMap; } - bool isArray() const { return type() == TypeArray; } - //@} - - /** @name Automatic Cast Protection - These are not implemented on purpose. Without them, C++ can perform - some conversions that are clearly not what the programmer intended. - - If you get a linker error about these being missing, you have made - mistake in your code. DO NOT IMPLEMENT THESE FUNCTIONS as a fix. - - All of these problems stem from trying to support char* in LLSD or in - std::string. There are too many automatic casts that will lead to - using an arbitrary pointer or scalar type to std::string. - */ - //@{ - LLSD(const void*); ///< construct from aribrary pointers - void assign(const void*); ///< assign from arbitrary pointers - LLSD& operator=(const void*); ///< assign from arbitrary pointers - - bool has(Integer) const; ///< has() only works for Maps - //@} - - /** @name Implementation */ - //@{ + //@} + + /** @name Array Values */ + //@{ + static LLSD emptyArray(); + + LLSD get(Integer) const; + void set(Integer, const LLSD&); + void insert(Integer, const LLSD&); + LLSD& append(const LLSD&); + void erase(Integer); + LLSD& with(Integer, const LLSD&); + + // accept size_t so we can index relative to size() + const LLSD& operator[](size_t) const; + LLSD& operator[](size_t); + // template overloads to support int literals, U32 et al. + template ::value, + bool>::type = true> + const LLSD& operator[](IDX i) const { return (*this)[size_t(i)]; } + template ::value, + bool>::type = true> + LLSD& operator[](IDX i) { return (*this)[size_t(i)]; } + //@} + + /** @name Iterators */ + //@{ + size_t size() const; + + typedef std::map::iterator map_iterator; + typedef std::map::const_iterator map_const_iterator; + + map_iterator beginMap(); + map_iterator endMap(); + map_const_iterator beginMap() const; + map_const_iterator endMap() const; + + typedef std::vector::iterator array_iterator; + typedef std::vector::const_iterator array_const_iterator; + typedef std::vector::reverse_iterator reverse_array_iterator; + + array_iterator beginArray(); + array_iterator endArray(); + array_const_iterator beginArray() const; + array_const_iterator endArray() const; + + reverse_array_iterator rbeginArray(); + reverse_array_iterator rendArray(); + //@} + + /** @name Type Testing */ + //@{ + enum Type { + TypeUndefined = 0, + TypeBoolean, + TypeInteger, + TypeReal, + TypeString, + TypeUUID, + TypeDate, + TypeURI, + TypeBinary, + TypeMap, + TypeArray, + TypeLLSDTypeEnd, + TypeLLSDTypeBegin = TypeUndefined, + TypeLLSDNumTypes = (TypeLLSDTypeEnd - TypeLLSDTypeBegin) + }; + + Type type() const; + + bool isUndefined() const { return type() == TypeUndefined; } + bool isDefined() const { return type() != TypeUndefined; } + bool isBoolean() const { return type() == TypeBoolean; } + bool isInteger() const { return type() == TypeInteger; } + bool isReal() const { return type() == TypeReal; } + bool isString() const { return type() == TypeString; } + bool isUUID() const { return type() == TypeUUID; } + bool isDate() const { return type() == TypeDate; } + bool isURI() const { return type() == TypeURI; } + bool isBinary() const { return type() == TypeBinary; } + bool isMap() const { return type() == TypeMap; } + bool isArray() const { return type() == TypeArray; } + //@} + + /** @name Automatic Cast Protection + These are not implemented on purpose. Without them, C++ can perform + some conversions that are clearly not what the programmer intended. + + If you get a linker error about these being missing, you have made + mistake in your code. DO NOT IMPLEMENT THESE FUNCTIONS as a fix. + + All of these problems stem from trying to support char* in LLSD or in + std::string. There are too many automatic casts that will lead to + using an arbitrary pointer or scalar type to std::string. + */ + //@{ + LLSD(const void*); ///< construct from aribrary pointers + void assign(const void*); ///< assign from arbitrary pointers + LLSD& operator=(const void*); ///< assign from arbitrary pointers + + bool has(Integer) const; ///< has() only works for Maps + //@} + + /** @name Implementation */ + //@{ public: - class Impl; + class Impl; private: - Impl* impl; - friend class LLSD::Impl; - //@} + Impl* impl; + friend class LLSD::Impl; + //@} private: - /** @name Debugging Interface */ - //@{ - /// Returns XML version of llsd -- only to be called from debugger - static const char *dumpXML(const LLSD &llsd); + /** @name Debugging Interface */ + //@{ + /// Returns XML version of llsd -- only to be called from debugger + static const char *dumpXML(const LLSD &llsd); - /// Returns Notation version of llsd -- only to be called from debugger - static const char *dump(const LLSD &llsd); - //@} + /// Returns Notation version of llsd -- only to be called from debugger + static const char *dump(const LLSD &llsd); + //@} public: - static std::string typeString(Type type); // Return human-readable type as a string + static std::string typeString(Type type); // Return human-readable type as a string }; struct llsd_select_bool { - LLSD::Boolean operator()(const LLSD& sd) const - { - return sd.asBoolean(); - } + LLSD::Boolean operator()(const LLSD& sd) const + { + return sd.asBoolean(); + } }; struct llsd_select_integer { - LLSD::Integer operator()(const LLSD& sd) const - { - return sd.asInteger(); - } + LLSD::Integer operator()(const LLSD& sd) const + { + return sd.asInteger(); + } }; struct llsd_select_real { - LLSD::Real operator()(const LLSD& sd) const - { - return sd.asReal(); - } + LLSD::Real operator()(const LLSD& sd) const + { + return sd.asReal(); + } }; struct llsd_select_float { - F32 operator()(const LLSD& sd) const - { - return (F32)sd.asReal(); - } + F32 operator()(const LLSD& sd) const + { + return (F32)sd.asReal(); + } }; struct llsd_select_uuid { - LLSD::UUID operator()(const LLSD& sd) const - { - return sd.asUUID(); - } + LLSD::UUID operator()(const LLSD& sd) const + { + return sd.asUUID(); + } }; struct llsd_select_string { - LLSD::String operator()(const LLSD& sd) const - { - return sd.asString(); - } + LLSD::String operator()(const LLSD& sd) const + { + return sd.asString(); + } }; LL_COMMON_API std::ostream& operator<<(std::ostream& s, const LLSD& llsd); @@ -492,30 +492,30 @@ namespace llsd #ifdef LLSD_DEBUG_INFO /** @name Unit Testing Interface */ //@{ - LL_COMMON_API void dumpStats(const LLSD&); ///< Output information on object and usage - - /// @warn THE FOLLOWING COUNTS WILL NOT BE ACCURATE IN A MULTI-THREADED - /// ENVIRONMENT. - /// - /// These counts track LLSD::Impl (hidden) objects. - LL_COMMON_API U32 allocationCount(); ///< how many Impls have been made - LL_COMMON_API U32 outstandingCount(); ///< how many Impls are still alive - - /// These counts track LLSD (public) objects. - LL_COMMON_API extern S32 sLLSDAllocationCount; ///< Number of LLSD objects ever created - LL_COMMON_API extern S32 sLLSDNetObjects; ///< Number of LLSD objects that exist + LL_COMMON_API void dumpStats(const LLSD&); ///< Output information on object and usage + + /// @warn THE FOLLOWING COUNTS WILL NOT BE ACCURATE IN A MULTI-THREADED + /// ENVIRONMENT. + /// + /// These counts track LLSD::Impl (hidden) objects. + LL_COMMON_API U32 allocationCount(); ///< how many Impls have been made + LL_COMMON_API U32 outstandingCount(); ///< how many Impls are still alive + + /// These counts track LLSD (public) objects. + LL_COMMON_API extern S32 sLLSDAllocationCount; ///< Number of LLSD objects ever created + LL_COMMON_API extern S32 sLLSDNetObjects; ///< Number of LLSD objects that exist #endif //@} } // namespace llsd /** QUESTIONS & TO DOS - - Would Binary be more convenient as unsigned char* buffer semantics? - - Should Binary be convertible to/from String, and if so how? - - as UTF8 encoded strings (making not like UUID<->String) - - as Base64 or Base96 encoded (making like UUID<->String) - - Conversions to std::string and LLUUID do not result in easy assignment - to std::string, std::string or LLUUID due to non-unique conversion paths + - Would Binary be more convenient as unsigned char* buffer semantics? + - Should Binary be convertible to/from String, and if so how? + - as UTF8 encoded strings (making not like UUID<->String) + - as Base64 or Base96 encoded (making like UUID<->String) + - Conversions to std::string and LLUUID do not result in easy assignment + to std::string, std::string or LLUUID due to non-unique conversion paths */ #endif // LL_LLSD_NEW_H diff --git a/indra/llcommon/llsdjson.cpp b/indra/llcommon/llsdjson.cpp index 8caaaee534..bb2b8681f7 100644 --- a/indra/llcommon/llsdjson.cpp +++ b/indra/llcommon/llsdjson.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llsdjson.cpp * @brief LLSD flexible data system * * $LicenseInfo:firstyear=2015&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2015, 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$ */ diff --git a/indra/llcommon/llsdjson.h b/indra/llcommon/llsdjson.h index e56cf03b45..79bf2c56fa 100644 --- a/indra/llcommon/llsdjson.h +++ b/indra/llcommon/llsdjson.h @@ -1,25 +1,25 @@ -/** +/** * @file llsdjson.cpp * @brief LLSD flexible data system * * $LicenseInfo:firstyear=2015&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2015, 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$ */ @@ -36,10 +36,10 @@ #include "llsd.h" #include "json/value.h" -/// Convert a parsed JSON structure into LLSD maintaining member names and +/// Convert a parsed JSON structure into LLSD maintaining member names and /// array indexes. /// JSON/JavaScript types are converted as follows: -/// +/// /// JSON Type | LLSD Type /// --------------+-------------- /// null | undefined @@ -50,14 +50,14 @@ /// boolean | LLSD::Boolean /// array | LLSD::Array /// object | LLSD::Map -/// +/// /// For maps and arrays child entries will be converted and added to the structure. /// Order is preserved for an array but not for objects. LLSD LlsdFromJson(const Json::Value &val); -/// Convert an LLSD object into Parsed JSON object maintaining member names and +/// Convert an LLSD object into Parsed JSON object maintaining member names and /// array indexs. -/// +/// /// Types are converted as follows: /// LLSD Type | JSON Type /// --------------+---------------- @@ -71,7 +71,7 @@ LLSD LlsdFromJson(const Json::Value &val); /// TypeUUID | string /// TypeMap | object /// TypeArray | array -/// TypeBinary | unsupported +/// TypeBinary | unsupported Json::Value LlsdToJson(const LLSD &val); #endif // LL_LLSDJSON_H diff --git a/indra/llcommon/llsdparam.cpp b/indra/llcommon/llsdparam.cpp index 30f49b27ea..b981be4d0a 100644 --- a/indra/llcommon/llsdparam.cpp +++ b/indra/llcommon/llsdparam.cpp @@ -1,26 +1,26 @@ -/** +/** * @file llsdparam.cpp - * @brief parameter block abstraction for creating complex objects and + * @brief parameter block abstraction for creating complex objects and * parsing construction parameters from xml and LLSD * * $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$ */ @@ -32,9 +32,9 @@ #include "llsdutil.h" #include "boost/bind.hpp" -static LLInitParam::Parser::parser_read_func_map_t sReadFuncs; -static LLInitParam::Parser::parser_write_func_map_t sWriteFuncs; -static LLInitParam::Parser::parser_inspect_func_map_t sInspectFuncs; +static LLInitParam::Parser::parser_read_func_map_t sReadFuncs; +static LLInitParam::Parser::parser_write_func_map_t sWriteFuncs; +static LLInitParam::Parser::parser_inspect_func_map_t sInspectFuncs; static const LLSD NO_VALUE_MARKER; // @@ -43,95 +43,95 @@ static const LLSD NO_VALUE_MARKER; LLParamSDParser::LLParamSDParser() : Parser(sReadFuncs, sWriteFuncs, sInspectFuncs) { - using boost::bind; - - if (sReadFuncs.empty()) - { - registerParserFuncs(readFlag, &LLParamSDParser::writeFlag); - registerParserFuncs(readS32, &LLParamSDParser::writeTypedValue); - registerParserFuncs(readU32, &LLParamSDParser::writeU32Param); - registerParserFuncs(readF32, &LLParamSDParser::writeTypedValue); - registerParserFuncs(readF64, &LLParamSDParser::writeTypedValue); - registerParserFuncs(readBool, &LLParamSDParser::writeTypedValue); - registerParserFuncs(readString, &LLParamSDParser::writeTypedValue); - registerParserFuncs(readUUID, &LLParamSDParser::writeTypedValue); - registerParserFuncs(readDate, &LLParamSDParser::writeTypedValue); - registerParserFuncs(readURI, &LLParamSDParser::writeTypedValue); - registerParserFuncs(readSD, &LLParamSDParser::writeTypedValue); - } + using boost::bind; + + if (sReadFuncs.empty()) + { + registerParserFuncs(readFlag, &LLParamSDParser::writeFlag); + registerParserFuncs(readS32, &LLParamSDParser::writeTypedValue); + registerParserFuncs(readU32, &LLParamSDParser::writeU32Param); + registerParserFuncs(readF32, &LLParamSDParser::writeTypedValue); + registerParserFuncs(readF64, &LLParamSDParser::writeTypedValue); + registerParserFuncs(readBool, &LLParamSDParser::writeTypedValue); + registerParserFuncs(readString, &LLParamSDParser::writeTypedValue); + registerParserFuncs(readUUID, &LLParamSDParser::writeTypedValue); + registerParserFuncs(readDate, &LLParamSDParser::writeTypedValue); + registerParserFuncs(readURI, &LLParamSDParser::writeTypedValue); + registerParserFuncs(readSD, &LLParamSDParser::writeTypedValue); + } } // special case handling of U32 due to ambiguous LLSD::assign overload bool LLParamSDParser::writeU32Param(LLParamSDParser::parser_t& parser, const void* val_ptr, parser_t::name_stack_t& name_stack) { - LLParamSDParser& sdparser = static_cast(parser); - if (!sdparser.mWriteRootSD) return false; - - parser_t::name_stack_range_t range(name_stack.begin(), name_stack.end()); - LLSD& sd_to_write = LLParamSDParserUtilities::getSDWriteNode(*sdparser.mWriteRootSD, range); - sd_to_write.assign((S32)*((const U32*)val_ptr)); - - return true; + LLParamSDParser& sdparser = static_cast(parser); + if (!sdparser.mWriteRootSD) return false; + + parser_t::name_stack_range_t range(name_stack.begin(), name_stack.end()); + LLSD& sd_to_write = LLParamSDParserUtilities::getSDWriteNode(*sdparser.mWriteRootSD, range); + sd_to_write.assign((S32)*((const U32*)val_ptr)); + + return true; } bool LLParamSDParser::writeFlag(LLParamSDParser::parser_t& parser, const void* val_ptr, parser_t::name_stack_t& name_stack) { - LLParamSDParser& sdparser = static_cast(parser); - if (!sdparser.mWriteRootSD) return false; + LLParamSDParser& sdparser = static_cast(parser); + if (!sdparser.mWriteRootSD) return false; - parser_t::name_stack_range_t range(name_stack.begin(), name_stack.end()); - LLParamSDParserUtilities::getSDWriteNode(*sdparser.mWriteRootSD, range); + parser_t::name_stack_range_t range(name_stack.begin(), name_stack.end()); + LLParamSDParserUtilities::getSDWriteNode(*sdparser.mWriteRootSD, range); - return true; + return true; } void LLParamSDParser::submit(LLInitParam::BaseBlock& block, const LLSD& sd, LLInitParam::Parser::name_stack_t& name_stack) { - mCurReadSD = &sd; - block.submitValue(name_stack, *this); + mCurReadSD = &sd; + block.submitValue(name_stack, *this); } void LLParamSDParser::readSD(const LLSD& sd, LLInitParam::BaseBlock& block, bool silent) { - mCurReadSD = NULL; - mNameStack.clear(); - setParseSilently(silent); + mCurReadSD = NULL; + mNameStack.clear(); + setParseSilently(silent); - LLParamSDParserUtilities::readSDValues(boost::bind(&LLParamSDParser::submit, this, boost::ref(block), _1, _2), sd, mNameStack); - //readSDValues(sd, block); + LLParamSDParserUtilities::readSDValues(boost::bind(&LLParamSDParser::submit, this, boost::ref(block), _1, _2), sd, mNameStack); + //readSDValues(sd, block); } void LLParamSDParser::writeSDImpl(LLSD& sd, const LLInitParam::BaseBlock& block, const LLInitParam::predicate_rule_t rules, const LLInitParam::BaseBlock* diff_block) { - mNameStack.clear(); - mWriteRootSD = &sd; + mNameStack.clear(); + mWriteRootSD = &sd; - name_stack_t name_stack; - block.serializeBlock(*this, name_stack, rules, diff_block); + name_stack_t name_stack; + block.serializeBlock(*this, name_stack, rules, diff_block); } /*virtual*/ std::string LLParamSDParser::getCurrentElementName() { - std::string full_name = "sd"; - for (name_stack_t::value_type& stack_pair : mNameStack) - { - full_name += llformat("[%s]", stack_pair.first.c_str()); - } + std::string full_name = "sd"; + for (name_stack_t::value_type& stack_pair : mNameStack) + { + full_name += llformat("[%s]", stack_pair.first.c_str()); + } - return full_name; + return full_name; } bool LLParamSDParser::readFlag(Parser& parser, void* val_ptr) { - LLParamSDParser& self = static_cast(parser); - return self.mCurReadSD == &NO_VALUE_MARKER; + LLParamSDParser& self = static_cast(parser); + return self.mCurReadSD == &NO_VALUE_MARKER; } bool LLParamSDParser::readS32(Parser& parser, void* val_ptr) { - LLParamSDParser& self = static_cast(parser); + LLParamSDParser& self = static_cast(parser); *((S32*)val_ptr) = self.mCurReadSD->asInteger(); return true; @@ -139,7 +139,7 @@ bool LLParamSDParser::readS32(Parser& parser, void* val_ptr) bool LLParamSDParser::readU32(Parser& parser, void* val_ptr) { - LLParamSDParser& self = static_cast(parser); + LLParamSDParser& self = static_cast(parser); *((U32*)val_ptr) = self.mCurReadSD->asInteger(); return true; @@ -147,7 +147,7 @@ bool LLParamSDParser::readU32(Parser& parser, void* val_ptr) bool LLParamSDParser::readF32(Parser& parser, void* val_ptr) { - LLParamSDParser& self = static_cast(parser); + LLParamSDParser& self = static_cast(parser); *((F32*)val_ptr) = self.mCurReadSD->asReal(); return true; @@ -155,7 +155,7 @@ bool LLParamSDParser::readF32(Parser& parser, void* val_ptr) bool LLParamSDParser::readF64(Parser& parser, void* val_ptr) { - LLParamSDParser& self = static_cast(parser); + LLParamSDParser& self = static_cast(parser); *((F64*)val_ptr) = self.mCurReadSD->asReal(); return true; @@ -163,7 +163,7 @@ bool LLParamSDParser::readF64(Parser& parser, void* val_ptr) bool LLParamSDParser::readBool(Parser& parser, void* val_ptr) { - LLParamSDParser& self = static_cast(parser); + LLParamSDParser& self = static_cast(parser); *((bool*)val_ptr) = self.mCurReadSD->asBoolean(); return true; @@ -171,170 +171,170 @@ bool LLParamSDParser::readBool(Parser& parser, void* val_ptr) bool LLParamSDParser::readString(Parser& parser, void* val_ptr) { - LLParamSDParser& self = static_cast(parser); + LLParamSDParser& self = static_cast(parser); - *((std::string*)val_ptr) = self.mCurReadSD->asString(); + *((std::string*)val_ptr) = self.mCurReadSD->asString(); return true; } bool LLParamSDParser::readUUID(Parser& parser, void* val_ptr) { - LLParamSDParser& self = static_cast(parser); + LLParamSDParser& self = static_cast(parser); - *((LLUUID*)val_ptr) = self.mCurReadSD->asUUID(); + *((LLUUID*)val_ptr) = self.mCurReadSD->asUUID(); return true; } bool LLParamSDParser::readDate(Parser& parser, void* val_ptr) { - LLParamSDParser& self = static_cast(parser); + LLParamSDParser& self = static_cast(parser); - *((LLDate*)val_ptr) = self.mCurReadSD->asDate(); + *((LLDate*)val_ptr) = self.mCurReadSD->asDate(); return true; } bool LLParamSDParser::readURI(Parser& parser, void* val_ptr) { - LLParamSDParser& self = static_cast(parser); + LLParamSDParser& self = static_cast(parser); - *((LLURI*)val_ptr) = self.mCurReadSD->asURI(); + *((LLURI*)val_ptr) = self.mCurReadSD->asURI(); return true; } bool LLParamSDParser::readSD(Parser& parser, void* val_ptr) { - LLParamSDParser& self = static_cast(parser); + LLParamSDParser& self = static_cast(parser); - *((LLSD*)val_ptr) = *self.mCurReadSD; + *((LLSD*)val_ptr) = *self.mCurReadSD; return true; } // static LLSD& LLParamSDParserUtilities::getSDWriteNode(LLSD& input, LLInitParam::Parser::name_stack_range_t& name_stack_range) { - LLSD* sd_to_write = &input; - - for (LLInitParam::Parser::name_stack_t::iterator it = name_stack_range.first; - it != name_stack_range.second; - ++it) - { - bool new_traversal = it->second; - - LLSD* child_sd; - if (it->first.empty()) - { - child_sd = sd_to_write; - if (child_sd->isUndefined()) - { - *child_sd = LLSD::emptyArray(); - } - if (new_traversal) - { - // write to new element at end - sd_to_write = &(*child_sd)[child_sd->size()]; - } - else - { - // write to last of existing elements, or first element if empty - sd_to_write = &(*child_sd)[llmax(0, child_sd->size() - 1)]; - } - } - else - { - sd_to_write = &(*sd_to_write)[it->first]; - } - it->second = false; - } - - return *sd_to_write; + LLSD* sd_to_write = &input; + + for (LLInitParam::Parser::name_stack_t::iterator it = name_stack_range.first; + it != name_stack_range.second; + ++it) + { + bool new_traversal = it->second; + + LLSD* child_sd; + if (it->first.empty()) + { + child_sd = sd_to_write; + if (child_sd->isUndefined()) + { + *child_sd = LLSD::emptyArray(); + } + if (new_traversal) + { + // write to new element at end + sd_to_write = &(*child_sd)[child_sd->size()]; + } + else + { + // write to last of existing elements, or first element if empty + sd_to_write = &(*child_sd)[llmax(0, child_sd->size() - 1)]; + } + } + else + { + sd_to_write = &(*sd_to_write)[it->first]; + } + it->second = false; + } + + return *sd_to_write; } //static void LLParamSDParserUtilities::readSDValues(read_sd_cb_t cb, const LLSD& sd, LLInitParam::Parser::name_stack_t& stack) { - if (sd.isMap()) - { - for (LLSD::map_const_iterator it = sd.beginMap(); - it != sd.endMap(); - ++it) - { - stack.push_back(make_pair(it->first, true)); - readSDValues(cb, it->second, stack); - stack.pop_back(); - } - } - else if (sd.isArray()) - { - for (LLSD::array_const_iterator it = sd.beginArray(); - it != sd.endArray(); - ++it) - { - stack.push_back(make_pair(std::string(), true)); - readSDValues(cb, *it, stack); - stack.pop_back(); - } - } - else if (sd.isUndefined()) - { - if (!cb.empty()) - { - cb(NO_VALUE_MARKER, stack); - } - } - else - { - if (!cb.empty()) - { - cb(sd, stack); - } - } + if (sd.isMap()) + { + for (LLSD::map_const_iterator it = sd.beginMap(); + it != sd.endMap(); + ++it) + { + stack.push_back(make_pair(it->first, true)); + readSDValues(cb, it->second, stack); + stack.pop_back(); + } + } + else if (sd.isArray()) + { + for (LLSD::array_const_iterator it = sd.beginArray(); + it != sd.endArray(); + ++it) + { + stack.push_back(make_pair(std::string(), true)); + readSDValues(cb, *it, stack); + stack.pop_back(); + } + } + else if (sd.isUndefined()) + { + if (!cb.empty()) + { + cb(NO_VALUE_MARKER, stack); + } + } + else + { + if (!cb.empty()) + { + cb(sd, stack); + } + } } //static void LLParamSDParserUtilities::readSDValues(read_sd_cb_t cb, const LLSD& sd) { - LLInitParam::Parser::name_stack_t stack = LLInitParam::Parser::name_stack_t(); - readSDValues(cb, sd, stack); + LLInitParam::Parser::name_stack_t stack = LLInitParam::Parser::name_stack_t(); + readSDValues(cb, sd, stack); } namespace LLInitParam { - // LLSD specialization - // block param interface - bool ParamValue::deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack, bool new_name) - { - if (name_stack.first == name_stack.second - && p.readValue(mValue)) - { - return true; - } - - LLSD& sd = LLParamSDParserUtilities::getSDWriteNode(mValue, name_stack); - - LLSD::String string; - - if (p.readValue(string)) - { - sd = string; - return true; - } - return false; - } - - //static - void ParamValue::serializeElement(Parser& p, const LLSD& sd, Parser::name_stack_t& name_stack) - { - p.writeValue(sd.asString(), name_stack); - } - - bool ParamValue::serializeBlock(Parser& p, Parser::name_stack_t& name_stack_range, const predicate_rule_t predicate_rule, const BaseBlock* diff_block) const - { - // attempt to write LLSD out directly - if (!p.writeValue(mValue, name_stack_range)) - { - // otherwise read from LLSD value and serialize out to parser (which could be LLSD, XUI, etc) - LLParamSDParserUtilities::readSDValues(boost::bind(&serializeElement, boost::ref(p), _1, _2), mValue, name_stack_range); - } - return true; - } + // LLSD specialization + // block param interface + bool ParamValue::deserializeBlock(Parser& p, Parser::name_stack_range_t& name_stack, bool new_name) + { + if (name_stack.first == name_stack.second + && p.readValue(mValue)) + { + return true; + } + + LLSD& sd = LLParamSDParserUtilities::getSDWriteNode(mValue, name_stack); + + LLSD::String string; + + if (p.readValue(string)) + { + sd = string; + return true; + } + return false; + } + + //static + void ParamValue::serializeElement(Parser& p, const LLSD& sd, Parser::name_stack_t& name_stack) + { + p.writeValue(sd.asString(), name_stack); + } + + bool ParamValue::serializeBlock(Parser& p, Parser::name_stack_t& name_stack_range, const predicate_rule_t predicate_rule, const BaseBlock* diff_block) const + { + // attempt to write LLSD out directly + if (!p.writeValue(mValue, name_stack_range)) + { + // otherwise read from LLSD value and serialize out to parser (which could be LLSD, XUI, etc) + LLParamSDParserUtilities::readSDValues(boost::bind(&serializeElement, boost::ref(p), _1, _2), mValue, name_stack_range); + } + return true; + } } diff --git a/indra/llcommon/llsdparam.h b/indra/llcommon/llsdparam.h index 82a623a8a0..21ebb9a258 100644 --- a/indra/llcommon/llsdparam.h +++ b/indra/llcommon/llsdparam.h @@ -1,26 +1,26 @@ -/** +/** * @file llsdparam.h - * @brief parameter block abstraction for creating complex objects and + * @brief parameter block abstraction for creating complex objects and * parsing construction parameters from xml and LLSD * * $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$ */ @@ -34,79 +34,79 @@ struct LL_COMMON_API LLParamSDParserUtilities { - static LLSD& getSDWriteNode(LLSD& input, LLInitParam::Parser::name_stack_range_t& name_stack_range); + static LLSD& getSDWriteNode(LLSD& input, LLInitParam::Parser::name_stack_range_t& name_stack_range); - typedef boost::function read_sd_cb_t; - static void readSDValues(read_sd_cb_t cb, const LLSD& sd, LLInitParam::Parser::name_stack_t& stack); - static void readSDValues(read_sd_cb_t cb, const LLSD& sd); + typedef boost::function read_sd_cb_t; + static void readSDValues(read_sd_cb_t cb, const LLSD& sd, LLInitParam::Parser::name_stack_t& stack); + static void readSDValues(read_sd_cb_t cb, const LLSD& sd); }; -class LL_COMMON_API LLParamSDParser -: public LLInitParam::Parser +class LL_COMMON_API LLParamSDParser +: public LLInitParam::Parser { LOG_CLASS(LLParamSDParser); typedef LLInitParam::Parser parser_t; public: - LLParamSDParser(); - void readSD(const LLSD& sd, LLInitParam::BaseBlock& block, bool silent = false); - template - void writeSD(LLSD& sd, - const BLOCK& block, - const LLInitParam::predicate_rule_t rules = LLInitParam::default_parse_rules(), - const LLInitParam::BaseBlock* diff_block = NULL) - { - if (!diff_block - && !rules.isAmbivalent(LLInitParam::HAS_DEFAULT_VALUE)) - { - diff_block = &LLInitParam::defaultValue(); - } - writeSDImpl(sd, block, rules, diff_block); - } - - /*virtual*/ std::string getCurrentElementName(); - /*virtual*/ std::string getCurrentFileName(){ return LLStringUtil::null; } + LLParamSDParser(); + void readSD(const LLSD& sd, LLInitParam::BaseBlock& block, bool silent = false); + template + void writeSD(LLSD& sd, + const BLOCK& block, + const LLInitParam::predicate_rule_t rules = LLInitParam::default_parse_rules(), + const LLInitParam::BaseBlock* diff_block = NULL) + { + if (!diff_block + && !rules.isAmbivalent(LLInitParam::HAS_DEFAULT_VALUE)) + { + diff_block = &LLInitParam::defaultValue(); + } + writeSDImpl(sd, block, rules, diff_block); + } + + /*virtual*/ std::string getCurrentElementName(); + /*virtual*/ std::string getCurrentFileName(){ return LLStringUtil::null; } private: - void writeSDImpl(LLSD& sd, - const LLInitParam::BaseBlock& block, - const LLInitParam::predicate_rule_t, - const LLInitParam::BaseBlock* diff_block); - - void submit(LLInitParam::BaseBlock& block, const LLSD& sd, LLInitParam::Parser::name_stack_t& name_stack); - - template - static bool writeTypedValue(Parser& parser, const void* val_ptr, parser_t::name_stack_t& name_stack) - { - LLParamSDParser& sdparser = static_cast(parser); - if (!sdparser.mWriteRootSD) return false; - - LLInitParam::Parser::name_stack_range_t range(name_stack.begin(), name_stack.end()); - LLSD& sd_to_write = LLParamSDParserUtilities::getSDWriteNode(*sdparser.mWriteRootSD, range); - - sd_to_write.assign(*((const T*)val_ptr)); - return true; - } - - static bool writeU32Param(Parser& parser, const void* value_ptr, parser_t::name_stack_t& name_stack); - static bool writeFlag(Parser& parser, const void* value_ptr, parser_t::name_stack_t& name_stack); - - static bool readFlag(Parser& parser, void* val_ptr); - static bool readS32(Parser& parser, void* val_ptr); - static bool readU32(Parser& parser, void* val_ptr); - static bool readF32(Parser& parser, void* val_ptr); - static bool readF64(Parser& parser, void* val_ptr); - static bool readBool(Parser& parser, void* val_ptr); - static bool readString(Parser& parser, void* val_ptr); - static bool readUUID(Parser& parser, void* val_ptr); - static bool readDate(Parser& parser, void* val_ptr); - static bool readURI(Parser& parser, void* val_ptr); - static bool readSD(Parser& parser, void* val_ptr); - - Parser::name_stack_t mNameStack; - const LLSD* mCurReadSD; - LLSD* mWriteRootSD; + void writeSDImpl(LLSD& sd, + const LLInitParam::BaseBlock& block, + const LLInitParam::predicate_rule_t, + const LLInitParam::BaseBlock* diff_block); + + void submit(LLInitParam::BaseBlock& block, const LLSD& sd, LLInitParam::Parser::name_stack_t& name_stack); + + template + static bool writeTypedValue(Parser& parser, const void* val_ptr, parser_t::name_stack_t& name_stack) + { + LLParamSDParser& sdparser = static_cast(parser); + if (!sdparser.mWriteRootSD) return false; + + LLInitParam::Parser::name_stack_range_t range(name_stack.begin(), name_stack.end()); + LLSD& sd_to_write = LLParamSDParserUtilities::getSDWriteNode(*sdparser.mWriteRootSD, range); + + sd_to_write.assign(*((const T*)val_ptr)); + return true; + } + + static bool writeU32Param(Parser& parser, const void* value_ptr, parser_t::name_stack_t& name_stack); + static bool writeFlag(Parser& parser, const void* value_ptr, parser_t::name_stack_t& name_stack); + + static bool readFlag(Parser& parser, void* val_ptr); + static bool readS32(Parser& parser, void* val_ptr); + static bool readU32(Parser& parser, void* val_ptr); + static bool readF32(Parser& parser, void* val_ptr); + static bool readF64(Parser& parser, void* val_ptr); + static bool readBool(Parser& parser, void* val_ptr); + static bool readString(Parser& parser, void* val_ptr); + static bool readUUID(Parser& parser, void* val_ptr); + static bool readDate(Parser& parser, void* val_ptr); + static bool readURI(Parser& parser, void* val_ptr); + static bool readSD(Parser& parser, void* val_ptr); + + Parser::name_stack_t mNameStack; + const LLSD* mCurReadSD; + LLSD* mWriteRootSD; }; @@ -114,29 +114,29 @@ template class LLSDParamAdapter : public T { public: - LLSDParamAdapter() {} - LLSDParamAdapter(const LLSD& sd) - { + LLSDParamAdapter() {} + LLSDParamAdapter(const LLSD& sd) + { LL_PROFILE_ZONE_SCOPED; - LLParamSDParser parser; - // don't spam for implicit parsing of LLSD, as we want to allow arbitrary freeform data and ignore most of it - bool parse_silently = true; - parser.readSD(sd, *this, parse_silently); - } - - operator LLSD() const - { - LLParamSDParser parser; - LLSD sd; - parser.writeSD(sd, *this); - return sd; - } - - LLSDParamAdapter(const T& val) - : T(val) - { - T::operator=(val); - } + LLParamSDParser parser; + // don't spam for implicit parsing of LLSD, as we want to allow arbitrary freeform data and ignore most of it + bool parse_silently = true; + parser.readSD(sd, *this, parse_silently); + } + + operator LLSD() const + { + LLParamSDParser parser; + LLSD sd; + parser.writeSD(sd, *this); + return sd; + } + + LLSDParamAdapter(const T& val) + : T(val) + { + T::operator=(val); + } }; #endif // LL_LLSDPARAM_H diff --git a/indra/llcommon/llsdserialize.cpp b/indra/llcommon/llsdserialize.cpp index 76171f2dfd..d5af31a28e 100644 --- a/indra/llcommon/llsdserialize.cpp +++ b/indra/llcommon/llsdserialize.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llsdserialize.cpp * @author Phoenix * @date 2006-03-05 @@ -7,21 +7,21 @@ * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -88,42 +88,42 @@ S32 parse_using(std::istream& istr, LLSD& data, size_t max_bytes, S32 max_depth= // static void LLSDSerialize::serialize(const LLSD& sd, std::ostream& str, ELLSD_Serialize type, - LLSDFormatter::EFormatterOptions options) + LLSDFormatter::EFormatterOptions options) { - LLPointer f = NULL; - - switch (type) - { - case LLSD_BINARY: - str << "\n"; - f = new LLSDBinaryFormatter; - break; - - case LLSD_XML: - str << "\n"; - f = new LLSDXMLFormatter; - break; - - case LLSD_NOTATION: - str << "\n"; - f = new LLSDNotationFormatter; - break; - - default: - LL_WARNS() << "serialize request for unknown ELLSD_Serialize" << LL_ENDL; - } - - if (f.notNull()) - { - f->format(sd, str, options); - } + LLPointer f = NULL; + + switch (type) + { + case LLSD_BINARY: + str << "\n"; + f = new LLSDBinaryFormatter; + break; + + case LLSD_XML: + str << "\n"; + f = new LLSDXMLFormatter; + break; + + case LLSD_NOTATION: + str << "\n"; + f = new LLSDNotationFormatter; + break; + + default: + LL_WARNS() << "serialize request for unknown ELLSD_Serialize" << LL_ENDL; + } + + if (f.notNull()) + { + f->format(sd, str, options); + } } // static bool LLSDSerialize::deserialize(LLSD& sd, std::istream& str, llssize max_bytes) { - char hdr_buf[MAX_HDR_LEN + 1] = ""; /* Flawfinder: ignore */ - bool fail_if_not_legacy = false; + char hdr_buf[MAX_HDR_LEN + 1] = ""; /* Flawfinder: ignore */ + bool fail_if_not_legacy = false; /* * Get the first line before anything. Don't read more than max_bytes: @@ -132,125 +132,125 @@ bool LLSDSerialize::deserialize(LLSD& sd, std::istream& str, llssize max_bytes) * sizeof(hdr_buf), get() will read no more than sizeof(hdr_buf)-2. */ llssize max_hdr_read = MAX_HDR_LEN; - if (max_bytes != LLSDSerialize::SIZE_UNLIMITED) - { + if (max_bytes != LLSDSerialize::SIZE_UNLIMITED) + { max_hdr_read = llmin(max_bytes + 1, max_hdr_read); - } + } str.get(hdr_buf, max_hdr_read, '\n'); - auto inbuf = str.gcount(); - - // https://en.cppreference.com/w/cpp/io/basic_istream/get - // When the get() above sees the specified delimiter '\n', it stops there - // without pulling it from the stream. If it turns out that the stream - // does NOT contain a header, and the content includes meaningful '\n', - // it's important to pull that into hdr_buf too. - if (inbuf < max_bytes && str.get(hdr_buf[inbuf])) - { - // got the delimiting '\n' - ++inbuf; - // None of the following requires that hdr_buf contain a final '\0' - // byte. We could store one if needed, since even the incremented - // inbuf won't exceed sizeof(hdr_buf)-1, but there's no need. - } - std::string header{ hdr_buf, static_cast(inbuf) }; - if (str.fail()) - { - str.clear(); - fail_if_not_legacy = true; - } - - if (!strncasecmp(LEGACY_NON_HEADER, hdr_buf, strlen(LEGACY_NON_HEADER))) /* Flawfinder: ignore */ - { // Create a LLSD XML parser, and parse the first chunk read above. - LLSDXMLParser x; - x.parsePart(hdr_buf, inbuf); // Parse the first part that was already read - auto parsed = x.parse(str, sd, max_bytes - inbuf); // Parse the rest of it - // Formally we should probably check (parsed != PARSE_FAILURE && - // parsed > 0), but since PARSE_FAILURE is -1, this suffices. - return (parsed > 0); - } - - if (fail_if_not_legacy) - { - LL_WARNS() << "deserialize LLSD parse failure" << LL_ENDL; - return false; - } - - /* - * Remove the newline chars - */ - std::string::size_type lastchar = header.find_last_not_of("\r\n"); - if (lastchar != std::string::npos) - { - // It's important that find_last_not_of() returns size_type, which is - // why lastchar explicitly declares the type above. erase(size_type) - // erases from that offset to the end of the string, whereas - // erase(iterator) erases only a single character. - header.erase(lastchar+1); - } - - // trim off the header syntax - auto start = header.find_first_not_of("(str, sd, max_bytes-inbuf) > 0); - } - else if (0 == LLStringUtil::compareInsensitive(header, LLSD_XML_HEADER)) - { - return (parse_using(str, sd, max_bytes-inbuf) > 0); - } - else if (0 == LLStringUtil::compareInsensitive(header, LLSD_NOTATION_HEADER)) - { - return (parse_using(str, sd, max_bytes-inbuf) > 0); - } - else // no header we recognize - { - LLPointer p; - if (inbuf && hdr_buf[0] == '<') - { - // looks like XML - LL_DEBUGS() << "deserialize request with no header, assuming XML" << LL_ENDL; - p = new LLSDXMLParser; - } - else - { - // assume notation - LL_DEBUGS() << "deserialize request with no header, assuming notation" << LL_ENDL; - p = new LLSDNotationParser; - } - // Since we've already read 'inbuf' bytes into 'hdr_buf', prepend that - // data to whatever remains in 'str'. - LLMemoryStreamBuf already(reinterpret_cast(hdr_buf), inbuf); - cat_streambuf prebuff(&already, str.rdbuf()); - std::istream prepend(&prebuff); + auto inbuf = str.gcount(); + + // https://en.cppreference.com/w/cpp/io/basic_istream/get + // When the get() above sees the specified delimiter '\n', it stops there + // without pulling it from the stream. If it turns out that the stream + // does NOT contain a header, and the content includes meaningful '\n', + // it's important to pull that into hdr_buf too. + if (inbuf < max_bytes && str.get(hdr_buf[inbuf])) + { + // got the delimiting '\n' + ++inbuf; + // None of the following requires that hdr_buf contain a final '\0' + // byte. We could store one if needed, since even the incremented + // inbuf won't exceed sizeof(hdr_buf)-1, but there's no need. + } + std::string header{ hdr_buf, static_cast(inbuf) }; + if (str.fail()) + { + str.clear(); + fail_if_not_legacy = true; + } + + if (!strncasecmp(LEGACY_NON_HEADER, hdr_buf, strlen(LEGACY_NON_HEADER))) /* Flawfinder: ignore */ + { // Create a LLSD XML parser, and parse the first chunk read above. + LLSDXMLParser x; + x.parsePart(hdr_buf, inbuf); // Parse the first part that was already read + auto parsed = x.parse(str, sd, max_bytes - inbuf); // Parse the rest of it + // Formally we should probably check (parsed != PARSE_FAILURE && + // parsed > 0), but since PARSE_FAILURE is -1, this suffices. + return (parsed > 0); + } + + if (fail_if_not_legacy) + { + LL_WARNS() << "deserialize LLSD parse failure" << LL_ENDL; + return false; + } + + /* + * Remove the newline chars + */ + std::string::size_type lastchar = header.find_last_not_of("\r\n"); + if (lastchar != std::string::npos) + { + // It's important that find_last_not_of() returns size_type, which is + // why lastchar explicitly declares the type above. erase(size_type) + // erases from that offset to the end of the string, whereas + // erase(iterator) erases only a single character. + header.erase(lastchar+1); + } + + // trim off the header syntax + auto start = header.find_first_not_of("(str, sd, max_bytes-inbuf) > 0); + } + else if (0 == LLStringUtil::compareInsensitive(header, LLSD_XML_HEADER)) + { + return (parse_using(str, sd, max_bytes-inbuf) > 0); + } + else if (0 == LLStringUtil::compareInsensitive(header, LLSD_NOTATION_HEADER)) + { + return (parse_using(str, sd, max_bytes-inbuf) > 0); + } + else // no header we recognize + { + LLPointer p; + if (inbuf && hdr_buf[0] == '<') + { + // looks like XML + LL_DEBUGS() << "deserialize request with no header, assuming XML" << LL_ENDL; + p = new LLSDXMLParser; + } + else + { + // assume notation + LL_DEBUGS() << "deserialize request with no header, assuming notation" << LL_ENDL; + p = new LLSDNotationParser; + } + // Since we've already read 'inbuf' bytes into 'hdr_buf', prepend that + // data to whatever remains in 'str'. + LLMemoryStreamBuf already(reinterpret_cast(hdr_buf), inbuf); + cat_streambuf prebuff(&already, str.rdbuf()); + std::istream prepend(&prebuff); #if 1 - return (p->parse(prepend, sd, max_bytes) > 0); + return (p->parse(prepend, sd, max_bytes) > 0); #else - // debugging the reconstituted 'prepend' stream - // allocate a buffer that we hope is big enough for the whole thing - std::vector wholemsg((max_bytes == size_t(SIZE_UNLIMITED))? 1024 : max_bytes); - prepend.read(wholemsg.data(), std::min(max_bytes, wholemsg.size())); - LLMemoryStream replay(reinterpret_cast(wholemsg.data()), prepend.gcount()); - auto success{ p->parse(replay, sd, prepend.gcount()) > 0 }; - { - LL_DEBUGS() << (success? "parsed: $$" : "failed: '") - << std::string(wholemsg.data(), llmin(prepend.gcount(), 100)) << "$$" - << LL_ENDL; - } - return success; + // debugging the reconstituted 'prepend' stream + // allocate a buffer that we hope is big enough for the whole thing + std::vector wholemsg((max_bytes == size_t(SIZE_UNLIMITED))? 1024 : max_bytes); + prepend.read(wholemsg.data(), std::min(max_bytes, wholemsg.size())); + LLMemoryStream replay(reinterpret_cast(wholemsg.data()), prepend.gcount()); + auto success{ p->parse(replay, sd, prepend.gcount()) > 0 }; + { + LL_DEBUGS() << (success? "parsed: $$" : "failed: '") + << std::string(wholemsg.data(), llmin(prepend.gcount(), 100)) << "$$" + << LL_ENDL; + } + return success; #endif - } + } } /** @@ -268,32 +268,32 @@ F64 ll_ntohd(F64 netlonglong) { return netlonglong; } // operation. U64 ll_htonll(U64 hostlonglong) { - return ((U64)(htonl((U32)((hostlonglong >> 32) & 0xFFFFFFFF))) | - ((U64)(htonl((U32)(hostlonglong & 0xFFFFFFFF))) << 32)); + return ((U64)(htonl((U32)((hostlonglong >> 32) & 0xFFFFFFFF))) | + ((U64)(htonl((U32)(hostlonglong & 0xFFFFFFFF))) << 32)); } U64 ll_ntohll(U64 netlonglong) { - return ((U64)(ntohl((U32)((netlonglong >> 32) & 0xFFFFFFFF))) | - ((U64)(ntohl((U32)(netlonglong & 0xFFFFFFFF))) << 32)); + return ((U64)(ntohl((U32)((netlonglong >> 32) & 0xFFFFFFFF))) | + ((U64)(ntohl((U32)(netlonglong & 0xFFFFFFFF))) << 32)); } union LLEndianSwapper { - F64 d; - U64 i; + F64 d; + U64 i; }; F64 ll_htond(F64 hostdouble) { - LLEndianSwapper tmp; - tmp.d = hostdouble; - tmp.i = ll_htonll(tmp.i); - return tmp.d; + LLEndianSwapper tmp; + tmp.d = hostdouble; + tmp.i = ll_htonll(tmp.i); + return tmp.d; } F64 ll_ntohd(F64 netdouble) { - LLEndianSwapper tmp; - tmp.d = netdouble; - tmp.i = ll_ntohll(tmp.i); - return tmp.d; + LLEndianSwapper tmp; + tmp.d = netdouble; + tmp.i = ll_ntohll(tmp.i); + return tmp.d; } #endif @@ -313,7 +313,7 @@ F64 ll_ntohd(F64 netdouble) llssize deserialize_string(std::istream& istr, std::string& value, llssize max_bytes); /** - * @brief Parse a delimited string. + * @brief Parse a delimited string. * * @param istr The stream to read from, with the delimiter already popped. * @param value [out] The string which was found. @@ -336,9 +336,9 @@ llssize deserialize_string_delim(std::istream& istr, std::string& value, char d) * PARSE_FAILURE (-1) on failure. */ llssize deserialize_string_raw( - std::istream& istr, - std::string& value, - llssize max_bytes); + std::istream& istr, + std::string& value, + llssize max_bytes); /** * @brief helper method for dealing with the different notation boolean format. @@ -351,10 +351,10 @@ llssize deserialize_string_raw( * PARSE_FAILURE (-1) on failure. */ llssize deserialize_boolean( - std::istream& istr, - LLSD& data, - const std::string& compare, - bool value); + std::istream& istr, + LLSD& data, + const std::string& compare, + bool value); /** * @brief Do notation escaping of a string to an ostream. @@ -379,7 +379,7 @@ static const char BINARY_FALSE_SERIAL = '0'; * LLSDParser */ LLSDParser::LLSDParser() - : mCheckLimits(true), mMaxBytesLeft(0), mParseLines(false) + : mCheckLimits(true), mMaxBytesLeft(0), mParseLines(false) { } @@ -389,75 +389,75 @@ LLSDParser::~LLSDParser() S32 LLSDParser::parse(std::istream& istr, LLSD& data, llssize max_bytes, S32 max_depth) { - mCheckLimits = (LLSDSerialize::SIZE_UNLIMITED == max_bytes) ? false : true; - mMaxBytesLeft = max_bytes; - return doParse(istr, data, max_depth); + mCheckLimits = (LLSDSerialize::SIZE_UNLIMITED == max_bytes) ? false : true; + mMaxBytesLeft = max_bytes; + return doParse(istr, data, max_depth); } // Parse using routine to get() lines, faster than parse() S32 LLSDParser::parseLines(std::istream& istr, LLSD& data) { - mCheckLimits = false; - mParseLines = true; - return doParse(istr, data); + mCheckLimits = false; + mParseLines = true; + return doParse(istr, data); } int LLSDParser::get(std::istream& istr) const { - if(mCheckLimits) --mMaxBytesLeft; - return istr.get(); + if(mCheckLimits) --mMaxBytesLeft; + return istr.get(); } std::istream& LLSDParser::get( - std::istream& istr, - char* s, - std::streamsize n, - char delim) const + std::istream& istr, + char* s, + std::streamsize n, + char delim) const { - istr.get(s, n, delim); - if(mCheckLimits) mMaxBytesLeft -= istr.gcount(); - return istr; + istr.get(s, n, delim); + if(mCheckLimits) mMaxBytesLeft -= istr.gcount(); + return istr; } std::istream& LLSDParser::get( - std::istream& istr, - std::streambuf& sb, - char delim) const + std::istream& istr, + std::streambuf& sb, + char delim) const { - istr.get(sb, delim); - if(mCheckLimits) mMaxBytesLeft -= istr.gcount(); - return istr; + istr.get(sb, delim); + if(mCheckLimits) mMaxBytesLeft -= istr.gcount(); + return istr; } std::istream& LLSDParser::ignore(std::istream& istr) const { - istr.ignore(); - if(mCheckLimits) --mMaxBytesLeft; - return istr; + istr.ignore(); + if(mCheckLimits) --mMaxBytesLeft; + return istr; } std::istream& LLSDParser::putback(std::istream& istr, char c) const { - istr.putback(c); - if(mCheckLimits) ++mMaxBytesLeft; - return istr; + istr.putback(c); + if(mCheckLimits) ++mMaxBytesLeft; + return istr; } std::istream& LLSDParser::read( - std::istream& istr, - char* s, - std::streamsize n) const + std::istream& istr, + char* s, + std::streamsize n) const { - istr.read(s, n); - if(mCheckLimits) mMaxBytesLeft -= istr.gcount(); - return istr; + istr.read(s, n); + if(mCheckLimits) mMaxBytesLeft -= istr.gcount(); + return istr; } void LLSDParser::account(llssize bytes) const { - if(mCheckLimits) mMaxBytesLeft -= bytes; + if(mCheckLimits) mMaxBytesLeft -= bytes; } @@ -466,7 +466,7 @@ void LLSDParser::account(llssize bytes) const */ LLSDNotationParser::LLSDNotationParser() { -} +} // virtual LLSDNotationParser::~LLSDNotationParser() @@ -475,463 +475,463 @@ LLSDNotationParser::~LLSDNotationParser() // virtual S32 LLSDNotationParser::doParse(std::istream& istr, LLSD& data, S32 max_depth) const { - LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD - // map: { string:object, string:object } - // array: [ object, object, object ] - // undef: ! - // boolean: true | false | 1 | 0 | T | F | t | f | TRUE | FALSE - // integer: i#### - // real: r#### - // uuid: u#### - // string: "g'day" | 'have a "nice" day' | s(size)"raw data" - // uri: l"escaped" - // date: d"YYYY-MM-DDTHH:MM:SS.FFZ" - // binary: b##"ff3120ab1" | b(size)"raw data" - char c; - c = istr.peek(); - if (max_depth == 0) - { - return PARSE_FAILURE; - } - while(isspace(c)) - { - // pop the whitespace. - c = get(istr); - c = istr.peek(); - continue; - } - if(!istr.good()) - { - return 0; - } - S32 parse_count = 1; - switch(c) - { - case '{': - { - S32 child_count = parseMap(istr, data, max_depth - 1); - if((child_count == PARSE_FAILURE) || data.isUndefined()) - { - parse_count = PARSE_FAILURE; - } - else - { - parse_count += child_count; - } - if(istr.fail()) - { - LL_INFOS() << "STREAM FAILURE reading map." << LL_ENDL; - parse_count = PARSE_FAILURE; - } - break; - } - - case '[': - { - S32 child_count = parseArray(istr, data, max_depth - 1); - if((child_count == PARSE_FAILURE) || data.isUndefined()) - { - parse_count = PARSE_FAILURE; - } - else - { - parse_count += child_count; - } - if(istr.fail()) - { - LL_INFOS() << "STREAM FAILURE reading array." << LL_ENDL; - parse_count = PARSE_FAILURE; - } - break; - } - - case '!': - c = get(istr); - data.clear(); - break; - - case '0': - c = get(istr); - data = false; - break; - - case 'F': - case 'f': - ignore(istr); - c = istr.peek(); - if(isalpha(c)) - { - auto cnt = deserialize_boolean( - istr, - data, - NOTATION_FALSE_SERIAL, - false); - if(PARSE_FAILURE == cnt) parse_count = cnt; - else account(cnt); - } - else - { - data = false; - } - if(istr.fail()) - { - LL_INFOS() << "STREAM FAILURE reading boolean." << LL_ENDL; - parse_count = PARSE_FAILURE; - } - break; - - case '1': - c = get(istr); - data = true; - break; - - case 'T': - case 't': - ignore(istr); - c = istr.peek(); - if(isalpha(c)) - { - auto cnt = deserialize_boolean(istr,data,NOTATION_TRUE_SERIAL,true); - if(PARSE_FAILURE == cnt) parse_count = cnt; - else account(cnt); - } - else - { - data = true; - } - if(istr.fail()) - { - LL_INFOS() << "STREAM FAILURE reading boolean." << LL_ENDL; - parse_count = PARSE_FAILURE; - } - break; - - case 'i': - { - c = get(istr); - S32 integer = 0; - istr >> integer; - data = integer; - if(istr.fail()) - { - LL_INFOS() << "STREAM FAILURE reading integer." << LL_ENDL; - parse_count = PARSE_FAILURE; - } - break; - } - - case 'r': - { - c = get(istr); - F64 real = 0.0; - istr >> real; - data = real; - if(istr.fail()) - { - LL_INFOS() << "STREAM FAILURE reading real." << LL_ENDL; - parse_count = PARSE_FAILURE; - } - break; - } - - case 'u': - { - c = get(istr); - LLUUID id; - istr >> id; - data = id; - if(istr.fail()) - { - LL_INFOS() << "STREAM FAILURE reading uuid." << LL_ENDL; - parse_count = PARSE_FAILURE; - } - break; - } - - case '\"': - case '\'': - case 's': - if(!parseString(istr, data)) - { - parse_count = PARSE_FAILURE; - } - if(istr.fail()) - { - LL_INFOS() << "STREAM FAILURE reading string." << LL_ENDL; - parse_count = PARSE_FAILURE; - } - break; - - case 'l': - { - c = get(istr); // pop the 'l' - c = get(istr); // pop the delimiter - std::string str; - auto cnt = deserialize_string_delim(istr, str, c); - if(PARSE_FAILURE == cnt) - { - parse_count = PARSE_FAILURE; - } - else - { - data = LLURI(str); - account(cnt); - } - if(istr.fail()) - { - LL_INFOS() << "STREAM FAILURE reading link." << LL_ENDL; - parse_count = PARSE_FAILURE; - } - break; - } - - case 'd': - { - c = get(istr); // pop the 'd' - c = get(istr); // pop the delimiter - std::string str; - auto cnt = deserialize_string_delim(istr, str, c); - if(PARSE_FAILURE == cnt) - { - parse_count = PARSE_FAILURE; - } - else - { - data = LLDate(str); - account(cnt); - } - if(istr.fail()) - { - LL_INFOS() << "STREAM FAILURE reading date." << LL_ENDL; - parse_count = PARSE_FAILURE; - } - break; - } - - case 'b': - if(!parseBinary(istr, data)) - { - parse_count = PARSE_FAILURE; - } - if(istr.fail()) - { - LL_INFOS() << "STREAM FAILURE reading data." << LL_ENDL; - parse_count = PARSE_FAILURE; - } - break; - - default: - parse_count = PARSE_FAILURE; - LL_INFOS() << "Unrecognized character while parsing: int(" << int(c) - << ")" << LL_ENDL; - break; - } - if(PARSE_FAILURE == parse_count) - { - data.clear(); - } - return parse_count; + LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD + // map: { string:object, string:object } + // array: [ object, object, object ] + // undef: ! + // boolean: true | false | 1 | 0 | T | F | t | f | TRUE | FALSE + // integer: i#### + // real: r#### + // uuid: u#### + // string: "g'day" | 'have a "nice" day' | s(size)"raw data" + // uri: l"escaped" + // date: d"YYYY-MM-DDTHH:MM:SS.FFZ" + // binary: b##"ff3120ab1" | b(size)"raw data" + char c; + c = istr.peek(); + if (max_depth == 0) + { + return PARSE_FAILURE; + } + while(isspace(c)) + { + // pop the whitespace. + c = get(istr); + c = istr.peek(); + continue; + } + if(!istr.good()) + { + return 0; + } + S32 parse_count = 1; + switch(c) + { + case '{': + { + S32 child_count = parseMap(istr, data, max_depth - 1); + if((child_count == PARSE_FAILURE) || data.isUndefined()) + { + parse_count = PARSE_FAILURE; + } + else + { + parse_count += child_count; + } + if(istr.fail()) + { + LL_INFOS() << "STREAM FAILURE reading map." << LL_ENDL; + parse_count = PARSE_FAILURE; + } + break; + } + + case '[': + { + S32 child_count = parseArray(istr, data, max_depth - 1); + if((child_count == PARSE_FAILURE) || data.isUndefined()) + { + parse_count = PARSE_FAILURE; + } + else + { + parse_count += child_count; + } + if(istr.fail()) + { + LL_INFOS() << "STREAM FAILURE reading array." << LL_ENDL; + parse_count = PARSE_FAILURE; + } + break; + } + + case '!': + c = get(istr); + data.clear(); + break; + + case '0': + c = get(istr); + data = false; + break; + + case 'F': + case 'f': + ignore(istr); + c = istr.peek(); + if(isalpha(c)) + { + auto cnt = deserialize_boolean( + istr, + data, + NOTATION_FALSE_SERIAL, + false); + if(PARSE_FAILURE == cnt) parse_count = cnt; + else account(cnt); + } + else + { + data = false; + } + if(istr.fail()) + { + LL_INFOS() << "STREAM FAILURE reading boolean." << LL_ENDL; + parse_count = PARSE_FAILURE; + } + break; + + case '1': + c = get(istr); + data = true; + break; + + case 'T': + case 't': + ignore(istr); + c = istr.peek(); + if(isalpha(c)) + { + auto cnt = deserialize_boolean(istr,data,NOTATION_TRUE_SERIAL,true); + if(PARSE_FAILURE == cnt) parse_count = cnt; + else account(cnt); + } + else + { + data = true; + } + if(istr.fail()) + { + LL_INFOS() << "STREAM FAILURE reading boolean." << LL_ENDL; + parse_count = PARSE_FAILURE; + } + break; + + case 'i': + { + c = get(istr); + S32 integer = 0; + istr >> integer; + data = integer; + if(istr.fail()) + { + LL_INFOS() << "STREAM FAILURE reading integer." << LL_ENDL; + parse_count = PARSE_FAILURE; + } + break; + } + + case 'r': + { + c = get(istr); + F64 real = 0.0; + istr >> real; + data = real; + if(istr.fail()) + { + LL_INFOS() << "STREAM FAILURE reading real." << LL_ENDL; + parse_count = PARSE_FAILURE; + } + break; + } + + case 'u': + { + c = get(istr); + LLUUID id; + istr >> id; + data = id; + if(istr.fail()) + { + LL_INFOS() << "STREAM FAILURE reading uuid." << LL_ENDL; + parse_count = PARSE_FAILURE; + } + break; + } + + case '\"': + case '\'': + case 's': + if(!parseString(istr, data)) + { + parse_count = PARSE_FAILURE; + } + if(istr.fail()) + { + LL_INFOS() << "STREAM FAILURE reading string." << LL_ENDL; + parse_count = PARSE_FAILURE; + } + break; + + case 'l': + { + c = get(istr); // pop the 'l' + c = get(istr); // pop the delimiter + std::string str; + auto cnt = deserialize_string_delim(istr, str, c); + if(PARSE_FAILURE == cnt) + { + parse_count = PARSE_FAILURE; + } + else + { + data = LLURI(str); + account(cnt); + } + if(istr.fail()) + { + LL_INFOS() << "STREAM FAILURE reading link." << LL_ENDL; + parse_count = PARSE_FAILURE; + } + break; + } + + case 'd': + { + c = get(istr); // pop the 'd' + c = get(istr); // pop the delimiter + std::string str; + auto cnt = deserialize_string_delim(istr, str, c); + if(PARSE_FAILURE == cnt) + { + parse_count = PARSE_FAILURE; + } + else + { + data = LLDate(str); + account(cnt); + } + if(istr.fail()) + { + LL_INFOS() << "STREAM FAILURE reading date." << LL_ENDL; + parse_count = PARSE_FAILURE; + } + break; + } + + case 'b': + if(!parseBinary(istr, data)) + { + parse_count = PARSE_FAILURE; + } + if(istr.fail()) + { + LL_INFOS() << "STREAM FAILURE reading data." << LL_ENDL; + parse_count = PARSE_FAILURE; + } + break; + + default: + parse_count = PARSE_FAILURE; + LL_INFOS() << "Unrecognized character while parsing: int(" << int(c) + << ")" << LL_ENDL; + break; + } + if(PARSE_FAILURE == parse_count) + { + data.clear(); + } + return parse_count; } S32 LLSDNotationParser::parseMap(std::istream& istr, LLSD& map, S32 max_depth) const { - LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD - // map: { string:object, string:object } - map = LLSD::emptyMap(); - S32 parse_count = 0; - char c = get(istr); - if(c == '{') - { - // eat commas, white - bool found_name = false; - std::string name; - c = get(istr); - while(c != '}' && istr.good()) - { - if(!found_name) - { - if((c == '\"') || (c == '\'') || (c == 's')) - { - putback(istr, c); - found_name = true; - auto count = deserialize_string(istr, name, mMaxBytesLeft); - if(PARSE_FAILURE == count) return PARSE_FAILURE; - account(count); - } - c = get(istr); - } - else - { - if(isspace(c) || (c == ':')) - { - c = get(istr); - continue; - } - putback(istr, c); - LLSD child; - S32 count = doParse(istr, child, max_depth); - if(count > 0) - { - // There must be a value for every key, thus - // child_count must be greater than 0. - parse_count += count; - map.insert(name, child); - } - else - { - return PARSE_FAILURE; - } - found_name = false; - c = get(istr); - } - } - if(c != '}') - { - map.clear(); - return PARSE_FAILURE; - } - } - return parse_count; + LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD + // map: { string:object, string:object } + map = LLSD::emptyMap(); + S32 parse_count = 0; + char c = get(istr); + if(c == '{') + { + // eat commas, white + bool found_name = false; + std::string name; + c = get(istr); + while(c != '}' && istr.good()) + { + if(!found_name) + { + if((c == '\"') || (c == '\'') || (c == 's')) + { + putback(istr, c); + found_name = true; + auto count = deserialize_string(istr, name, mMaxBytesLeft); + if(PARSE_FAILURE == count) return PARSE_FAILURE; + account(count); + } + c = get(istr); + } + else + { + if(isspace(c) || (c == ':')) + { + c = get(istr); + continue; + } + putback(istr, c); + LLSD child; + S32 count = doParse(istr, child, max_depth); + if(count > 0) + { + // There must be a value for every key, thus + // child_count must be greater than 0. + parse_count += count; + map.insert(name, child); + } + else + { + return PARSE_FAILURE; + } + found_name = false; + c = get(istr); + } + } + if(c != '}') + { + map.clear(); + return PARSE_FAILURE; + } + } + return parse_count; } S32 LLSDNotationParser::parseArray(std::istream& istr, LLSD& array, S32 max_depth) const { - LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD - // array: [ object, object, object ] - array = LLSD::emptyArray(); - S32 parse_count = 0; - char c = get(istr); - if(c == '[') - { - // eat commas, white - c = get(istr); - while((c != ']') && istr.good()) - { - LLSD child; - if(isspace(c) || (c == ',')) - { - c = get(istr); - continue; - } - putback(istr, c); - S32 count = doParse(istr, child, max_depth); - if(PARSE_FAILURE == count) - { - return PARSE_FAILURE; - } - else - { - parse_count += count; - array.append(child); - } - c = get(istr); - } - if(c != ']') - { - return PARSE_FAILURE; - } - } - return parse_count; + LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD + // array: [ object, object, object ] + array = LLSD::emptyArray(); + S32 parse_count = 0; + char c = get(istr); + if(c == '[') + { + // eat commas, white + c = get(istr); + while((c != ']') && istr.good()) + { + LLSD child; + if(isspace(c) || (c == ',')) + { + c = get(istr); + continue; + } + putback(istr, c); + S32 count = doParse(istr, child, max_depth); + if(PARSE_FAILURE == count) + { + return PARSE_FAILURE; + } + else + { + parse_count += count; + array.append(child); + } + c = get(istr); + } + if(c != ']') + { + return PARSE_FAILURE; + } + } + return parse_count; } bool LLSDNotationParser::parseString(std::istream& istr, LLSD& data) const { - LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD - std::string value; - auto count = deserialize_string(istr, value, mMaxBytesLeft); - if(PARSE_FAILURE == count) return false; - account(count); - data = value; - return true; + LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD + std::string value; + auto count = deserialize_string(istr, value, mMaxBytesLeft); + if(PARSE_FAILURE == count) return false; + account(count); + data = value; + return true; } bool LLSDNotationParser::parseBinary(std::istream& istr, LLSD& data) const { - LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD - // binary: b##"ff3120ab1" - // or: b(len)"..." - - // I want to manually control those values here to make sure the - // parser doesn't break when someone changes a constant somewhere - // else. - const U32 BINARY_BUFFER_SIZE = 256; - const U32 STREAM_GET_COUNT = 255; - - // need to read the base out. - char buf[BINARY_BUFFER_SIZE]; /* Flawfinder: ignore */ - get(istr, buf, STREAM_GET_COUNT, '"'); - char c = get(istr); - if(c != '"') return false; - if(0 == strncmp("b(", buf, 2)) - { - // We probably have a valid raw binary stream. determine - // the size, and read it. - auto len = strtol(buf + 2, NULL, 0); - if(mCheckLimits && (len > mMaxBytesLeft)) return false; - std::vector value; - if(len) - { - value.resize(len); - account(fullread(istr, (char *)&value[0], len)); - } - c = get(istr); // strip off the trailing double-quote - data = value; - } - else if(0 == strncmp("b64", buf, 3)) - { - // *FIX: A bit inefficient, but works for now. To make the - // format better, I would need to add a hint into the - // serialization format that indicated how long it was. - std::stringstream coded_stream; - get(istr, *(coded_stream.rdbuf()), '\"'); - c = get(istr); - std::string encoded(coded_stream.str()); - S32 len = apr_base64_decode_len(encoded.c_str()); - std::vector value; - if(len) - { - value.resize(len); - len = apr_base64_decode_binary(&value[0], encoded.c_str()); - value.resize(len); - } - data = value; - } - else if(0 == strncmp("b16", buf, 3)) - { - // yay, base 16. We pop the next character which is either a - // double quote or base 16 data. If it's a double quote, we're - // done parsing. If it's not, put the data back, and read the - // stream until the next double quote. - char* read; /*Flawfinder: ignore*/ - U8 byte; - U8 byte_buffer[BINARY_BUFFER_SIZE]; - U8* write; - std::vector value; - c = get(istr); - while(c != '"') - { - putback(istr, c); - read = buf; - write = byte_buffer; - get(istr, buf, STREAM_GET_COUNT, '"'); - c = get(istr); - while(*read != '\0') /*Flawfinder: ignore*/ - { - byte = hex_as_nybble(*read++); - byte = byte << 4; - byte |= hex_as_nybble(*read++); - *write++ = byte; - } - // copy the data out of the byte buffer - value.insert(value.end(), byte_buffer, write); - } - data = value; - } - else - { - return false; - } - return true; + LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD + // binary: b##"ff3120ab1" + // or: b(len)"..." + + // I want to manually control those values here to make sure the + // parser doesn't break when someone changes a constant somewhere + // else. + const U32 BINARY_BUFFER_SIZE = 256; + const U32 STREAM_GET_COUNT = 255; + + // need to read the base out. + char buf[BINARY_BUFFER_SIZE]; /* Flawfinder: ignore */ + get(istr, buf, STREAM_GET_COUNT, '"'); + char c = get(istr); + if(c != '"') return false; + if(0 == strncmp("b(", buf, 2)) + { + // We probably have a valid raw binary stream. determine + // the size, and read it. + auto len = strtol(buf + 2, NULL, 0); + if(mCheckLimits && (len > mMaxBytesLeft)) return false; + std::vector value; + if(len) + { + value.resize(len); + account(fullread(istr, (char *)&value[0], len)); + } + c = get(istr); // strip off the trailing double-quote + data = value; + } + else if(0 == strncmp("b64", buf, 3)) + { + // *FIX: A bit inefficient, but works for now. To make the + // format better, I would need to add a hint into the + // serialization format that indicated how long it was. + std::stringstream coded_stream; + get(istr, *(coded_stream.rdbuf()), '\"'); + c = get(istr); + std::string encoded(coded_stream.str()); + S32 len = apr_base64_decode_len(encoded.c_str()); + std::vector value; + if(len) + { + value.resize(len); + len = apr_base64_decode_binary(&value[0], encoded.c_str()); + value.resize(len); + } + data = value; + } + else if(0 == strncmp("b16", buf, 3)) + { + // yay, base 16. We pop the next character which is either a + // double quote or base 16 data. If it's a double quote, we're + // done parsing. If it's not, put the data back, and read the + // stream until the next double quote. + char* read; /*Flawfinder: ignore*/ + U8 byte; + U8 byte_buffer[BINARY_BUFFER_SIZE]; + U8* write; + std::vector value; + c = get(istr); + while(c != '"') + { + putback(istr, c); + read = buf; + write = byte_buffer; + get(istr, buf, STREAM_GET_COUNT, '"'); + c = get(istr); + while(*read != '\0') /*Flawfinder: ignore*/ + { + byte = hex_as_nybble(*read++); + byte = byte << 4; + byte |= hex_as_nybble(*read++); + *write++ = byte; + } + // copy the data out of the byte buffer + value.insert(value.end(), byte_buffer, write); + } + data = value; + } + else + { + return false; + } + return true; } @@ -950,7 +950,7 @@ LLSDBinaryParser::~LLSDBinaryParser() // virtual S32 LLSDBinaryParser::doParse(std::istream& istr, LLSD& data, S32 max_depth) const { - LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD + LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD /** * Undefined: '!'
* Boolean: '1' for true '0' for false
@@ -967,332 +967,332 @@ S32 LLSDBinaryParser::doParse(std::istream& istr, LLSD& data, S32 max_depth) con * map keys are serialized as s + 4 byte integer size + string or in the * notation format. */ - char c; - c = get(istr); - if(!istr.good()) - { - return 0; - } - if (max_depth == 0) - { - return PARSE_FAILURE; - } - S32 parse_count = 1; - switch(c) - { - case '{': - { - S32 child_count = parseMap(istr, data, max_depth - 1); - if((child_count == PARSE_FAILURE) || data.isUndefined()) - { - parse_count = PARSE_FAILURE; - } - else - { - parse_count += child_count; - } - if(istr.fail()) - { - LL_INFOS() << "STREAM FAILURE reading binary map." << LL_ENDL; - parse_count = PARSE_FAILURE; - } - break; - } - - case '[': - { - S32 child_count = parseArray(istr, data, max_depth - 1); - if((child_count == PARSE_FAILURE) || data.isUndefined()) - { - parse_count = PARSE_FAILURE; - } - else - { - parse_count += child_count; - } - if(istr.fail()) - { - LL_INFOS() << "STREAM FAILURE reading binary array." << LL_ENDL; - parse_count = PARSE_FAILURE; - } - break; - } - - case '!': - data.clear(); - break; - - case '0': - data = false; - break; - - case '1': - data = true; - break; - - case 'i': - { - U32 value_nbo = 0; - read(istr, (char*)&value_nbo, sizeof(U32)); /*Flawfinder: ignore*/ - data = (S32)ntohl(value_nbo); - if(istr.fail()) - { - LL_INFOS() << "STREAM FAILURE reading binary integer." << LL_ENDL; - } - break; - } - - case 'r': - { - F64 real_nbo = 0.0; - read(istr, (char*)&real_nbo, sizeof(F64)); /*Flawfinder: ignore*/ - data = ll_ntohd(real_nbo); - if(istr.fail()) - { - LL_INFOS() << "STREAM FAILURE reading binary real." << LL_ENDL; - } - break; - } - - case 'u': - { - LLUUID id; - read(istr, (char*)(&id.mData), UUID_BYTES); /*Flawfinder: ignore*/ - data = id; - if(istr.fail()) - { - LL_INFOS() << "STREAM FAILURE reading binary uuid." << LL_ENDL; - } - break; - } - - case '\'': - case '"': - { - std::string value; - auto cnt = deserialize_string_delim(istr, value, c); - if(PARSE_FAILURE == cnt) - { - parse_count = PARSE_FAILURE; - } - else - { - data = value; - account(cnt); - } - if(istr.fail()) - { - LL_INFOS() << "STREAM FAILURE reading binary (notation-style) string." - << LL_ENDL; - parse_count = PARSE_FAILURE; - } - break; - } - - case 's': - { - std::string value; - if(parseString(istr, value)) - { - data = value; - } - else - { - parse_count = PARSE_FAILURE; - } - if(istr.fail()) - { - LL_INFOS() << "STREAM FAILURE reading binary string." << LL_ENDL; - parse_count = PARSE_FAILURE; - } - break; - } - - case 'l': - { - std::string value; - if(parseString(istr, value)) - { - data = LLURI(value); - } - else - { - parse_count = PARSE_FAILURE; - } - if(istr.fail()) - { - LL_INFOS() << "STREAM FAILURE reading binary link." << LL_ENDL; - parse_count = PARSE_FAILURE; - } - break; - } - - case 'd': - { - F64 real = 0.0; - read(istr, (char*)&real, sizeof(F64)); /*Flawfinder: ignore*/ - data = LLDate(real); - if(istr.fail()) - { - LL_INFOS() << "STREAM FAILURE reading binary date." << LL_ENDL; - parse_count = PARSE_FAILURE; - } - break; - } - - case 'b': - { - // We probably have a valid raw binary stream. determine - // the size, and read it. - U32 size_nbo = 0; - read(istr, (char*)&size_nbo, sizeof(U32)); /*Flawfinder: ignore*/ - S32 size = (S32)ntohl(size_nbo); - if(mCheckLimits && (size > mMaxBytesLeft)) - { - parse_count = PARSE_FAILURE; - } - else - { - std::vector value; - if(size > 0) - { - value.resize(size); - account(fullread(istr, (char*)&value[0], size)); - } - data = value; - } - if(istr.fail()) - { - LL_INFOS() << "STREAM FAILURE reading binary." << LL_ENDL; - parse_count = PARSE_FAILURE; - } - break; - } - - default: - parse_count = PARSE_FAILURE; - LL_INFOS() << "Unrecognized character while parsing: int(" << int(c) - << ")" << LL_ENDL; - break; - } - if(PARSE_FAILURE == parse_count) - { - data.clear(); - } - return parse_count; + char c; + c = get(istr); + if(!istr.good()) + { + return 0; + } + if (max_depth == 0) + { + return PARSE_FAILURE; + } + S32 parse_count = 1; + switch(c) + { + case '{': + { + S32 child_count = parseMap(istr, data, max_depth - 1); + if((child_count == PARSE_FAILURE) || data.isUndefined()) + { + parse_count = PARSE_FAILURE; + } + else + { + parse_count += child_count; + } + if(istr.fail()) + { + LL_INFOS() << "STREAM FAILURE reading binary map." << LL_ENDL; + parse_count = PARSE_FAILURE; + } + break; + } + + case '[': + { + S32 child_count = parseArray(istr, data, max_depth - 1); + if((child_count == PARSE_FAILURE) || data.isUndefined()) + { + parse_count = PARSE_FAILURE; + } + else + { + parse_count += child_count; + } + if(istr.fail()) + { + LL_INFOS() << "STREAM FAILURE reading binary array." << LL_ENDL; + parse_count = PARSE_FAILURE; + } + break; + } + + case '!': + data.clear(); + break; + + case '0': + data = false; + break; + + case '1': + data = true; + break; + + case 'i': + { + U32 value_nbo = 0; + read(istr, (char*)&value_nbo, sizeof(U32)); /*Flawfinder: ignore*/ + data = (S32)ntohl(value_nbo); + if(istr.fail()) + { + LL_INFOS() << "STREAM FAILURE reading binary integer." << LL_ENDL; + } + break; + } + + case 'r': + { + F64 real_nbo = 0.0; + read(istr, (char*)&real_nbo, sizeof(F64)); /*Flawfinder: ignore*/ + data = ll_ntohd(real_nbo); + if(istr.fail()) + { + LL_INFOS() << "STREAM FAILURE reading binary real." << LL_ENDL; + } + break; + } + + case 'u': + { + LLUUID id; + read(istr, (char*)(&id.mData), UUID_BYTES); /*Flawfinder: ignore*/ + data = id; + if(istr.fail()) + { + LL_INFOS() << "STREAM FAILURE reading binary uuid." << LL_ENDL; + } + break; + } + + case '\'': + case '"': + { + std::string value; + auto cnt = deserialize_string_delim(istr, value, c); + if(PARSE_FAILURE == cnt) + { + parse_count = PARSE_FAILURE; + } + else + { + data = value; + account(cnt); + } + if(istr.fail()) + { + LL_INFOS() << "STREAM FAILURE reading binary (notation-style) string." + << LL_ENDL; + parse_count = PARSE_FAILURE; + } + break; + } + + case 's': + { + std::string value; + if(parseString(istr, value)) + { + data = value; + } + else + { + parse_count = PARSE_FAILURE; + } + if(istr.fail()) + { + LL_INFOS() << "STREAM FAILURE reading binary string." << LL_ENDL; + parse_count = PARSE_FAILURE; + } + break; + } + + case 'l': + { + std::string value; + if(parseString(istr, value)) + { + data = LLURI(value); + } + else + { + parse_count = PARSE_FAILURE; + } + if(istr.fail()) + { + LL_INFOS() << "STREAM FAILURE reading binary link." << LL_ENDL; + parse_count = PARSE_FAILURE; + } + break; + } + + case 'd': + { + F64 real = 0.0; + read(istr, (char*)&real, sizeof(F64)); /*Flawfinder: ignore*/ + data = LLDate(real); + if(istr.fail()) + { + LL_INFOS() << "STREAM FAILURE reading binary date." << LL_ENDL; + parse_count = PARSE_FAILURE; + } + break; + } + + case 'b': + { + // We probably have a valid raw binary stream. determine + // the size, and read it. + U32 size_nbo = 0; + read(istr, (char*)&size_nbo, sizeof(U32)); /*Flawfinder: ignore*/ + S32 size = (S32)ntohl(size_nbo); + if(mCheckLimits && (size > mMaxBytesLeft)) + { + parse_count = PARSE_FAILURE; + } + else + { + std::vector value; + if(size > 0) + { + value.resize(size); + account(fullread(istr, (char*)&value[0], size)); + } + data = value; + } + if(istr.fail()) + { + LL_INFOS() << "STREAM FAILURE reading binary." << LL_ENDL; + parse_count = PARSE_FAILURE; + } + break; + } + + default: + parse_count = PARSE_FAILURE; + LL_INFOS() << "Unrecognized character while parsing: int(" << int(c) + << ")" << LL_ENDL; + break; + } + if(PARSE_FAILURE == parse_count) + { + data.clear(); + } + return parse_count; } S32 LLSDBinaryParser::parseMap(std::istream& istr, LLSD& map, S32 max_depth) const { - map = LLSD::emptyMap(); - U32 value_nbo = 0; - read(istr, (char*)&value_nbo, sizeof(U32)); /*Flawfinder: ignore*/ - S32 size = (S32)ntohl(value_nbo); - S32 parse_count = 0; - S32 count = 0; - char c = get(istr); - while(c != '}' && (count < size) && istr.good()) - { - std::string name; - switch(c) - { - case 'k': - if(!parseString(istr, name)) - { - return PARSE_FAILURE; - } - break; - case '\'': - case '"': - { - auto cnt = deserialize_string_delim(istr, name, c); - if(PARSE_FAILURE == cnt) return PARSE_FAILURE; - account(cnt); - break; - } - } - LLSD child; - S32 child_count = doParse(istr, child, max_depth); - if(child_count > 0) - { - // There must be a value for every key, thus child_count - // must be greater than 0. - parse_count += child_count; - map.insert(name, child); - } - else - { - return PARSE_FAILURE; - } - ++count; - c = get(istr); - } - if((c != '}') || (count < size)) - { - // Make sure it is correctly terminated and we parsed as many - // as were said to be there. - return PARSE_FAILURE; - } - return parse_count; + map = LLSD::emptyMap(); + U32 value_nbo = 0; + read(istr, (char*)&value_nbo, sizeof(U32)); /*Flawfinder: ignore*/ + S32 size = (S32)ntohl(value_nbo); + S32 parse_count = 0; + S32 count = 0; + char c = get(istr); + while(c != '}' && (count < size) && istr.good()) + { + std::string name; + switch(c) + { + case 'k': + if(!parseString(istr, name)) + { + return PARSE_FAILURE; + } + break; + case '\'': + case '"': + { + auto cnt = deserialize_string_delim(istr, name, c); + if(PARSE_FAILURE == cnt) return PARSE_FAILURE; + account(cnt); + break; + } + } + LLSD child; + S32 child_count = doParse(istr, child, max_depth); + if(child_count > 0) + { + // There must be a value for every key, thus child_count + // must be greater than 0. + parse_count += child_count; + map.insert(name, child); + } + else + { + return PARSE_FAILURE; + } + ++count; + c = get(istr); + } + if((c != '}') || (count < size)) + { + // Make sure it is correctly terminated and we parsed as many + // as were said to be there. + return PARSE_FAILURE; + } + return parse_count; } S32 LLSDBinaryParser::parseArray(std::istream& istr, LLSD& array, S32 max_depth) const { - array = LLSD::emptyArray(); - U32 value_nbo = 0; - read(istr, (char*)&value_nbo, sizeof(U32)); /*Flawfinder: ignore*/ - S32 size = (S32)ntohl(value_nbo); - - // *FIX: This would be a good place to reserve some space in the - // array... - - S32 parse_count = 0; - S32 count = 0; - char c = istr.peek(); - while((c != ']') && (count < size) && istr.good()) - { - LLSD child; - S32 child_count = doParse(istr, child, max_depth); - if(PARSE_FAILURE == child_count) - { - return PARSE_FAILURE; - } - if(child_count) - { - parse_count += child_count; - array.append(child); - } - ++count; - c = istr.peek(); - } - c = get(istr); - if((c != ']') || (count < size)) - { - // Make sure it is correctly terminated and we parsed as many - // as were said to be there. - return PARSE_FAILURE; - } - return parse_count; + array = LLSD::emptyArray(); + U32 value_nbo = 0; + read(istr, (char*)&value_nbo, sizeof(U32)); /*Flawfinder: ignore*/ + S32 size = (S32)ntohl(value_nbo); + + // *FIX: This would be a good place to reserve some space in the + // array... + + S32 parse_count = 0; + S32 count = 0; + char c = istr.peek(); + while((c != ']') && (count < size) && istr.good()) + { + LLSD child; + S32 child_count = doParse(istr, child, max_depth); + if(PARSE_FAILURE == child_count) + { + return PARSE_FAILURE; + } + if(child_count) + { + parse_count += child_count; + array.append(child); + } + ++count; + c = istr.peek(); + } + c = get(istr); + if((c != ']') || (count < size)) + { + // Make sure it is correctly terminated and we parsed as many + // as were said to be there. + return PARSE_FAILURE; + } + return parse_count; } bool LLSDBinaryParser::parseString( - std::istream& istr, - std::string& value) const + std::istream& istr, + std::string& value) const { - // *FIX: This is memory inefficient. - U32 value_nbo = 0; - read(istr, (char*)&value_nbo, sizeof(U32)); /*Flawfinder: ignore*/ - S32 size = (S32)ntohl(value_nbo); - if(mCheckLimits && (size > mMaxBytesLeft)) return false; - if(size < 0) return false; - std::vector buf; - if(size) - { - buf.resize(size); - account(fullread(istr, &buf[0], size)); - value.assign(buf.begin(), buf.end()); - } - return true; + // *FIX: This is memory inefficient. + U32 value_nbo = 0; + read(istr, (char*)&value_nbo, sizeof(U32)); /*Flawfinder: ignore*/ + S32 size = (S32)ntohl(value_nbo); + if(mCheckLimits && (size > mMaxBytesLeft)) return false; + if(size < 0) return false; + std::vector buf; + if(size) + { + buf.resize(size); + account(fullread(istr, &buf[0], size)); + value.assign(buf.begin(), buf.end()); + } + return true; } @@ -1312,12 +1312,12 @@ LLSDFormatter::~LLSDFormatter() void LLSDFormatter::boolalpha(bool alpha) { - mBoolAlpha = alpha; + mBoolAlpha = alpha; } void LLSDFormatter::realFormat(const std::string& format) { - mRealFormat = format; + mRealFormat = format; } S32 LLSDFormatter::format(const LLSD& data, std::ostream& ostr) const @@ -1333,8 +1333,8 @@ S32 LLSDFormatter::format(const LLSD& data, std::ostream& ostr, EFormatterOption void LLSDFormatter::formatReal(LLSD::Real real, std::ostream& ostr) const { - std::string buffer = llformat(mRealFormat.c_str(), real); - ostr << buffer; + std::string buffer = llformat(mRealFormat.c_str(), real); + ostr << buffer; } /** @@ -1353,174 +1353,174 @@ LLSDNotationFormatter::~LLSDNotationFormatter() // static std::string LLSDNotationFormatter::escapeString(const std::string& in) { - std::ostringstream ostr; - serialize_string(in, ostr); - return ostr.str(); + std::ostringstream ostr; + serialize_string(in, ostr); + return ostr.str(); } S32 LLSDNotationFormatter::format_impl(const LLSD& data, std::ostream& ostr, - EFormatterOptions options, U32 level) const + EFormatterOptions options, U32 level) const { - S32 format_count = 1; - std::string pre; - std::string post; - - if (options & LLSDFormatter::OPTIONS_PRETTY) - { - for (U32 i = 0; i < level; i++) - { - pre += " "; - } - post = "\n"; - } - - switch(data.type()) - { - case LLSD::TypeMap: - { - if (0 != level) ostr << post << pre; - ostr << "{"; - std::string inner_pre; - if (options & LLSDFormatter::OPTIONS_PRETTY) - { - inner_pre = pre + " "; - } - - bool need_comma = false; - LLSD::map_const_iterator iter = data.beginMap(); - LLSD::map_const_iterator end = data.endMap(); - for(; iter != end; ++iter) - { - if(need_comma) ostr << ","; - need_comma = true; - ostr << post << inner_pre << '\''; - serialize_string((*iter).first, ostr); - ostr << "':"; - format_count += format_impl((*iter).second, ostr, options, level + 2); - } - ostr << post << pre << "}"; - break; - } - - case LLSD::TypeArray: - { - ostr << post << pre << "["; - bool need_comma = false; - LLSD::array_const_iterator iter = data.beginArray(); - LLSD::array_const_iterator end = data.endArray(); - for(; iter != end; ++iter) - { - if(need_comma) ostr << ","; - need_comma = true; - format_count += format_impl(*iter, ostr, options, level + 1); - } - ostr << "]"; - break; - } - - case LLSD::TypeUndefined: - ostr << "!"; - break; - - case LLSD::TypeBoolean: - if(mBoolAlpha || + S32 format_count = 1; + std::string pre; + std::string post; + + if (options & LLSDFormatter::OPTIONS_PRETTY) + { + for (U32 i = 0; i < level; i++) + { + pre += " "; + } + post = "\n"; + } + + switch(data.type()) + { + case LLSD::TypeMap: + { + if (0 != level) ostr << post << pre; + ostr << "{"; + std::string inner_pre; + if (options & LLSDFormatter::OPTIONS_PRETTY) + { + inner_pre = pre + " "; + } + + bool need_comma = false; + LLSD::map_const_iterator iter = data.beginMap(); + LLSD::map_const_iterator end = data.endMap(); + for(; iter != end; ++iter) + { + if(need_comma) ostr << ","; + need_comma = true; + ostr << post << inner_pre << '\''; + serialize_string((*iter).first, ostr); + ostr << "':"; + format_count += format_impl((*iter).second, ostr, options, level + 2); + } + ostr << post << pre << "}"; + break; + } + + case LLSD::TypeArray: + { + ostr << post << pre << "["; + bool need_comma = false; + LLSD::array_const_iterator iter = data.beginArray(); + LLSD::array_const_iterator end = data.endArray(); + for(; iter != end; ++iter) + { + if(need_comma) ostr << ","; + need_comma = true; + format_count += format_impl(*iter, ostr, options, level + 1); + } + ostr << "]"; + break; + } + + case LLSD::TypeUndefined: + ostr << "!"; + break; + + case LLSD::TypeBoolean: + if(mBoolAlpha || #if( LL_WINDOWS || __GNUC__ > 2) - (ostr.flags() & std::ios::boolalpha) + (ostr.flags() & std::ios::boolalpha) #else - (ostr.flags() & 0x0100) + (ostr.flags() & 0x0100) #endif - ) - { - ostr << (data.asBoolean() - ? NOTATION_TRUE_SERIAL : NOTATION_FALSE_SERIAL); - } - else - { - ostr << (data.asBoolean() ? 1 : 0); - } - break; - - case LLSD::TypeInteger: - ostr << "i" << data.asInteger(); - break; - - case LLSD::TypeReal: - ostr << "r"; - if(mRealFormat.empty()) - { - ostr << data.asReal(); - } - else - { - formatReal(data.asReal(), ostr); - } - break; - - case LLSD::TypeUUID: - ostr << "u" << data.asUUID(); - break; - - case LLSD::TypeString: - ostr << '\''; - serialize_string(data.asStringRef(), ostr); - ostr << '\''; - break; - - case LLSD::TypeDate: - ostr << "d\"" << data.asDate() << "\""; - break; - - case LLSD::TypeURI: - ostr << "l\""; - serialize_string(data.asString(), ostr); - ostr << "\""; - break; - - case LLSD::TypeBinary: - { - // *FIX: memory inefficient. - const std::vector& buffer = data.asBinary(); - if (options & LLSDFormatter::OPTIONS_PRETTY_BINARY) - { - ostr << "b16\""; - if (! buffer.empty()) - { - std::ios_base::fmtflags old_flags = ostr.flags(); - ostr.setf( std::ios::hex, std::ios::basefield ); - // It shouldn't strictly matter whether the emitted hex digits - // are uppercase; LLSDNotationParser handles either; but as of - // 2020-05-13, Python's llbase.llsd requires uppercase hex. - ostr << std::uppercase; - auto oldfill(ostr.fill('0')); - auto oldwidth(ostr.width()); - for (size_t i = 0; i < buffer.size(); i++) - { - // have to restate setw() before every conversion - ostr << std::setw(2) << (int) buffer[i]; - } - ostr.width(oldwidth); - ostr.fill(oldfill); - ostr.flags(old_flags); - } - } - else // ! OPTIONS_PRETTY_BINARY - { - ostr << "b(" << buffer.size() << ")\""; - if (! buffer.empty()) - { - ostr.write((const char*)&buffer[0], buffer.size()); - } - } - ostr << "\""; - break; - } - - default: - // *NOTE: This should never happen. - ostr << "!"; - break; - } - return format_count; + ) + { + ostr << (data.asBoolean() + ? NOTATION_TRUE_SERIAL : NOTATION_FALSE_SERIAL); + } + else + { + ostr << (data.asBoolean() ? 1 : 0); + } + break; + + case LLSD::TypeInteger: + ostr << "i" << data.asInteger(); + break; + + case LLSD::TypeReal: + ostr << "r"; + if(mRealFormat.empty()) + { + ostr << data.asReal(); + } + else + { + formatReal(data.asReal(), ostr); + } + break; + + case LLSD::TypeUUID: + ostr << "u" << data.asUUID(); + break; + + case LLSD::TypeString: + ostr << '\''; + serialize_string(data.asStringRef(), ostr); + ostr << '\''; + break; + + case LLSD::TypeDate: + ostr << "d\"" << data.asDate() << "\""; + break; + + case LLSD::TypeURI: + ostr << "l\""; + serialize_string(data.asString(), ostr); + ostr << "\""; + break; + + case LLSD::TypeBinary: + { + // *FIX: memory inefficient. + const std::vector& buffer = data.asBinary(); + if (options & LLSDFormatter::OPTIONS_PRETTY_BINARY) + { + ostr << "b16\""; + if (! buffer.empty()) + { + std::ios_base::fmtflags old_flags = ostr.flags(); + ostr.setf( std::ios::hex, std::ios::basefield ); + // It shouldn't strictly matter whether the emitted hex digits + // are uppercase; LLSDNotationParser handles either; but as of + // 2020-05-13, Python's llbase.llsd requires uppercase hex. + ostr << std::uppercase; + auto oldfill(ostr.fill('0')); + auto oldwidth(ostr.width()); + for (size_t i = 0; i < buffer.size(); i++) + { + // have to restate setw() before every conversion + ostr << std::setw(2) << (int) buffer[i]; + } + ostr.width(oldwidth); + ostr.fill(oldfill); + ostr.flags(old_flags); + } + } + else // ! OPTIONS_PRETTY_BINARY + { + ostr << "b(" << buffer.size() << ")\""; + if (! buffer.empty()) + { + ostr.write((const char*)&buffer[0], buffer.size()); + } + } + ostr << "\""; + break; + } + + default: + // *NOTE: This should never happen. + ostr << "!"; + break; + } + return format_count; } /** @@ -1538,119 +1538,119 @@ LLSDBinaryFormatter::~LLSDBinaryFormatter() // virtual S32 LLSDBinaryFormatter::format_impl(const LLSD& data, std::ostream& ostr, - EFormatterOptions options, U32 level) const + EFormatterOptions options, U32 level) const { - S32 format_count = 1; - switch(data.type()) - { - case LLSD::TypeMap: - { - ostr.put('{'); - U32 size_nbo = htonl(data.size()); - ostr.write((const char*)(&size_nbo), sizeof(U32)); - LLSD::map_const_iterator iter = data.beginMap(); - LLSD::map_const_iterator end = data.endMap(); - for(; iter != end; ++iter) - { - ostr.put('k'); - formatString((*iter).first, ostr); - format_count += format_impl((*iter).second, ostr, options, level+1); - } - ostr.put('}'); - break; - } - - case LLSD::TypeArray: - { - ostr.put('['); - U32 size_nbo = htonl(data.size()); - ostr.write((const char*)(&size_nbo), sizeof(U32)); - LLSD::array_const_iterator iter = data.beginArray(); - LLSD::array_const_iterator end = data.endArray(); - for(; iter != end; ++iter) - { - format_count += format_impl(*iter, ostr, options, level+1); - } - ostr.put(']'); - break; - } - - case LLSD::TypeUndefined: - ostr.put('!'); - break; - - case LLSD::TypeBoolean: - if(data.asBoolean()) ostr.put(BINARY_TRUE_SERIAL); - else ostr.put(BINARY_FALSE_SERIAL); - break; - - case LLSD::TypeInteger: - { - ostr.put('i'); - U32 value_nbo = htonl(data.asInteger()); - ostr.write((const char*)(&value_nbo), sizeof(U32)); - break; - } - - case LLSD::TypeReal: - { - ostr.put('r'); - F64 value_nbo = ll_htond(data.asReal()); - ostr.write((const char*)(&value_nbo), sizeof(F64)); - break; - } - - case LLSD::TypeUUID: - { - ostr.put('u'); - LLUUID temp = data.asUUID(); - ostr.write((const char*)(&(temp.mData)), UUID_BYTES); - break; - } - - case LLSD::TypeString: - ostr.put('s'); - formatString(data.asStringRef(), ostr); - break; - - case LLSD::TypeDate: - { - ostr.put('d'); - F64 value = data.asReal(); - ostr.write((const char*)(&value), sizeof(F64)); - break; - } - - case LLSD::TypeURI: - ostr.put('l'); - formatString(data.asString(), ostr); - break; - - case LLSD::TypeBinary: - { - ostr.put('b'); - const std::vector& buffer = data.asBinary(); - U32 size_nbo = htonl(buffer.size()); - ostr.write((const char*)(&size_nbo), sizeof(U32)); - if(buffer.size()) ostr.write((const char*)&buffer[0], buffer.size()); - break; - } - - default: - // *NOTE: This should never happen. - ostr.put('!'); - break; - } - return format_count; + S32 format_count = 1; + switch(data.type()) + { + case LLSD::TypeMap: + { + ostr.put('{'); + U32 size_nbo = htonl(data.size()); + ostr.write((const char*)(&size_nbo), sizeof(U32)); + LLSD::map_const_iterator iter = data.beginMap(); + LLSD::map_const_iterator end = data.endMap(); + for(; iter != end; ++iter) + { + ostr.put('k'); + formatString((*iter).first, ostr); + format_count += format_impl((*iter).second, ostr, options, level+1); + } + ostr.put('}'); + break; + } + + case LLSD::TypeArray: + { + ostr.put('['); + U32 size_nbo = htonl(data.size()); + ostr.write((const char*)(&size_nbo), sizeof(U32)); + LLSD::array_const_iterator iter = data.beginArray(); + LLSD::array_const_iterator end = data.endArray(); + for(; iter != end; ++iter) + { + format_count += format_impl(*iter, ostr, options, level+1); + } + ostr.put(']'); + break; + } + + case LLSD::TypeUndefined: + ostr.put('!'); + break; + + case LLSD::TypeBoolean: + if(data.asBoolean()) ostr.put(BINARY_TRUE_SERIAL); + else ostr.put(BINARY_FALSE_SERIAL); + break; + + case LLSD::TypeInteger: + { + ostr.put('i'); + U32 value_nbo = htonl(data.asInteger()); + ostr.write((const char*)(&value_nbo), sizeof(U32)); + break; + } + + case LLSD::TypeReal: + { + ostr.put('r'); + F64 value_nbo = ll_htond(data.asReal()); + ostr.write((const char*)(&value_nbo), sizeof(F64)); + break; + } + + case LLSD::TypeUUID: + { + ostr.put('u'); + LLUUID temp = data.asUUID(); + ostr.write((const char*)(&(temp.mData)), UUID_BYTES); + break; + } + + case LLSD::TypeString: + ostr.put('s'); + formatString(data.asStringRef(), ostr); + break; + + case LLSD::TypeDate: + { + ostr.put('d'); + F64 value = data.asReal(); + ostr.write((const char*)(&value), sizeof(F64)); + break; + } + + case LLSD::TypeURI: + ostr.put('l'); + formatString(data.asString(), ostr); + break; + + case LLSD::TypeBinary: + { + ostr.put('b'); + const std::vector& buffer = data.asBinary(); + U32 size_nbo = htonl(buffer.size()); + ostr.write((const char*)(&size_nbo), sizeof(U32)); + if(buffer.size()) ostr.write((const char*)&buffer[0], buffer.size()); + break; + } + + default: + // *NOTE: This should never happen. + ostr.put('!'); + break; + } + return format_count; } void LLSDBinaryFormatter::formatString( - const std::string& string, - std::ostream& ostr) const + const std::string& string, + std::ostream& ostr) const { - U32 size_nbo = htonl(string.size()); - ostr.write((const char*)(&size_nbo), sizeof(U32)); - ostr.write(string.c_str(), string.size()); + U32 size_nbo = htonl(string.size()); + ostr.write((const char*)(&size_nbo), sizeof(U32)); + ostr.write(string.c_str(), string.size()); } /** @@ -1658,491 +1658,491 @@ void LLSDBinaryFormatter::formatString( */ llssize deserialize_string(std::istream& istr, std::string& value, llssize max_bytes) { - int c = istr.get(); - if(istr.fail()) - { - // No data in stream, bail out but mention the character we - // grabbed. - return LLSDParser::PARSE_FAILURE; - } - - llssize rv = LLSDParser::PARSE_FAILURE; - switch(c) - { - case '\'': - case '"': - rv = deserialize_string_delim(istr, value, c); - break; - case 's': - // technically, less than max_bytes, but this is just meant to - // catch egregious protocol errors. parse errors will be - // caught in the case of incorrect counts. - rv = deserialize_string_raw(istr, value, max_bytes); - break; - default: - break; - } - if(LLSDParser::PARSE_FAILURE == rv) return rv; - return rv + 1; // account for the character grabbed at the top. + int c = istr.get(); + if(istr.fail()) + { + // No data in stream, bail out but mention the character we + // grabbed. + return LLSDParser::PARSE_FAILURE; + } + + llssize rv = LLSDParser::PARSE_FAILURE; + switch(c) + { + case '\'': + case '"': + rv = deserialize_string_delim(istr, value, c); + break; + case 's': + // technically, less than max_bytes, but this is just meant to + // catch egregious protocol errors. parse errors will be + // caught in the case of incorrect counts. + rv = deserialize_string_raw(istr, value, max_bytes); + break; + default: + break; + } + if(LLSDParser::PARSE_FAILURE == rv) return rv; + return rv + 1; // account for the character grabbed at the top. } llssize deserialize_string_delim( - std::istream& istr, - std::string& value, - char delim) + std::istream& istr, + std::string& value, + char delim) { - std::ostringstream write_buffer; - bool found_escape = false; - bool found_hex = false; - bool found_digit = false; - U8 byte = 0; - llssize count = 0; - - while (true) - { - int next_byte = istr.get(); - ++count; - - if(istr.fail()) - { - // If our stream is empty, break out - value = write_buffer.str(); - return LLSDParser::PARSE_FAILURE; - } - - char next_char = (char)next_byte; // Now that we know it's not EOF - - if(found_escape) - { - // next character(s) is a special sequence. - if(found_hex) - { - if(found_digit) - { - found_digit = false; - found_hex = false; - found_escape = false; - byte = byte << 4; - byte |= hex_as_nybble(next_char); - write_buffer << byte; - byte = 0; - } - else - { - // next character is the first nybble of - // - found_digit = true; - byte = hex_as_nybble(next_char); - } - } - else if(next_char == 'x') - { - found_hex = true; - } - else - { - switch(next_char) - { - case 'a': - write_buffer << '\a'; - break; - case 'b': - write_buffer << '\b'; - break; - case 'f': - write_buffer << '\f'; - break; - case 'n': - write_buffer << '\n'; - break; - case 'r': - write_buffer << '\r'; - break; - case 't': - write_buffer << '\t'; - break; - case 'v': - write_buffer << '\v'; - break; - default: - write_buffer << next_char; - break; - } - found_escape = false; - } - } - else if(next_char == '\\') - { - found_escape = true; - } - else if(next_char == delim) - { - break; - } - else - { - write_buffer << next_char; - } - } - - value = write_buffer.str(); - return count; + std::ostringstream write_buffer; + bool found_escape = false; + bool found_hex = false; + bool found_digit = false; + U8 byte = 0; + llssize count = 0; + + while (true) + { + int next_byte = istr.get(); + ++count; + + if(istr.fail()) + { + // If our stream is empty, break out + value = write_buffer.str(); + return LLSDParser::PARSE_FAILURE; + } + + char next_char = (char)next_byte; // Now that we know it's not EOF + + if(found_escape) + { + // next character(s) is a special sequence. + if(found_hex) + { + if(found_digit) + { + found_digit = false; + found_hex = false; + found_escape = false; + byte = byte << 4; + byte |= hex_as_nybble(next_char); + write_buffer << byte; + byte = 0; + } + else + { + // next character is the first nybble of + // + found_digit = true; + byte = hex_as_nybble(next_char); + } + } + else if(next_char == 'x') + { + found_hex = true; + } + else + { + switch(next_char) + { + case 'a': + write_buffer << '\a'; + break; + case 'b': + write_buffer << '\b'; + break; + case 'f': + write_buffer << '\f'; + break; + case 'n': + write_buffer << '\n'; + break; + case 'r': + write_buffer << '\r'; + break; + case 't': + write_buffer << '\t'; + break; + case 'v': + write_buffer << '\v'; + break; + default: + write_buffer << next_char; + break; + } + found_escape = false; + } + } + else if(next_char == '\\') + { + found_escape = true; + } + else if(next_char == delim) + { + break; + } + else + { + write_buffer << next_char; + } + } + + value = write_buffer.str(); + return count; } llssize deserialize_string_raw( - std::istream& istr, - std::string& value, - llssize max_bytes) + std::istream& istr, + std::string& value, + llssize max_bytes) { - llssize count = 0; - const S32 BUF_LEN = 20; - char buf[BUF_LEN]; /* Flawfinder: ignore */ - istr.get(buf, BUF_LEN - 1, ')'); - count += istr.gcount(); - int c = istr.get(); - c = istr.get(); - count += 2; - if(((c == '"') || (c == '\'')) && (buf[0] == '(')) - { - // We probably have a valid raw string. determine - // the size, and read it. - // *FIX: This is memory inefficient. - auto len = strtol(buf + 1, NULL, 0); - if((max_bytes>0)&&(len>max_bytes)) return LLSDParser::PARSE_FAILURE; - std::vector buf; - if(len) - { - buf.resize(len); - count += fullread(istr, (char *)&buf[0], len); - value.assign(buf.begin(), buf.end()); - } - c = istr.get(); - ++count; - if(!((c == '"') || (c == '\''))) - { - return LLSDParser::PARSE_FAILURE; - } - } - else - { - return LLSDParser::PARSE_FAILURE; - } - return count; + llssize count = 0; + const S32 BUF_LEN = 20; + char buf[BUF_LEN]; /* Flawfinder: ignore */ + istr.get(buf, BUF_LEN - 1, ')'); + count += istr.gcount(); + int c = istr.get(); + c = istr.get(); + count += 2; + if(((c == '"') || (c == '\'')) && (buf[0] == '(')) + { + // We probably have a valid raw string. determine + // the size, and read it. + // *FIX: This is memory inefficient. + auto len = strtol(buf + 1, NULL, 0); + if((max_bytes>0)&&(len>max_bytes)) return LLSDParser::PARSE_FAILURE; + std::vector buf; + if(len) + { + buf.resize(len); + count += fullread(istr, (char *)&buf[0], len); + value.assign(buf.begin(), buf.end()); + } + c = istr.get(); + ++count; + if(!((c == '"') || (c == '\''))) + { + return LLSDParser::PARSE_FAILURE; + } + } + else + { + return LLSDParser::PARSE_FAILURE; + } + return count; } static const char* NOTATION_STRING_CHARACTERS[256] = { - "\\x00", // 0 - "\\x01", // 1 - "\\x02", // 2 - "\\x03", // 3 - "\\x04", // 4 - "\\x05", // 5 - "\\x06", // 6 - "\\a", // 7 - "\\b", // 8 - "\\t", // 9 - "\\n", // 10 - "\\v", // 11 - "\\f", // 12 - "\\r", // 13 - "\\x0e", // 14 - "\\x0f", // 15 - "\\x10", // 16 - "\\x11", // 17 - "\\x12", // 18 - "\\x13", // 19 - "\\x14", // 20 - "\\x15", // 21 - "\\x16", // 22 - "\\x17", // 23 - "\\x18", // 24 - "\\x19", // 25 - "\\x1a", // 26 - "\\x1b", // 27 - "\\x1c", // 28 - "\\x1d", // 29 - "\\x1e", // 30 - "\\x1f", // 31 - " ", // 32 - "!", // 33 - "\"", // 34 - "#", // 35 - "$", // 36 - "%", // 37 - "&", // 38 - "\\'", // 39 - "(", // 40 - ")", // 41 - "*", // 42 - "+", // 43 - ",", // 44 - "-", // 45 - ".", // 46 - "/", // 47 - "0", // 48 - "1", // 49 - "2", // 50 - "3", // 51 - "4", // 52 - "5", // 53 - "6", // 54 - "7", // 55 - "8", // 56 - "9", // 57 - ":", // 58 - ";", // 59 - "<", // 60 - "=", // 61 - ">", // 62 - "?", // 63 - "@", // 64 - "A", // 65 - "B", // 66 - "C", // 67 - "D", // 68 - "E", // 69 - "F", // 70 - "G", // 71 - "H", // 72 - "I", // 73 - "J", // 74 - "K", // 75 - "L", // 76 - "M", // 77 - "N", // 78 - "O", // 79 - "P", // 80 - "Q", // 81 - "R", // 82 - "S", // 83 - "T", // 84 - "U", // 85 - "V", // 86 - "W", // 87 - "X", // 88 - "Y", // 89 - "Z", // 90 - "[", // 91 - "\\\\", // 92 - "]", // 93 - "^", // 94 - "_", // 95 - "`", // 96 - "a", // 97 - "b", // 98 - "c", // 99 - "d", // 100 - "e", // 101 - "f", // 102 - "g", // 103 - "h", // 104 - "i", // 105 - "j", // 106 - "k", // 107 - "l", // 108 - "m", // 109 - "n", // 110 - "o", // 111 - "p", // 112 - "q", // 113 - "r", // 114 - "s", // 115 - "t", // 116 - "u", // 117 - "v", // 118 - "w", // 119 - "x", // 120 - "y", // 121 - "z", // 122 - "{", // 123 - "|", // 124 - "}", // 125 - "~", // 126 - "\\x7f", // 127 - "\\x80", // 128 - "\\x81", // 129 - "\\x82", // 130 - "\\x83", // 131 - "\\x84", // 132 - "\\x85", // 133 - "\\x86", // 134 - "\\x87", // 135 - "\\x88", // 136 - "\\x89", // 137 - "\\x8a", // 138 - "\\x8b", // 139 - "\\x8c", // 140 - "\\x8d", // 141 - "\\x8e", // 142 - "\\x8f", // 143 - "\\x90", // 144 - "\\x91", // 145 - "\\x92", // 146 - "\\x93", // 147 - "\\x94", // 148 - "\\x95", // 149 - "\\x96", // 150 - "\\x97", // 151 - "\\x98", // 152 - "\\x99", // 153 - "\\x9a", // 154 - "\\x9b", // 155 - "\\x9c", // 156 - "\\x9d", // 157 - "\\x9e", // 158 - "\\x9f", // 159 - "\\xa0", // 160 - "\\xa1", // 161 - "\\xa2", // 162 - "\\xa3", // 163 - "\\xa4", // 164 - "\\xa5", // 165 - "\\xa6", // 166 - "\\xa7", // 167 - "\\xa8", // 168 - "\\xa9", // 169 - "\\xaa", // 170 - "\\xab", // 171 - "\\xac", // 172 - "\\xad", // 173 - "\\xae", // 174 - "\\xaf", // 175 - "\\xb0", // 176 - "\\xb1", // 177 - "\\xb2", // 178 - "\\xb3", // 179 - "\\xb4", // 180 - "\\xb5", // 181 - "\\xb6", // 182 - "\\xb7", // 183 - "\\xb8", // 184 - "\\xb9", // 185 - "\\xba", // 186 - "\\xbb", // 187 - "\\xbc", // 188 - "\\xbd", // 189 - "\\xbe", // 190 - "\\xbf", // 191 - "\\xc0", // 192 - "\\xc1", // 193 - "\\xc2", // 194 - "\\xc3", // 195 - "\\xc4", // 196 - "\\xc5", // 197 - "\\xc6", // 198 - "\\xc7", // 199 - "\\xc8", // 200 - "\\xc9", // 201 - "\\xca", // 202 - "\\xcb", // 203 - "\\xcc", // 204 - "\\xcd", // 205 - "\\xce", // 206 - "\\xcf", // 207 - "\\xd0", // 208 - "\\xd1", // 209 - "\\xd2", // 210 - "\\xd3", // 211 - "\\xd4", // 212 - "\\xd5", // 213 - "\\xd6", // 214 - "\\xd7", // 215 - "\\xd8", // 216 - "\\xd9", // 217 - "\\xda", // 218 - "\\xdb", // 219 - "\\xdc", // 220 - "\\xdd", // 221 - "\\xde", // 222 - "\\xdf", // 223 - "\\xe0", // 224 - "\\xe1", // 225 - "\\xe2", // 226 - "\\xe3", // 227 - "\\xe4", // 228 - "\\xe5", // 229 - "\\xe6", // 230 - "\\xe7", // 231 - "\\xe8", // 232 - "\\xe9", // 233 - "\\xea", // 234 - "\\xeb", // 235 - "\\xec", // 236 - "\\xed", // 237 - "\\xee", // 238 - "\\xef", // 239 - "\\xf0", // 240 - "\\xf1", // 241 - "\\xf2", // 242 - "\\xf3", // 243 - "\\xf4", // 244 - "\\xf5", // 245 - "\\xf6", // 246 - "\\xf7", // 247 - "\\xf8", // 248 - "\\xf9", // 249 - "\\xfa", // 250 - "\\xfb", // 251 - "\\xfc", // 252 - "\\xfd", // 253 - "\\xfe", // 254 - "\\xff" // 255 + "\\x00", // 0 + "\\x01", // 1 + "\\x02", // 2 + "\\x03", // 3 + "\\x04", // 4 + "\\x05", // 5 + "\\x06", // 6 + "\\a", // 7 + "\\b", // 8 + "\\t", // 9 + "\\n", // 10 + "\\v", // 11 + "\\f", // 12 + "\\r", // 13 + "\\x0e", // 14 + "\\x0f", // 15 + "\\x10", // 16 + "\\x11", // 17 + "\\x12", // 18 + "\\x13", // 19 + "\\x14", // 20 + "\\x15", // 21 + "\\x16", // 22 + "\\x17", // 23 + "\\x18", // 24 + "\\x19", // 25 + "\\x1a", // 26 + "\\x1b", // 27 + "\\x1c", // 28 + "\\x1d", // 29 + "\\x1e", // 30 + "\\x1f", // 31 + " ", // 32 + "!", // 33 + "\"", // 34 + "#", // 35 + "$", // 36 + "%", // 37 + "&", // 38 + "\\'", // 39 + "(", // 40 + ")", // 41 + "*", // 42 + "+", // 43 + ",", // 44 + "-", // 45 + ".", // 46 + "/", // 47 + "0", // 48 + "1", // 49 + "2", // 50 + "3", // 51 + "4", // 52 + "5", // 53 + "6", // 54 + "7", // 55 + "8", // 56 + "9", // 57 + ":", // 58 + ";", // 59 + "<", // 60 + "=", // 61 + ">", // 62 + "?", // 63 + "@", // 64 + "A", // 65 + "B", // 66 + "C", // 67 + "D", // 68 + "E", // 69 + "F", // 70 + "G", // 71 + "H", // 72 + "I", // 73 + "J", // 74 + "K", // 75 + "L", // 76 + "M", // 77 + "N", // 78 + "O", // 79 + "P", // 80 + "Q", // 81 + "R", // 82 + "S", // 83 + "T", // 84 + "U", // 85 + "V", // 86 + "W", // 87 + "X", // 88 + "Y", // 89 + "Z", // 90 + "[", // 91 + "\\\\", // 92 + "]", // 93 + "^", // 94 + "_", // 95 + "`", // 96 + "a", // 97 + "b", // 98 + "c", // 99 + "d", // 100 + "e", // 101 + "f", // 102 + "g", // 103 + "h", // 104 + "i", // 105 + "j", // 106 + "k", // 107 + "l", // 108 + "m", // 109 + "n", // 110 + "o", // 111 + "p", // 112 + "q", // 113 + "r", // 114 + "s", // 115 + "t", // 116 + "u", // 117 + "v", // 118 + "w", // 119 + "x", // 120 + "y", // 121 + "z", // 122 + "{", // 123 + "|", // 124 + "}", // 125 + "~", // 126 + "\\x7f", // 127 + "\\x80", // 128 + "\\x81", // 129 + "\\x82", // 130 + "\\x83", // 131 + "\\x84", // 132 + "\\x85", // 133 + "\\x86", // 134 + "\\x87", // 135 + "\\x88", // 136 + "\\x89", // 137 + "\\x8a", // 138 + "\\x8b", // 139 + "\\x8c", // 140 + "\\x8d", // 141 + "\\x8e", // 142 + "\\x8f", // 143 + "\\x90", // 144 + "\\x91", // 145 + "\\x92", // 146 + "\\x93", // 147 + "\\x94", // 148 + "\\x95", // 149 + "\\x96", // 150 + "\\x97", // 151 + "\\x98", // 152 + "\\x99", // 153 + "\\x9a", // 154 + "\\x9b", // 155 + "\\x9c", // 156 + "\\x9d", // 157 + "\\x9e", // 158 + "\\x9f", // 159 + "\\xa0", // 160 + "\\xa1", // 161 + "\\xa2", // 162 + "\\xa3", // 163 + "\\xa4", // 164 + "\\xa5", // 165 + "\\xa6", // 166 + "\\xa7", // 167 + "\\xa8", // 168 + "\\xa9", // 169 + "\\xaa", // 170 + "\\xab", // 171 + "\\xac", // 172 + "\\xad", // 173 + "\\xae", // 174 + "\\xaf", // 175 + "\\xb0", // 176 + "\\xb1", // 177 + "\\xb2", // 178 + "\\xb3", // 179 + "\\xb4", // 180 + "\\xb5", // 181 + "\\xb6", // 182 + "\\xb7", // 183 + "\\xb8", // 184 + "\\xb9", // 185 + "\\xba", // 186 + "\\xbb", // 187 + "\\xbc", // 188 + "\\xbd", // 189 + "\\xbe", // 190 + "\\xbf", // 191 + "\\xc0", // 192 + "\\xc1", // 193 + "\\xc2", // 194 + "\\xc3", // 195 + "\\xc4", // 196 + "\\xc5", // 197 + "\\xc6", // 198 + "\\xc7", // 199 + "\\xc8", // 200 + "\\xc9", // 201 + "\\xca", // 202 + "\\xcb", // 203 + "\\xcc", // 204 + "\\xcd", // 205 + "\\xce", // 206 + "\\xcf", // 207 + "\\xd0", // 208 + "\\xd1", // 209 + "\\xd2", // 210 + "\\xd3", // 211 + "\\xd4", // 212 + "\\xd5", // 213 + "\\xd6", // 214 + "\\xd7", // 215 + "\\xd8", // 216 + "\\xd9", // 217 + "\\xda", // 218 + "\\xdb", // 219 + "\\xdc", // 220 + "\\xdd", // 221 + "\\xde", // 222 + "\\xdf", // 223 + "\\xe0", // 224 + "\\xe1", // 225 + "\\xe2", // 226 + "\\xe3", // 227 + "\\xe4", // 228 + "\\xe5", // 229 + "\\xe6", // 230 + "\\xe7", // 231 + "\\xe8", // 232 + "\\xe9", // 233 + "\\xea", // 234 + "\\xeb", // 235 + "\\xec", // 236 + "\\xed", // 237 + "\\xee", // 238 + "\\xef", // 239 + "\\xf0", // 240 + "\\xf1", // 241 + "\\xf2", // 242 + "\\xf3", // 243 + "\\xf4", // 244 + "\\xf5", // 245 + "\\xf6", // 246 + "\\xf7", // 247 + "\\xf8", // 248 + "\\xf9", // 249 + "\\xfa", // 250 + "\\xfb", // 251 + "\\xfc", // 252 + "\\xfd", // 253 + "\\xfe", // 254 + "\\xff" // 255 }; void serialize_string(const std::string& value, std::ostream& str) { - std::string::const_iterator it = value.begin(); - std::string::const_iterator end = value.end(); - U8 c; - for(; it != end; ++it) - { - c = (U8)(*it); - str << NOTATION_STRING_CHARACTERS[c]; - } + std::string::const_iterator it = value.begin(); + std::string::const_iterator end = value.end(); + U8 c; + for(; it != end; ++it) + { + c = (U8)(*it); + str << NOTATION_STRING_CHARACTERS[c]; + } } llssize deserialize_boolean( - std::istream& istr, - LLSD& data, - const std::string& compare, - bool value) + std::istream& istr, + LLSD& data, + const std::string& compare, + bool value) { - // - // this method is a little goofy, because it gets the stream at - // the point where the t or f has already been - // consumed. Basically, parse for a patch to the string passed in - // starting at index 1. If it's a match: - // * assign data to value - // * return the number of bytes read - // otherwise: - // * set data to LLSD::null - // * return LLSDParser::PARSE_FAILURE (-1) - // - llssize bytes_read = 0; - std::string::size_type ii = 0; - char c = istr.peek(); - while((++ii < compare.size()) - && (tolower(c) == (int)compare[ii]) - && istr.good()) - { - istr.ignore(); - ++bytes_read; - c = istr.peek(); - } - if(compare.size() != ii) - { - data.clear(); - return LLSDParser::PARSE_FAILURE; - } - data = value; - return bytes_read; + // + // this method is a little goofy, because it gets the stream at + // the point where the t or f has already been + // consumed. Basically, parse for a patch to the string passed in + // starting at index 1. If it's a match: + // * assign data to value + // * return the number of bytes read + // otherwise: + // * set data to LLSD::null + // * return LLSDParser::PARSE_FAILURE (-1) + // + llssize bytes_read = 0; + std::string::size_type ii = 0; + char c = istr.peek(); + while((++ii < compare.size()) + && (tolower(c) == (int)compare[ii]) + && istr.good()) + { + istr.ignore(); + ++bytes_read; + c = istr.peek(); + } + if(compare.size() != ii) + { + data.clear(); + return LLSDParser::PARSE_FAILURE; + } + data = value; + return bytes_read; } std::ostream& operator<<(std::ostream& s, const LLSD& llsd) { - s << LLSDNotationStreamer(llsd); - return s; + s << LLSDNotationStreamer(llsd); + return s; } @@ -2151,89 +2151,89 @@ std::ostream& operator<<(std::ostream& s, const LLSD& llsd) //return a string containing gzipped bytes of binary serialized LLSD // VERY inefficient -- creates several copies of LLSD block in memory std::string zip_llsd(LLSD& data) -{ - std::stringstream llsd_strm; - - LLSDSerialize::toBinary(data, llsd_strm); - - const U32 CHUNK = 65536; - - z_stream strm; - strm.zalloc = Z_NULL; - strm.zfree = Z_NULL; - strm.opaque = Z_NULL; - - S32 ret = deflateInit(&strm, Z_BEST_COMPRESSION); - if (ret != Z_OK) - { - LL_WARNS() << "Failed to compress LLSD block." << LL_ENDL; - return std::string(); - } - - std::string source = llsd_strm.str(); - - U8 out[CHUNK]; - - strm.avail_in = narrow(source.size()); - strm.next_in = (U8*) source.data(); - U8* output = NULL; - - U32 cur_size = 0; - - U32 have = 0; - - do - { - strm.avail_out = CHUNK; - strm.next_out = out; - - ret = deflate(&strm, Z_FINISH); - if (ret == Z_OK || ret == Z_STREAM_END) - { //copy result into output - if (strm.avail_out >= CHUNK) - { - deflateEnd(&strm); - if(output) - free(output); - LL_WARNS() << "Failed to compress LLSD block." << LL_ENDL; - return std::string(); - } - - have = CHUNK-strm.avail_out; - U8* new_output = (U8*) realloc(output, cur_size+have); - if (new_output == NULL) - { - LL_WARNS() << "Failed to compress LLSD block: can't reallocate memory, current size: " << cur_size << " bytes; requested " << cur_size + have << " bytes." << LL_ENDL; - deflateEnd(&strm); - if (output) - { - free(output); - } - return std::string(); - } - output = new_output; - memcpy(output+cur_size, out, have); - cur_size += have; - } - else - { - deflateEnd(&strm); - if(output) - free(output); - LL_WARNS() << "Failed to compress LLSD block." << LL_ENDL; - return std::string(); - } - } - while (ret == Z_OK); - - std::string::size_type size = cur_size; - - std::string result((char*) output, size); - deflateEnd(&strm); - if(output) - free(output); - - return result; +{ + std::stringstream llsd_strm; + + LLSDSerialize::toBinary(data, llsd_strm); + + const U32 CHUNK = 65536; + + z_stream strm; + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + + S32 ret = deflateInit(&strm, Z_BEST_COMPRESSION); + if (ret != Z_OK) + { + LL_WARNS() << "Failed to compress LLSD block." << LL_ENDL; + return std::string(); + } + + std::string source = llsd_strm.str(); + + U8 out[CHUNK]; + + strm.avail_in = narrow(source.size()); + strm.next_in = (U8*) source.data(); + U8* output = NULL; + + U32 cur_size = 0; + + U32 have = 0; + + do + { + strm.avail_out = CHUNK; + strm.next_out = out; + + ret = deflate(&strm, Z_FINISH); + if (ret == Z_OK || ret == Z_STREAM_END) + { //copy result into output + if (strm.avail_out >= CHUNK) + { + deflateEnd(&strm); + if(output) + free(output); + LL_WARNS() << "Failed to compress LLSD block." << LL_ENDL; + return std::string(); + } + + have = CHUNK-strm.avail_out; + U8* new_output = (U8*) realloc(output, cur_size+have); + if (new_output == NULL) + { + LL_WARNS() << "Failed to compress LLSD block: can't reallocate memory, current size: " << cur_size << " bytes; requested " << cur_size + have << " bytes." << LL_ENDL; + deflateEnd(&strm); + if (output) + { + free(output); + } + return std::string(); + } + output = new_output; + memcpy(output+cur_size, out, have); + cur_size += have; + } + else + { + deflateEnd(&strm); + if(output) + free(output); + LL_WARNS() << "Failed to compress LLSD block." << LL_ENDL; + return std::string(); + } + } + while (ret == Z_OK); + + std::string::size_type size = cur_size; + + std::string result((char*) output, size); + deflateEnd(&strm); + if(output) + free(output); + + return result; } //decompress a block of LLSD from provided istream @@ -2241,230 +2241,230 @@ std::string zip_llsd(LLSD& data) // and deserializes from that copy using LLSDSerialize LLUZipHelper::EZipRresult LLUZipHelper::unzip_llsd(LLSD& data, std::istream& is, S32 size) { - std::unique_ptr in = std::unique_ptr(new(std::nothrow) U8[size]); - if (!in) - { - return ZR_MEM_ERROR; - } - is.read((char*) in.get(), size); - - return unzip_llsd(data, in.get(), size); + std::unique_ptr in = std::unique_ptr(new(std::nothrow) U8[size]); + if (!in) + { + return ZR_MEM_ERROR; + } + is.read((char*) in.get(), size); + + return unzip_llsd(data, in.get(), size); } LLUZipHelper::EZipRresult LLUZipHelper::unzip_llsd(LLSD& data, const U8* in, S32 size) { - U8* result = NULL; - llssize cur_size = 0; - z_stream strm; - - constexpr U32 CHUNK = 1024 * 512; - - static thread_local std::unique_ptr out; - if (!out) - { - out = std::unique_ptr(new(std::nothrow) U8[CHUNK]); - } - - strm.zalloc = Z_NULL; - strm.zfree = Z_NULL; - strm.opaque = Z_NULL; - strm.avail_in = size; - strm.next_in = const_cast(in); - - S32 ret = inflateInit(&strm); - - do - { - strm.avail_out = CHUNK; - strm.next_out = out.get(); - ret = inflate(&strm, Z_NO_FLUSH); - switch (ret) - { - case Z_NEED_DICT: - case Z_DATA_ERROR: - { - inflateEnd(&strm); - free(result); - return ZR_DATA_ERROR; - } - case Z_STREAM_ERROR: - case Z_BUF_ERROR: - { - inflateEnd(&strm); - free(result); - return ZR_BUFFER_ERROR; - } - - case Z_MEM_ERROR: - { - inflateEnd(&strm); - free(result); - return ZR_MEM_ERROR; - } - } - - U32 have = CHUNK-strm.avail_out; - - U8* new_result = (U8*)realloc(result, cur_size + have); - if (new_result == NULL) - { - inflateEnd(&strm); - if (result) - { - free(result); - } - return ZR_MEM_ERROR; - } - result = new_result; - memcpy(result+cur_size, out.get(), have); - cur_size += have; - - } while (ret == Z_OK && ret != Z_STREAM_END); - - inflateEnd(&strm); - - if (ret != Z_STREAM_END) - { - free(result); - return ZR_DATA_ERROR; - } - - //result now points to the decompressed LLSD block - { - char* result_ptr = strip_deprecated_header((char*)result, cur_size); - - boost::iostreams::stream istrm(result_ptr, cur_size); - - if (!LLSDSerialize::fromBinary(data, istrm, cur_size, UNZIP_LLSD_MAX_DEPTH)) - { - free(result); - return ZR_PARSE_ERROR; - } - } - - free(result); - return ZR_OK; + U8* result = NULL; + llssize cur_size = 0; + z_stream strm; + + constexpr U32 CHUNK = 1024 * 512; + + static thread_local std::unique_ptr out; + if (!out) + { + out = std::unique_ptr(new(std::nothrow) U8[CHUNK]); + } + + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + strm.avail_in = size; + strm.next_in = const_cast(in); + + S32 ret = inflateInit(&strm); + + do + { + strm.avail_out = CHUNK; + strm.next_out = out.get(); + ret = inflate(&strm, Z_NO_FLUSH); + switch (ret) + { + case Z_NEED_DICT: + case Z_DATA_ERROR: + { + inflateEnd(&strm); + free(result); + return ZR_DATA_ERROR; + } + case Z_STREAM_ERROR: + case Z_BUF_ERROR: + { + inflateEnd(&strm); + free(result); + return ZR_BUFFER_ERROR; + } + + case Z_MEM_ERROR: + { + inflateEnd(&strm); + free(result); + return ZR_MEM_ERROR; + } + } + + U32 have = CHUNK-strm.avail_out; + + U8* new_result = (U8*)realloc(result, cur_size + have); + if (new_result == NULL) + { + inflateEnd(&strm); + if (result) + { + free(result); + } + return ZR_MEM_ERROR; + } + result = new_result; + memcpy(result+cur_size, out.get(), have); + cur_size += have; + + } while (ret == Z_OK && ret != Z_STREAM_END); + + inflateEnd(&strm); + + if (ret != Z_STREAM_END) + { + free(result); + return ZR_DATA_ERROR; + } + + //result now points to the decompressed LLSD block + { + char* result_ptr = strip_deprecated_header((char*)result, cur_size); + + boost::iostreams::stream istrm(result_ptr, cur_size); + + if (!LLSDSerialize::fromBinary(data, istrm, cur_size, UNZIP_LLSD_MAX_DEPTH)) + { + free(result); + return ZR_PARSE_ERROR; + } + } + + free(result); + return ZR_OK; } //This unzip function will only work with a gzip header and trailer - while the contents //of the actual compressed data is the same for either format (gzip vs zlib ), the headers //and trailers are different for the formats. U8* unzip_llsdNavMesh( bool& valid, size_t& outsize, std::istream& is, S32 size ) { - if (size == 0) - { - LL_WARNS() << "No data to unzip." << LL_ENDL; - return NULL; - } - - U8* result = NULL; - U32 cur_size = 0; - z_stream strm; - - const U32 CHUNK = 0x4000; - - U8 *in = new(std::nothrow) U8[size]; - if (in == NULL) - { - LL_WARNS() << "Memory allocation failure." << LL_ENDL; - return NULL; - } - is.read((char*) in, size); - - U8 out[CHUNK]; - - strm.zalloc = Z_NULL; - strm.zfree = Z_NULL; - strm.opaque = Z_NULL; - strm.avail_in = size; - strm.next_in = in; - - - S32 ret = inflateInit2(&strm, windowBits | ENABLE_ZLIB_GZIP ); - do - { - strm.avail_out = CHUNK; - strm.next_out = out; - ret = inflate(&strm, Z_NO_FLUSH); - if (ret == Z_STREAM_ERROR) - { - inflateEnd(&strm); - free(result); - delete [] in; - valid = false; - } - - switch (ret) - { - case Z_NEED_DICT: - ret = Z_DATA_ERROR; - case Z_DATA_ERROR: - case Z_MEM_ERROR: - inflateEnd(&strm); - free(result); - delete [] in; - valid = false; - break; - } - - U32 have = CHUNK-strm.avail_out; - - U8* new_result = (U8*) realloc(result, cur_size + have); - if (new_result == NULL) - { - LL_WARNS() << "Failed to unzip LLSD NavMesh block: can't reallocate memory, current size: " << cur_size - << " bytes; requested " << cur_size + have - << " bytes; total syze: ." << size << " bytes." - << LL_ENDL; - inflateEnd(&strm); - if (result) - { - free(result); - } - delete[] in; - valid = false; - return NULL; - } - result = new_result; - memcpy(result+cur_size, out, have); - cur_size += have; - - } while (ret == Z_OK); - - inflateEnd(&strm); - delete [] in; - - if (ret != Z_STREAM_END) - { - free(result); - valid = false; - return NULL; - } - - //result now points to the decompressed LLSD block - { - outsize= cur_size; - valid = true; - } - - return result; + if (size == 0) + { + LL_WARNS() << "No data to unzip." << LL_ENDL; + return NULL; + } + + U8* result = NULL; + U32 cur_size = 0; + z_stream strm; + + const U32 CHUNK = 0x4000; + + U8 *in = new(std::nothrow) U8[size]; + if (in == NULL) + { + LL_WARNS() << "Memory allocation failure." << LL_ENDL; + return NULL; + } + is.read((char*) in, size); + + U8 out[CHUNK]; + + strm.zalloc = Z_NULL; + strm.zfree = Z_NULL; + strm.opaque = Z_NULL; + strm.avail_in = size; + strm.next_in = in; + + + S32 ret = inflateInit2(&strm, windowBits | ENABLE_ZLIB_GZIP ); + do + { + strm.avail_out = CHUNK; + strm.next_out = out; + ret = inflate(&strm, Z_NO_FLUSH); + if (ret == Z_STREAM_ERROR) + { + inflateEnd(&strm); + free(result); + delete [] in; + valid = false; + } + + switch (ret) + { + case Z_NEED_DICT: + ret = Z_DATA_ERROR; + case Z_DATA_ERROR: + case Z_MEM_ERROR: + inflateEnd(&strm); + free(result); + delete [] in; + valid = false; + break; + } + + U32 have = CHUNK-strm.avail_out; + + U8* new_result = (U8*) realloc(result, cur_size + have); + if (new_result == NULL) + { + LL_WARNS() << "Failed to unzip LLSD NavMesh block: can't reallocate memory, current size: " << cur_size + << " bytes; requested " << cur_size + have + << " bytes; total syze: ." << size << " bytes." + << LL_ENDL; + inflateEnd(&strm); + if (result) + { + free(result); + } + delete[] in; + valid = false; + return NULL; + } + result = new_result; + memcpy(result+cur_size, out, have); + cur_size += have; + + } while (ret == Z_OK); + + inflateEnd(&strm); + delete [] in; + + if (ret != Z_STREAM_END) + { + free(result); + valid = false; + return NULL; + } + + //result now points to the decompressed LLSD block + { + outsize= cur_size; + valid = true; + } + + return result; } char* strip_deprecated_header(char* in, llssize& cur_size, llssize* header_size) { - const char* deprecated_header = ""; - constexpr size_t deprecated_header_size = 17; - - if (cur_size > deprecated_header_size - && memcmp(in, deprecated_header, deprecated_header_size) == 0) - { - in = in + deprecated_header_size; - cur_size = cur_size - deprecated_header_size; - if (header_size) - { - *header_size = deprecated_header_size + 1; - } - } - - return in; + const char* deprecated_header = ""; + constexpr size_t deprecated_header_size = 17; + + if (cur_size > deprecated_header_size + && memcmp(in, deprecated_header, deprecated_header_size) == 0) + { + in = in + deprecated_header_size; + cur_size = cur_size - deprecated_header_size; + if (header_size) + { + *header_size = deprecated_header_size + 1; + } + } + + return in; } diff --git a/indra/llcommon/llsdserialize.h b/indra/llcommon/llsdserialize.h index 676b7bfd6a..12dd3c96ec 100644 --- a/indra/llcommon/llsdserialize.h +++ b/indra/llcommon/llsdserialize.h @@ -1,4 +1,4 @@ -/** +/** * @file llsdserialize.h * @author Phoenix * @date 2006-02-26 @@ -7,21 +7,21 @@ * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -34,574 +34,574 @@ #include "llrefcount.h" #include "llsd.h" -/** +/** * @class LLSDParser * @brief Abstract base class for LLSD parsers. */ class LL_COMMON_API LLSDParser : public LLRefCount { protected: - /** - * @brief Destructor - */ - virtual ~LLSDParser(); + /** + * @brief Destructor + */ + virtual ~LLSDParser(); public: - /** - * @brief Anonymous enum to indicate parsing failure. - */ - enum - { - PARSE_FAILURE = -1 - }; - - /** - * @brief Constructor - */ - LLSDParser(); - - /** - * @brief Call this method to parse a stream for LLSD. - * - * This method parses the istream for a structured data. This - * method assumes that the istream is a complete llsd object -- - * for example an opened and closed map with an arbitrary nesting - * of elements. This method will return after reading one data - * object, allowing continued reading from the stream by the - * caller. - * @param istr The input stream. - * @param data[out] The newly parse structured data. - * @param max_bytes The maximum number of bytes that will be in - * the stream. Pass in LLSDSerialize::SIZE_UNLIMITED (-1) to set no - * byte limit. - * @return Returns the number of LLSD objects parsed into - * data. Returns PARSE_FAILURE (-1) on parse failure. - */ - S32 parse(std::istream& istr, LLSD& data, llssize max_bytes, S32 max_depth = -1); - - /** Like parse(), but uses a different call (istream.getline()) to read by lines - * This API is better suited for XML, where the parse cannot tell - * where the document actually ends. - */ - S32 parseLines(std::istream& istr, LLSD& data); - - /** - * @brief Resets the parser so parse() or parseLines() can be called again for another chunk. - */ - void reset() { doReset(); }; + /** + * @brief Anonymous enum to indicate parsing failure. + */ + enum + { + PARSE_FAILURE = -1 + }; + + /** + * @brief Constructor + */ + LLSDParser(); + + /** + * @brief Call this method to parse a stream for LLSD. + * + * This method parses the istream for a structured data. This + * method assumes that the istream is a complete llsd object -- + * for example an opened and closed map with an arbitrary nesting + * of elements. This method will return after reading one data + * object, allowing continued reading from the stream by the + * caller. + * @param istr The input stream. + * @param data[out] The newly parse structured data. + * @param max_bytes The maximum number of bytes that will be in + * the stream. Pass in LLSDSerialize::SIZE_UNLIMITED (-1) to set no + * byte limit. + * @return Returns the number of LLSD objects parsed into + * data. Returns PARSE_FAILURE (-1) on parse failure. + */ + S32 parse(std::istream& istr, LLSD& data, llssize max_bytes, S32 max_depth = -1); + + /** Like parse(), but uses a different call (istream.getline()) to read by lines + * This API is better suited for XML, where the parse cannot tell + * where the document actually ends. + */ + S32 parseLines(std::istream& istr, LLSD& data); + + /** + * @brief Resets the parser so parse() or parseLines() can be called again for another chunk. + */ + void reset() { doReset(); }; protected: - /** - * @brief Pure virtual base for doing the parse. - * - * This method parses the istream for a structured data. This - * method assumes that the istream is a complete llsd object -- - * for example an opened and closed map with an arbitrary nesting - * of elements. This method will return after reading one data - * object, allowing continued reading from the stream by the - * caller. - * @param istr The input stream. - * @param data[out] The newly parse structured data. - * @param max_depth Max depth parser will check before exiting - * with parse error, -1 - unlimited. - * @return Returns the number of LLSD objects parsed into - * data. Returns PARSE_FAILURE (-1) on parse failure. - */ - virtual S32 doParse(std::istream& istr, LLSD& data, S32 max_depth = -1) const = 0; - - /** - * @brief Virtual default function for resetting the parser - */ - virtual void doReset() {}; - - /* @name Simple istream helper methods - * - * These helper methods exist to help correctly use the - * mMaxBytesLeft without really thinking about it for most simple - * operations. Use of the streamtools in llstreamtools.h will - * require custom wrapping. - */ - //@{ - /** - * @brief get a byte off the stream - * - * @param istr The istream to work with. - * @return returns the next character. - */ - int get(std::istream& istr) const; - - /** - * @brief get several bytes off the stream into a buffer. - * - * @param istr The istream to work with. - * @param s The buffer to get into - * @param n Extract maximum of n-1 bytes and null temrinate. - * @param delim Delimiter to get until found. - * @return Returns istr. - */ - std::istream& get( - std::istream& istr, - char* s, - std::streamsize n, - char delim) const; - - /** - * @brief get several bytes off the stream into a streambuf - * - * @param istr The istream to work with. - * @param sb The streambuf to read into - * @param delim Delimiter to get until found. - * @return Returns istr. - */ - std::istream& get( - std::istream& istr, - std::streambuf& sb, - char delim) const; - - /** - * @brief ignore the next byte on the istream - * - * @param istr The istream to work with. - * @return Returns istr. - */ - std::istream& ignore(std::istream& istr) const; - - /** - * @brief put the last character retrieved back on the stream - * - * @param istr The istream to work with. - * @param c The character to put back - * @return Returns istr. - */ - std::istream& putback(std::istream& istr, char c) const; - - /** - * @brief read a block of n characters into a buffer - * - * @param istr The istream to work with. - * @param s The buffer to read into - * @param n The number of bytes to read. - * @return Returns istr. - */ - std::istream& read(std::istream& istr, char* s, std::streamsize n) const; - //@} + /** + * @brief Pure virtual base for doing the parse. + * + * This method parses the istream for a structured data. This + * method assumes that the istream is a complete llsd object -- + * for example an opened and closed map with an arbitrary nesting + * of elements. This method will return after reading one data + * object, allowing continued reading from the stream by the + * caller. + * @param istr The input stream. + * @param data[out] The newly parse structured data. + * @param max_depth Max depth parser will check before exiting + * with parse error, -1 - unlimited. + * @return Returns the number of LLSD objects parsed into + * data. Returns PARSE_FAILURE (-1) on parse failure. + */ + virtual S32 doParse(std::istream& istr, LLSD& data, S32 max_depth = -1) const = 0; + + /** + * @brief Virtual default function for resetting the parser + */ + virtual void doReset() {}; + + /* @name Simple istream helper methods + * + * These helper methods exist to help correctly use the + * mMaxBytesLeft without really thinking about it for most simple + * operations. Use of the streamtools in llstreamtools.h will + * require custom wrapping. + */ + //@{ + /** + * @brief get a byte off the stream + * + * @param istr The istream to work with. + * @return returns the next character. + */ + int get(std::istream& istr) const; + + /** + * @brief get several bytes off the stream into a buffer. + * + * @param istr The istream to work with. + * @param s The buffer to get into + * @param n Extract maximum of n-1 bytes and null temrinate. + * @param delim Delimiter to get until found. + * @return Returns istr. + */ + std::istream& get( + std::istream& istr, + char* s, + std::streamsize n, + char delim) const; + + /** + * @brief get several bytes off the stream into a streambuf + * + * @param istr The istream to work with. + * @param sb The streambuf to read into + * @param delim Delimiter to get until found. + * @return Returns istr. + */ + std::istream& get( + std::istream& istr, + std::streambuf& sb, + char delim) const; + + /** + * @brief ignore the next byte on the istream + * + * @param istr The istream to work with. + * @return Returns istr. + */ + std::istream& ignore(std::istream& istr) const; + + /** + * @brief put the last character retrieved back on the stream + * + * @param istr The istream to work with. + * @param c The character to put back + * @return Returns istr. + */ + std::istream& putback(std::istream& istr, char c) const; + + /** + * @brief read a block of n characters into a buffer + * + * @param istr The istream to work with. + * @param s The buffer to read into + * @param n The number of bytes to read. + * @return Returns istr. + */ + std::istream& read(std::istream& istr, char* s, std::streamsize n) const; + //@} protected: - /** - * @brief Accunt for bytes read outside of the istream helpers. - * - * Conceptually const since it only modifies mutable members. - * @param bytes The number of bytes read. - */ - void account(llssize bytes) const; + /** + * @brief Accunt for bytes read outside of the istream helpers. + * + * Conceptually const since it only modifies mutable members. + * @param bytes The number of bytes read. + */ + void account(llssize bytes) const; protected: - /** - * @brief boolean to set if byte counts should be checked during parsing. - */ - bool mCheckLimits; - - /** - * @brief The maximum number of bytes left to be parsed. - */ - mutable llssize mMaxBytesLeft; - - /** - * @brief Use line-based reading to get text - */ - bool mParseLines; + /** + * @brief boolean to set if byte counts should be checked during parsing. + */ + bool mCheckLimits; + + /** + * @brief The maximum number of bytes left to be parsed. + */ + mutable llssize mMaxBytesLeft; + + /** + * @brief Use line-based reading to get text + */ + bool mParseLines; }; -/** +/** * @class LLSDNotationParser * @brief Parser which handles the original notation format for LLSD. */ class LL_COMMON_API LLSDNotationParser : public LLSDParser { protected: - /** - * @brief Destructor - */ - virtual ~LLSDNotationParser(); + /** + * @brief Destructor + */ + virtual ~LLSDNotationParser(); public: - /** - * @brief Constructor - */ - LLSDNotationParser(); + /** + * @brief Constructor + */ + LLSDNotationParser(); protected: - /** - * @brief Call this method to parse a stream for LLSD. - * - * This method parses the istream for a structured data. This - * method assumes that the istream is a complete llsd object -- - * for example an opened and closed map with an arbitrary nesting - * of elements. This method will return after reading one data - * object, allowing continued reading from the stream by the - * caller. - * @param istr The input stream. - * @param data[out] The newly parse structured data. Undefined on failure. - * @param max_depth Max depth parser will check before exiting - * with parse error, -1 - unlimited. - * @return Returns the number of LLSD objects parsed into - * data. Returns PARSE_FAILURE (-1) on parse failure. - */ - virtual S32 doParse(std::istream& istr, LLSD& data, S32 max_depth = -1) const; + /** + * @brief Call this method to parse a stream for LLSD. + * + * This method parses the istream for a structured data. This + * method assumes that the istream is a complete llsd object -- + * for example an opened and closed map with an arbitrary nesting + * of elements. This method will return after reading one data + * object, allowing continued reading from the stream by the + * caller. + * @param istr The input stream. + * @param data[out] The newly parse structured data. Undefined on failure. + * @param max_depth Max depth parser will check before exiting + * with parse error, -1 - unlimited. + * @return Returns the number of LLSD objects parsed into + * data. Returns PARSE_FAILURE (-1) on parse failure. + */ + virtual S32 doParse(std::istream& istr, LLSD& data, S32 max_depth = -1) const; private: - /** - * @brief Parse a map from the istream - * - * @param istr The input stream. - * @param map The map to add the parsed data. - * @param max_depth Allowed parsing depth. - * @return Returns The number of LLSD objects parsed into data. - */ - S32 parseMap(std::istream& istr, LLSD& map, S32 max_depth) const; - - /** - * @brief Parse an array from the istream. - * - * @param istr The input stream. - * @param array The array to append the parsed data. - * @param max_depth Allowed parsing depth. - * @return Returns The number of LLSD objects parsed into data. - */ - S32 parseArray(std::istream& istr, LLSD& array, S32 max_depth) const; - - /** - * @brief Parse a string from the istream and assign it to data. - * - * @param istr The input stream. - * @param data[out] The data to assign. - * @return Retuns true if a complete string was parsed. - */ - bool parseString(std::istream& istr, LLSD& data) const; - - /** - * @brief Parse binary data from the stream. - * - * @param istr The input stream. - * @param data[out] The data to assign. - * @return Retuns true if a complete blob was parsed. - */ - bool parseBinary(std::istream& istr, LLSD& data) const; + /** + * @brief Parse a map from the istream + * + * @param istr The input stream. + * @param map The map to add the parsed data. + * @param max_depth Allowed parsing depth. + * @return Returns The number of LLSD objects parsed into data. + */ + S32 parseMap(std::istream& istr, LLSD& map, S32 max_depth) const; + + /** + * @brief Parse an array from the istream. + * + * @param istr The input stream. + * @param array The array to append the parsed data. + * @param max_depth Allowed parsing depth. + * @return Returns The number of LLSD objects parsed into data. + */ + S32 parseArray(std::istream& istr, LLSD& array, S32 max_depth) const; + + /** + * @brief Parse a string from the istream and assign it to data. + * + * @param istr The input stream. + * @param data[out] The data to assign. + * @return Retuns true if a complete string was parsed. + */ + bool parseString(std::istream& istr, LLSD& data) const; + + /** + * @brief Parse binary data from the stream. + * + * @param istr The input stream. + * @param data[out] The data to assign. + * @return Retuns true if a complete blob was parsed. + */ + bool parseBinary(std::istream& istr, LLSD& data) const; }; -/** +/** * @class LLSDXMLParser * @brief Parser which handles XML format LLSD. */ class LL_COMMON_API LLSDXMLParser : public LLSDParser { protected: - /** - * @brief Destructor - */ - virtual ~LLSDXMLParser(); + /** + * @brief Destructor + */ + virtual ~LLSDXMLParser(); public: - /** - * @brief Constructor - */ - LLSDXMLParser(bool emit_errors=true); + /** + * @brief Constructor + */ + LLSDXMLParser(bool emit_errors=true); protected: - /** - * @brief Call this method to parse a stream for LLSD. - * - * This method parses the istream for a structured data. This - * method assumes that the istream is a complete llsd object -- - * for example an opened and closed map with an arbitrary nesting - * of elements. This method will return after reading one data - * object, allowing continued reading from the stream by the - * caller. - * @param istr The input stream. - * @param data[out] The newly parse structured data. - * @param max_depth Max depth parser will check before exiting - * with parse error, -1 - unlimited. - * @return Returns the number of LLSD objects parsed into - * data. Returns PARSE_FAILURE (-1) on parse failure. - */ - virtual S32 doParse(std::istream& istr, LLSD& data, S32 max_depth = -1) const; - - /** - * @brief Virtual default function for resetting the parser - */ - virtual void doReset(); + /** + * @brief Call this method to parse a stream for LLSD. + * + * This method parses the istream for a structured data. This + * method assumes that the istream is a complete llsd object -- + * for example an opened and closed map with an arbitrary nesting + * of elements. This method will return after reading one data + * object, allowing continued reading from the stream by the + * caller. + * @param istr The input stream. + * @param data[out] The newly parse structured data. + * @param max_depth Max depth parser will check before exiting + * with parse error, -1 - unlimited. + * @return Returns the number of LLSD objects parsed into + * data. Returns PARSE_FAILURE (-1) on parse failure. + */ + virtual S32 doParse(std::istream& istr, LLSD& data, S32 max_depth = -1) const; + + /** + * @brief Virtual default function for resetting the parser + */ + virtual void doReset(); private: - class Impl; - Impl& impl; + class Impl; + Impl& impl; - void parsePart(const char* buf, llssize len); - friend class LLSDSerialize; + void parsePart(const char* buf, llssize len); + friend class LLSDSerialize; }; -/** +/** * @class LLSDBinaryParser * @brief Parser which handles binary formatted LLSD. */ class LL_COMMON_API LLSDBinaryParser : public LLSDParser { protected: - /** - * @brief Destructor - */ - virtual ~LLSDBinaryParser(); + /** + * @brief Destructor + */ + virtual ~LLSDBinaryParser(); public: - /** - * @brief Constructor - */ - LLSDBinaryParser(); + /** + * @brief Constructor + */ + LLSDBinaryParser(); protected: - /** - * @brief Call this method to parse a stream for LLSD. - * - * This method parses the istream for a structured data. This - * method assumes that the istream is a complete llsd object -- - * for example an opened and closed map with an arbitrary nesting - * of elements. This method will return after reading one data - * object, allowing continued reading from the stream by the - * caller. - * @param istr The input stream. - * @param data[out] The newly parse structured data. - * @param max_depth Max depth parser will check before exiting - * with parse error, -1 - unlimited. - * @return Returns the number of LLSD objects parsed into - * data. Returns -1 on parse failure. - */ - virtual S32 doParse(std::istream& istr, LLSD& data, S32 max_depth = -1) const; + /** + * @brief Call this method to parse a stream for LLSD. + * + * This method parses the istream for a structured data. This + * method assumes that the istream is a complete llsd object -- + * for example an opened and closed map with an arbitrary nesting + * of elements. This method will return after reading one data + * object, allowing continued reading from the stream by the + * caller. + * @param istr The input stream. + * @param data[out] The newly parse structured data. + * @param max_depth Max depth parser will check before exiting + * with parse error, -1 - unlimited. + * @return Returns the number of LLSD objects parsed into + * data. Returns -1 on parse failure. + */ + virtual S32 doParse(std::istream& istr, LLSD& data, S32 max_depth = -1) const; private: - /** - * @brief Parse a map from the istream - * - * @param istr The input stream. - * @param map The map to add the parsed data. - * @param max_depth Allowed parsing depth. - * @return Returns The number of LLSD objects parsed into data. - */ - S32 parseMap(std::istream& istr, LLSD& map, S32 max_depth) const; - - /** - * @brief Parse an array from the istream. - * - * @param istr The input stream. - * @param array The array to append the parsed data. - * @param max_depth Allowed parsing depth. - * @return Returns The number of LLSD objects parsed into data. - */ - S32 parseArray(std::istream& istr, LLSD& array, S32 max_depth) const; - - /** - * @brief Parse a string from the istream and assign it to data. - * - * @param istr The input stream. - * @param value[out] The string to assign. - * @return Retuns true if a complete string was parsed. - */ - bool parseString(std::istream& istr, std::string& value) const; + /** + * @brief Parse a map from the istream + * + * @param istr The input stream. + * @param map The map to add the parsed data. + * @param max_depth Allowed parsing depth. + * @return Returns The number of LLSD objects parsed into data. + */ + S32 parseMap(std::istream& istr, LLSD& map, S32 max_depth) const; + + /** + * @brief Parse an array from the istream. + * + * @param istr The input stream. + * @param array The array to append the parsed data. + * @param max_depth Allowed parsing depth. + * @return Returns The number of LLSD objects parsed into data. + */ + S32 parseArray(std::istream& istr, LLSD& array, S32 max_depth) const; + + /** + * @brief Parse a string from the istream and assign it to data. + * + * @param istr The input stream. + * @param value[out] The string to assign. + * @return Retuns true if a complete string was parsed. + */ + bool parseString(std::istream& istr, std::string& value) const; }; -/** +/** * @class LLSDFormatter * @brief Abstract base class for formatting LLSD. */ class LL_COMMON_API LLSDFormatter : public LLRefCount { protected: - /** - * @brief Destructor - */ - virtual ~LLSDFormatter(); + /** + * @brief Destructor + */ + virtual ~LLSDFormatter(); public: - /** - * Options for output - */ - typedef enum e_formatter_options_type - { - OPTIONS_NONE = 0, - OPTIONS_PRETTY = 1, - OPTIONS_PRETTY_BINARY = 2 - } EFormatterOptions; - - /** - * @brief Constructor - */ - LLSDFormatter(bool boolAlpha=false, const std::string& realFormat="", - EFormatterOptions options=OPTIONS_PRETTY_BINARY); - - /** - * @brief Set the boolean serialization format. - * - * @param alpha Serializes boolean as alpha if true. - */ - void boolalpha(bool alpha); - - /** - * @brief Set the real format - * - * By default, the formatter will use default double serialization - * which is frequently frustrating for many applications. You can - * set the precision on the stream independently, but that still - * might not work depending on the value. - * EXAMPLES:
- * %.2f
- * @param format A format string which follows the printf format - * rules. Specify an empty string to return to default formatting. - */ - void realFormat(const std::string& format); - - /** - * @brief Call this method to format an LLSD to a stream with options as - * set by the constructor. - * - * @param data The data to write. - * @param ostr The destination stream for the data. - * @return Returns The number of LLSD objects formatted out - */ - S32 format(const LLSD& data, std::ostream& ostr) const; - - /** - * @brief Call this method to format an LLSD to a stream, passing options - * explicitly. - * - * @param data The data to write. - * @param ostr The destination stream for the data. - * @param options OPTIONS_NONE to emit LLSD::Binary as raw bytes - * @return Returns The number of LLSD objects formatted out - */ - virtual S32 format(const LLSD& data, std::ostream& ostr, EFormatterOptions options) const; + /** + * Options for output + */ + typedef enum e_formatter_options_type + { + OPTIONS_NONE = 0, + OPTIONS_PRETTY = 1, + OPTIONS_PRETTY_BINARY = 2 + } EFormatterOptions; + + /** + * @brief Constructor + */ + LLSDFormatter(bool boolAlpha=false, const std::string& realFormat="", + EFormatterOptions options=OPTIONS_PRETTY_BINARY); + + /** + * @brief Set the boolean serialization format. + * + * @param alpha Serializes boolean as alpha if true. + */ + void boolalpha(bool alpha); + + /** + * @brief Set the real format + * + * By default, the formatter will use default double serialization + * which is frequently frustrating for many applications. You can + * set the precision on the stream independently, but that still + * might not work depending on the value. + * EXAMPLES:
+ * %.2f
+ * @param format A format string which follows the printf format + * rules. Specify an empty string to return to default formatting. + */ + void realFormat(const std::string& format); + + /** + * @brief Call this method to format an LLSD to a stream with options as + * set by the constructor. + * + * @param data The data to write. + * @param ostr The destination stream for the data. + * @return Returns The number of LLSD objects formatted out + */ + S32 format(const LLSD& data, std::ostream& ostr) const; + + /** + * @brief Call this method to format an LLSD to a stream, passing options + * explicitly. + * + * @param data The data to write. + * @param ostr The destination stream for the data. + * @param options OPTIONS_NONE to emit LLSD::Binary as raw bytes + * @return Returns The number of LLSD objects formatted out + */ + virtual S32 format(const LLSD& data, std::ostream& ostr, EFormatterOptions options) const; protected: - /** - * @brief Implementation to format the data. This is called recursively. - * - * @param data The data to write. - * @param ostr The destination stream for the data. - * @return Returns The number of LLSD objects formatted out - */ - virtual S32 format_impl(const LLSD& data, std::ostream& ostr, EFormatterOptions options, - U32 level) const = 0; - - /** - * @brief Helper method which appropriately obeys the real format. - * - * @param real The real value to format. - * @param ostr The destination stream for the data. - */ - void formatReal(LLSD::Real real, std::ostream& ostr) const; - - bool mBoolAlpha; - std::string mRealFormat; - EFormatterOptions mOptions; + /** + * @brief Implementation to format the data. This is called recursively. + * + * @param data The data to write. + * @param ostr The destination stream for the data. + * @return Returns The number of LLSD objects formatted out + */ + virtual S32 format_impl(const LLSD& data, std::ostream& ostr, EFormatterOptions options, + U32 level) const = 0; + + /** + * @brief Helper method which appropriately obeys the real format. + * + * @param real The real value to format. + * @param ostr The destination stream for the data. + */ + void formatReal(LLSD::Real real, std::ostream& ostr) const; + + bool mBoolAlpha; + std::string mRealFormat; + EFormatterOptions mOptions; }; -/** +/** * @class LLSDNotationFormatter * @brief Formatter which outputs the original notation format for LLSD. */ class LL_COMMON_API LLSDNotationFormatter : public LLSDFormatter { protected: - /** - * @brief Destructor - */ - virtual ~LLSDNotationFormatter(); + /** + * @brief Destructor + */ + virtual ~LLSDNotationFormatter(); public: - /** - * @brief Constructor - */ - LLSDNotationFormatter(bool boolAlpha=false, const std::string& realFormat="", - EFormatterOptions options=OPTIONS_PRETTY_BINARY); - - /** - * @brief Helper static method to return a notation escaped string - * - * This method will return the notation escaped string, but not - * the surrounding serialization identifiers such as a double or - * single quote. It will be up to the caller to embed those as - * appropriate. - * @param in The raw, unescaped string. - * @return Returns an escaped string appropriate for serialization. - */ - static std::string escapeString(const std::string& in); + /** + * @brief Constructor + */ + LLSDNotationFormatter(bool boolAlpha=false, const std::string& realFormat="", + EFormatterOptions options=OPTIONS_PRETTY_BINARY); + + /** + * @brief Helper static method to return a notation escaped string + * + * This method will return the notation escaped string, but not + * the surrounding serialization identifiers such as a double or + * single quote. It will be up to the caller to embed those as + * appropriate. + * @param in The raw, unescaped string. + * @return Returns an escaped string appropriate for serialization. + */ + static std::string escapeString(const std::string& in); protected: - /** - * @brief Implementation to format the data. This is called recursively. - * - * @param data The data to write. - * @param ostr The destination stream for the data. - * @return Returns The number of LLSD objects formatted out - */ - S32 format_impl(const LLSD& data, std::ostream& ostr, EFormatterOptions options, - U32 level) const override; + /** + * @brief Implementation to format the data. This is called recursively. + * + * @param data The data to write. + * @param ostr The destination stream for the data. + * @return Returns The number of LLSD objects formatted out + */ + S32 format_impl(const LLSD& data, std::ostream& ostr, EFormatterOptions options, + U32 level) const override; }; -/** +/** * @class LLSDXMLFormatter * @brief Formatter which outputs the LLSD as XML. */ class LL_COMMON_API LLSDXMLFormatter : public LLSDFormatter { protected: - /** - * @brief Destructor - */ - virtual ~LLSDXMLFormatter(); + /** + * @brief Destructor + */ + virtual ~LLSDXMLFormatter(); public: - /** - * @brief Constructor - */ - LLSDXMLFormatter(bool boolAlpha=false, const std::string& realFormat="", - EFormatterOptions options=OPTIONS_PRETTY_BINARY); - - /** - * @brief Helper static method to return an xml escaped string - * - * @param in A valid UTF-8 string. - * @return Returns an escaped string appropriate for serialization. - */ - static std::string escapeString(const std::string& in); - - /** - * @brief Call this method to format an LLSD to a stream. - * - * @param data The data to write. - * @param ostr The destination stream for the data. - * @return Returns The number of LLSD objects formatted out - */ - S32 format(const LLSD& data, std::ostream& ostr, EFormatterOptions options) const override; - - // also pull down base-class format() method that isn't overridden - using LLSDFormatter::format; + /** + * @brief Constructor + */ + LLSDXMLFormatter(bool boolAlpha=false, const std::string& realFormat="", + EFormatterOptions options=OPTIONS_PRETTY_BINARY); + + /** + * @brief Helper static method to return an xml escaped string + * + * @param in A valid UTF-8 string. + * @return Returns an escaped string appropriate for serialization. + */ + static std::string escapeString(const std::string& in); + + /** + * @brief Call this method to format an LLSD to a stream. + * + * @param data The data to write. + * @param ostr The destination stream for the data. + * @return Returns The number of LLSD objects formatted out + */ + S32 format(const LLSD& data, std::ostream& ostr, EFormatterOptions options) const override; + + // also pull down base-class format() method that isn't overridden + using LLSDFormatter::format; protected: - /** - * @brief Implementation to format the data. This is called recursively. - * - * @param data The data to write. - * @param ostr The destination stream for the data. - * @return Returns The number of LLSD objects formatted out - */ - S32 format_impl(const LLSD& data, std::ostream& ostr, EFormatterOptions options, - U32 level) const override; + /** + * @brief Implementation to format the data. This is called recursively. + * + * @param data The data to write. + * @param ostr The destination stream for the data. + * @return Returns The number of LLSD objects formatted out + */ + S32 format_impl(const LLSD& data, std::ostream& ostr, EFormatterOptions options, + U32 level) const override; }; -/** +/** * @class LLSDBinaryFormatter * @brief Formatter which outputs the LLSD as a binary notation format. * @@ -628,42 +628,42 @@ protected: class LL_COMMON_API LLSDBinaryFormatter : public LLSDFormatter { protected: - /** - * @brief Destructor - */ - virtual ~LLSDBinaryFormatter(); + /** + * @brief Destructor + */ + virtual ~LLSDBinaryFormatter(); public: - /** - * @brief Constructor - */ - LLSDBinaryFormatter(bool boolAlpha=false, const std::string& realFormat="", - EFormatterOptions options=OPTIONS_PRETTY_BINARY); + /** + * @brief Constructor + */ + LLSDBinaryFormatter(bool boolAlpha=false, const std::string& realFormat="", + EFormatterOptions options=OPTIONS_PRETTY_BINARY); protected: - /** - * @brief Implementation to format the data. This is called recursively. - * - * @param data The data to write. - * @param ostr The destination stream for the data. - * @return Returns The number of LLSD objects formatted out - */ - S32 format_impl(const LLSD& data, std::ostream& ostr, EFormatterOptions options, - U32 level) const override; - - /** - * @brief Helper method to serialize strings - * - * This method serializes a network byte order size and the raw - * string contents. - * @param string The string to write. - * @param ostr The destination stream for the data. - */ - void formatString(const std::string& string, std::ostream& ostr) const; + /** + * @brief Implementation to format the data. This is called recursively. + * + * @param data The data to write. + * @param ostr The destination stream for the data. + * @return Returns The number of LLSD objects formatted out + */ + S32 format_impl(const LLSD& data, std::ostream& ostr, EFormatterOptions options, + U32 level) const override; + + /** + * @brief Helper method to serialize strings + * + * This method serializes a network byte order size and the raw + * string contents. + * @param string The string to write. + * @param ostr The destination stream for the data. + */ + void formatString(const std::string& string, std::ostream& ostr) const; }; -/** +/** * @class LLSDNotationStreamFormatter * @brief Formatter which is specialized for use on streams which * outputs the original notation format for LLSD. @@ -674,7 +674,7 @@ protected: * LLSD sd;
* sd["foo"] = "bar";
* std::stringstream params;
- * params << "[{'version':i1}," << LLSDOStreamer(sd) + * params << "[{'version':i1}," << LLSDOStreamer(sd) * << "]"; * * @@ -687,165 +687,165 @@ template class LLSDOStreamer { public: - /** - * @brief Constructor - */ - LLSDOStreamer(const LLSD& data, - LLSDFormatter::EFormatterOptions options=LLSDFormatter::OPTIONS_PRETTY_BINARY) : - mSD(data), mOptions(options) {} - - /** - * @brief Stream operator. - * - * Use this inline during construction during a stream operation. - * @param str The destination stream for serialized output. - * @param The formatter which will output it's LLSD. - * @return Returns the stream passed in after streaming mSD. - */ - friend std::ostream& operator<<( - std::ostream& out, - const LLSDOStreamer& streamer) - { - LLPointer f = new Formatter; - f->format(streamer.mSD, out, streamer.mOptions); - return out; - } + /** + * @brief Constructor + */ + LLSDOStreamer(const LLSD& data, + LLSDFormatter::EFormatterOptions options=LLSDFormatter::OPTIONS_PRETTY_BINARY) : + mSD(data), mOptions(options) {} + + /** + * @brief Stream operator. + * + * Use this inline during construction during a stream operation. + * @param str The destination stream for serialized output. + * @param The formatter which will output it's LLSD. + * @return Returns the stream passed in after streaming mSD. + */ + friend std::ostream& operator<<( + std::ostream& out, + const LLSDOStreamer& streamer) + { + LLPointer f = new Formatter; + f->format(streamer.mSD, out, streamer.mOptions); + return out; + } protected: - LLSD mSD; - LLSDFormatter::EFormatterOptions mOptions; + LLSD mSD; + LLSDFormatter::EFormatterOptions mOptions; }; -typedef LLSDOStreamer LLSDNotationStreamer; -typedef LLSDOStreamer LLSDXMLStreamer; +typedef LLSDOStreamer LLSDNotationStreamer; +typedef LLSDOStreamer LLSDXMLStreamer; -/** +/** * @class LLSDSerialize * @brief Serializer / deserializer for the various LLSD formats */ class LL_COMMON_API LLSDSerialize { public: - enum ELLSD_Serialize - { + enum ELLSD_Serialize + { LLSD_BINARY, LLSD_XML, LLSD_NOTATION - }; - - /** - * @brief anonymouse enumeration for useful max_bytes constants. - */ - enum - { - // Setting an unlimited size is discouraged and should only be - // used when reading cin or another stream source which does - // not provide access to size. - SIZE_UNLIMITED = -1, - }; - - /* - * Generic in/outs - */ - static void serialize(const LLSD& sd, std::ostream& str, ELLSD_Serialize, - LLSDFormatter::EFormatterOptions options=LLSDFormatter::OPTIONS_PRETTY_BINARY); - - /** - * @brief Examine a stream, and parse 1 sd object out based on contents. - * - * @param sd [out] The data found on the stream - * @param str The incoming stream - * @param max_bytes the maximum number of bytes to parse - * @return Returns true if the stream appears to contain valid data - */ - static bool deserialize(LLSD& sd, std::istream& str, llssize max_bytes); - - /* - * Notation Methods - */ - static S32 toNotation(const LLSD& sd, std::ostream& str) - { - LLPointer f = new LLSDNotationFormatter; - return f->format(sd, str, LLSDFormatter::OPTIONS_NONE); - } - static S32 toPrettyNotation(const LLSD& sd, std::ostream& str) - { - LLPointer f = new LLSDNotationFormatter; - return f->format(sd, str, LLSDFormatter::OPTIONS_PRETTY); - } - static S32 toPrettyBinaryNotation(const LLSD& sd, std::ostream& str) - { - LLPointer f = new LLSDNotationFormatter; - return f->format(sd, str, - LLSDFormatter::EFormatterOptions(LLSDFormatter::OPTIONS_PRETTY | - LLSDFormatter::OPTIONS_PRETTY_BINARY)); - } - static S32 fromNotation(LLSD& sd, std::istream& str, llssize max_bytes) - { - LLPointer p = new LLSDNotationParser; - return p->parse(str, sd, max_bytes); - } - static LLSD fromNotation(std::istream& str, llssize max_bytes) - { - LLPointer p = new LLSDNotationParser; - LLSD sd; - (void)p->parse(str, sd, max_bytes); - return sd; - } - - /* - * XML Methods - */ - static S32 toXML(const LLSD& sd, std::ostream& str) - { - LLPointer f = new LLSDXMLFormatter; - return f->format(sd, str, LLSDFormatter::OPTIONS_NONE); - } - static S32 toPrettyXML(const LLSD& sd, std::ostream& str) - { - LLPointer f = new LLSDXMLFormatter; - return f->format(sd, str, LLSDFormatter::OPTIONS_PRETTY); - } - - static S32 fromXMLEmbedded(LLSD& sd, std::istream& str, bool emit_errors=true) - { - // no need for max_bytes since xml formatting is not - // subvertable by bad sizes. - LLPointer p = new LLSDXMLParser(emit_errors); - return p->parse(str, sd, LLSDSerialize::SIZE_UNLIMITED); - } - // Line oriented parser, 30% faster than fromXML(), but can - // only be used when you know you have the complete XML - // document available in the stream. - static S32 fromXMLDocument(LLSD& sd, std::istream& str, bool emit_errors=true) - { - LLPointer p = new LLSDXMLParser(emit_errors); - return p->parseLines(str, sd); - } - static S32 fromXML(LLSD& sd, std::istream& str, bool emit_errors=true) - { - return fromXMLEmbedded(sd, str, emit_errors); -// return fromXMLDocument(sd, str, emit_errors); - } - - /* - * Binary Methods - */ - static S32 toBinary(const LLSD& sd, std::ostream& str) - { - LLPointer f = new LLSDBinaryFormatter; - return f->format(sd, str, LLSDFormatter::OPTIONS_NONE); - } - static S32 fromBinary(LLSD& sd, std::istream& str, llssize max_bytes, S32 max_depth = -1) - { - LLPointer p = new LLSDBinaryParser; - return p->parse(str, sd, max_bytes, max_depth); - } - static LLSD fromBinary(std::istream& str, llssize max_bytes, S32 max_depth = -1) - { - LLPointer p = new LLSDBinaryParser; - LLSD sd; - (void)p->parse(str, sd, max_bytes, max_depth); - return sd; - } + }; + + /** + * @brief anonymouse enumeration for useful max_bytes constants. + */ + enum + { + // Setting an unlimited size is discouraged and should only be + // used when reading cin or another stream source which does + // not provide access to size. + SIZE_UNLIMITED = -1, + }; + + /* + * Generic in/outs + */ + static void serialize(const LLSD& sd, std::ostream& str, ELLSD_Serialize, + LLSDFormatter::EFormatterOptions options=LLSDFormatter::OPTIONS_PRETTY_BINARY); + + /** + * @brief Examine a stream, and parse 1 sd object out based on contents. + * + * @param sd [out] The data found on the stream + * @param str The incoming stream + * @param max_bytes the maximum number of bytes to parse + * @return Returns true if the stream appears to contain valid data + */ + static bool deserialize(LLSD& sd, std::istream& str, llssize max_bytes); + + /* + * Notation Methods + */ + static S32 toNotation(const LLSD& sd, std::ostream& str) + { + LLPointer f = new LLSDNotationFormatter; + return f->format(sd, str, LLSDFormatter::OPTIONS_NONE); + } + static S32 toPrettyNotation(const LLSD& sd, std::ostream& str) + { + LLPointer f = new LLSDNotationFormatter; + return f->format(sd, str, LLSDFormatter::OPTIONS_PRETTY); + } + static S32 toPrettyBinaryNotation(const LLSD& sd, std::ostream& str) + { + LLPointer f = new LLSDNotationFormatter; + return f->format(sd, str, + LLSDFormatter::EFormatterOptions(LLSDFormatter::OPTIONS_PRETTY | + LLSDFormatter::OPTIONS_PRETTY_BINARY)); + } + static S32 fromNotation(LLSD& sd, std::istream& str, llssize max_bytes) + { + LLPointer p = new LLSDNotationParser; + return p->parse(str, sd, max_bytes); + } + static LLSD fromNotation(std::istream& str, llssize max_bytes) + { + LLPointer p = new LLSDNotationParser; + LLSD sd; + (void)p->parse(str, sd, max_bytes); + return sd; + } + + /* + * XML Methods + */ + static S32 toXML(const LLSD& sd, std::ostream& str) + { + LLPointer f = new LLSDXMLFormatter; + return f->format(sd, str, LLSDFormatter::OPTIONS_NONE); + } + static S32 toPrettyXML(const LLSD& sd, std::ostream& str) + { + LLPointer f = new LLSDXMLFormatter; + return f->format(sd, str, LLSDFormatter::OPTIONS_PRETTY); + } + + static S32 fromXMLEmbedded(LLSD& sd, std::istream& str, bool emit_errors=true) + { + // no need for max_bytes since xml formatting is not + // subvertable by bad sizes. + LLPointer p = new LLSDXMLParser(emit_errors); + return p->parse(str, sd, LLSDSerialize::SIZE_UNLIMITED); + } + // Line oriented parser, 30% faster than fromXML(), but can + // only be used when you know you have the complete XML + // document available in the stream. + static S32 fromXMLDocument(LLSD& sd, std::istream& str, bool emit_errors=true) + { + LLPointer p = new LLSDXMLParser(emit_errors); + return p->parseLines(str, sd); + } + static S32 fromXML(LLSD& sd, std::istream& str, bool emit_errors=true) + { + return fromXMLEmbedded(sd, str, emit_errors); +// return fromXMLDocument(sd, str, emit_errors); + } + + /* + * Binary Methods + */ + static S32 toBinary(const LLSD& sd, std::ostream& str) + { + LLPointer f = new LLSDBinaryFormatter; + return f->format(sd, str, LLSDFormatter::OPTIONS_NONE); + } + static S32 fromBinary(LLSD& sd, std::istream& str, llssize max_bytes, S32 max_depth = -1) + { + LLPointer p = new LLSDBinaryParser; + return p->parse(str, sd, max_bytes, max_depth); + } + static LLSD fromBinary(std::istream& str, llssize max_bytes, S32 max_depth = -1) + { + LLPointer p = new LLSDBinaryParser; + LLSD sd; + (void)p->parse(str, sd, max_bytes, max_depth); + return sd; + } }; class LL_COMMON_API LLUZipHelper : public LLRefCount @@ -858,12 +858,12 @@ public: ZR_SIZE_ERROR, ZR_DATA_ERROR, ZR_PARSE_ERROR, - ZR_BUFFER_ERROR, - ZR_VERSION_ERROR + ZR_BUFFER_ERROR, + ZR_VERSION_ERROR } EZipRresult; // return OK or reason for failure static EZipRresult unzip_llsd(LLSD& data, std::istream& is, S32 size); - static EZipRresult unzip_llsd(LLSD& data, const U8* in, S32 size); + static EZipRresult unzip_llsd(LLSD& data, const U8* in, S32 size); }; //dirty little zip functions -- yell at davep diff --git a/indra/llcommon/llsdserialize_xml.cpp b/indra/llcommon/llsdserialize_xml.cpp index db61f4ae41..88cbb3b984 100644 --- a/indra/llcommon/llsdserialize_xml.cpp +++ b/indra/llcommon/llsdserialize_xml.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llsdserialize_xml.cpp * @brief XML parsers and formatters for LLSD * * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -58,195 +58,195 @@ LLSDXMLFormatter::~LLSDXMLFormatter() // virtual S32 LLSDXMLFormatter::format(const LLSD& data, std::ostream& ostr, - EFormatterOptions options) const + EFormatterOptions options) const { - std::streamsize old_precision = ostr.precision(25); - - std::string post; - if (options & LLSDFormatter::OPTIONS_PRETTY) - { - post = "\n"; - } - ostr << "" << post; - S32 rv = format_impl(data, ostr, options, 1); - ostr << "\n"; - - ostr.precision(old_precision); - return rv; + std::streamsize old_precision = ostr.precision(25); + + std::string post; + if (options & LLSDFormatter::OPTIONS_PRETTY) + { + post = "\n"; + } + ostr << "" << post; + S32 rv = format_impl(data, ostr, options, 1); + ostr << "\n"; + + ostr.precision(old_precision); + return rv; } S32 LLSDXMLFormatter::format_impl(const LLSD& data, std::ostream& ostr, - EFormatterOptions options, U32 level) const + EFormatterOptions options, U32 level) const { - S32 format_count = 1; - std::string pre; - std::string post; - - if (options & LLSDFormatter::OPTIONS_PRETTY) - { - for (U32 i = 0; i < level; i++) - { - pre += " "; - } - post = "\n"; - } - - switch(data.type()) - { - case LLSD::TypeMap: - if(0 == data.size()) - { - ostr << pre << "" << post; - } - else - { - ostr << pre << "" << post; - LLSD::map_const_iterator iter = data.beginMap(); - LLSD::map_const_iterator end = data.endMap(); - for(; iter != end; ++iter) - { - ostr << pre << "" << escapeString((*iter).first) << "" << post; - format_count += format_impl((*iter).second, ostr, options, level + 1); - } - ostr << pre << "" << post; - } - break; - - case LLSD::TypeArray: - if(0 == data.size()) - { - ostr << pre << "" << post; - } - else - { - ostr << pre << "" << post; - LLSD::array_const_iterator iter = data.beginArray(); - LLSD::array_const_iterator end = data.endArray(); - for(; iter != end; ++iter) - { - format_count += format_impl(*iter, ostr, options, level + 1); - } - ostr << pre << "" << post; - } - break; - - case LLSD::TypeUndefined: - ostr << pre << "" << post; - break; - - case LLSD::TypeBoolean: - ostr << pre << ""; - if(mBoolAlpha || - (ostr.flags() & std::ios::boolalpha) - ) - { - ostr << (data.asBoolean() ? "true" : "false"); - } - else - { - ostr << (data.asBoolean() ? 1 : 0); - } - ostr << "" << post; - break; - - case LLSD::TypeInteger: - ostr << pre << "" << data.asInteger() << "" << post; - break; - - case LLSD::TypeReal: - ostr << pre << ""; - if(mRealFormat.empty()) - { - ostr << data.asReal(); - } - else - { - formatReal(data.asReal(), ostr); - } - ostr << "" << post; - break; - - case LLSD::TypeUUID: - if(data.asUUID().isNull()) ostr << pre << "" << post; - else ostr << pre << "" << data.asUUID() << "" << post; - break; - - case LLSD::TypeString: - if(data.asStringRef().empty()) ostr << pre << "" << post; - else ostr << pre << "" << escapeString(data.asStringRef()) <<"" << post; - break; - - case LLSD::TypeDate: - ostr << pre << "" << data.asDate() << "" << post; - break; - - case LLSD::TypeURI: - ostr << pre << "" << escapeString(data.asString()) << "" << post; - break; - - case LLSD::TypeBinary: - { - const LLSD::Binary& buffer = data.asBinary(); - if(buffer.empty()) - { - ostr << pre << "" << post; - } - else - { - // *FIX: memory inefficient. - // *TODO: convert to use LLBase64 - ostr << pre << ""; - int b64_buffer_length = apr_base64_encode_len(narrow(buffer.size())); - char* b64_buffer = new char[b64_buffer_length]; - b64_buffer_length = apr_base64_encode_binary( - b64_buffer, - &buffer[0], - narrow(buffer.size())); - ostr.write(b64_buffer, b64_buffer_length - 1); - delete[] b64_buffer; - ostr << "" << post; - } - break; - } - default: - // *NOTE: This should never happen. - ostr << pre << "" << post; - break; - } - return format_count; + S32 format_count = 1; + std::string pre; + std::string post; + + if (options & LLSDFormatter::OPTIONS_PRETTY) + { + for (U32 i = 0; i < level; i++) + { + pre += " "; + } + post = "\n"; + } + + switch(data.type()) + { + case LLSD::TypeMap: + if(0 == data.size()) + { + ostr << pre << "" << post; + } + else + { + ostr << pre << "" << post; + LLSD::map_const_iterator iter = data.beginMap(); + LLSD::map_const_iterator end = data.endMap(); + for(; iter != end; ++iter) + { + ostr << pre << "" << escapeString((*iter).first) << "" << post; + format_count += format_impl((*iter).second, ostr, options, level + 1); + } + ostr << pre << "" << post; + } + break; + + case LLSD::TypeArray: + if(0 == data.size()) + { + ostr << pre << "" << post; + } + else + { + ostr << pre << "" << post; + LLSD::array_const_iterator iter = data.beginArray(); + LLSD::array_const_iterator end = data.endArray(); + for(; iter != end; ++iter) + { + format_count += format_impl(*iter, ostr, options, level + 1); + } + ostr << pre << "" << post; + } + break; + + case LLSD::TypeUndefined: + ostr << pre << "" << post; + break; + + case LLSD::TypeBoolean: + ostr << pre << ""; + if(mBoolAlpha || + (ostr.flags() & std::ios::boolalpha) + ) + { + ostr << (data.asBoolean() ? "true" : "false"); + } + else + { + ostr << (data.asBoolean() ? 1 : 0); + } + ostr << "" << post; + break; + + case LLSD::TypeInteger: + ostr << pre << "" << data.asInteger() << "" << post; + break; + + case LLSD::TypeReal: + ostr << pre << ""; + if(mRealFormat.empty()) + { + ostr << data.asReal(); + } + else + { + formatReal(data.asReal(), ostr); + } + ostr << "" << post; + break; + + case LLSD::TypeUUID: + if(data.asUUID().isNull()) ostr << pre << "" << post; + else ostr << pre << "" << data.asUUID() << "" << post; + break; + + case LLSD::TypeString: + if(data.asStringRef().empty()) ostr << pre << "" << post; + else ostr << pre << "" << escapeString(data.asStringRef()) <<"" << post; + break; + + case LLSD::TypeDate: + ostr << pre << "" << data.asDate() << "" << post; + break; + + case LLSD::TypeURI: + ostr << pre << "" << escapeString(data.asString()) << "" << post; + break; + + case LLSD::TypeBinary: + { + const LLSD::Binary& buffer = data.asBinary(); + if(buffer.empty()) + { + ostr << pre << "" << post; + } + else + { + // *FIX: memory inefficient. + // *TODO: convert to use LLBase64 + ostr << pre << ""; + int b64_buffer_length = apr_base64_encode_len(narrow(buffer.size())); + char* b64_buffer = new char[b64_buffer_length]; + b64_buffer_length = apr_base64_encode_binary( + b64_buffer, + &buffer[0], + narrow(buffer.size())); + ostr.write(b64_buffer, b64_buffer_length - 1); + delete[] b64_buffer; + ostr << "" << post; + } + break; + } + default: + // *NOTE: This should never happen. + ostr << pre << "" << post; + break; + } + return format_count; } // static std::string LLSDXMLFormatter::escapeString(const std::string& in) { - std::ostringstream out; - std::string::const_iterator it = in.begin(); - std::string::const_iterator end = in.end(); - for(; it != end; ++it) - { - switch((*it)) - { - case '<': - out << "<"; - break; - case '>': - out << ">"; - break; - case '&': - out << "&"; - break; - case '\'': - out << "'"; - break; - case '"': - out << """; - break; - default: - out << (*it); - break; - } - } - return out.str(); + std::ostringstream out; + std::string::const_iterator it = in.begin(); + std::string::const_iterator end = in.end(); + for(; it != end; ++it) + { + switch((*it)) + { + case '<': + out << "<"; + break; + case '>': + out << ">"; + break; + case '&': + out << "&"; + break; + case '\'': + out << "'"; + break; + case '"': + out << """; + break; + default: + out << (*it); + break; + } + } + return out.str(); } @@ -254,161 +254,161 @@ std::string LLSDXMLFormatter::escapeString(const std::string& in) class LLSDXMLParser::Impl { public: - Impl(bool emit_errors); - ~Impl(); - - S32 parse(std::istream& input, LLSD& data); - S32 parseLines(std::istream& input, LLSD& data); + Impl(bool emit_errors); + ~Impl(); + + S32 parse(std::istream& input, LLSD& data); + S32 parseLines(std::istream& input, LLSD& data); - void parsePart(const char *buf, llssize len); - - void reset(); + void parsePart(const char *buf, llssize len); + + void reset(); private: - void startElementHandler(const XML_Char* name, const XML_Char** attributes); - void endElementHandler(const XML_Char* name); - void characterDataHandler(const XML_Char* data, int length); - - static void sStartElementHandler( - void* userData, const XML_Char* name, const XML_Char** attributes); - static void sEndElementHandler( - void* userData, const XML_Char* name); - static void sCharacterDataHandler( - void* userData, const XML_Char* data, int length); - - void startSkipping(); - - enum Element { - ELEMENT_LLSD, - ELEMENT_UNDEF, - ELEMENT_BOOL, - ELEMENT_INTEGER, - ELEMENT_REAL, - ELEMENT_STRING, - ELEMENT_UUID, - ELEMENT_DATE, - ELEMENT_URI, - ELEMENT_BINARY, - ELEMENT_MAP, - ELEMENT_ARRAY, - ELEMENT_KEY, - ELEMENT_UNKNOWN - }; - static Element readElement(const XML_Char* name); - - static const XML_Char* findAttribute(const XML_Char* name, const XML_Char** pairs); - - bool mEmitErrors; - - XML_Parser mParser; - - LLSD mResult; - S32 mParseCount; - - bool mInLLSDElement; // true if we're on LLSD - bool mGracefullStop; // true if we found the
LLSDRefStack; - LLSDRefStack mStack; - - int mDepth; - bool mSkipping; - int mSkipThrough; - - std::string mCurrentKey; // Current XML - std::string mCurrentContent; // String data between and + void startElementHandler(const XML_Char* name, const XML_Char** attributes); + void endElementHandler(const XML_Char* name); + void characterDataHandler(const XML_Char* data, int length); + + static void sStartElementHandler( + void* userData, const XML_Char* name, const XML_Char** attributes); + static void sEndElementHandler( + void* userData, const XML_Char* name); + static void sCharacterDataHandler( + void* userData, const XML_Char* data, int length); + + void startSkipping(); + + enum Element { + ELEMENT_LLSD, + ELEMENT_UNDEF, + ELEMENT_BOOL, + ELEMENT_INTEGER, + ELEMENT_REAL, + ELEMENT_STRING, + ELEMENT_UUID, + ELEMENT_DATE, + ELEMENT_URI, + ELEMENT_BINARY, + ELEMENT_MAP, + ELEMENT_ARRAY, + ELEMENT_KEY, + ELEMENT_UNKNOWN + }; + static Element readElement(const XML_Char* name); + + static const XML_Char* findAttribute(const XML_Char* name, const XML_Char** pairs); + + bool mEmitErrors; + + XML_Parser mParser; + + LLSD mResult; + S32 mParseCount; + + bool mInLLSDElement; // true if we're on LLSD + bool mGracefullStop; // true if we found the
LLSDRefStack; + LLSDRefStack mStack; + + int mDepth; + bool mSkipping; + int mSkipThrough; + + std::string mCurrentKey; // Current XML + std::string mCurrentContent; // String data between and }; LLSDXMLParser::Impl::Impl(bool emit_errors) - : mEmitErrors(emit_errors) + : mEmitErrors(emit_errors) { - mParser = XML_ParserCreate(NULL); - reset(); + mParser = XML_ParserCreate(NULL); + reset(); } LLSDXMLParser::Impl::~Impl() { - XML_ParserFree(mParser); + XML_ParserFree(mParser); } inline bool is_eol(char c) { - return (c == '\n' || c == '\r'); + return (c == '\n' || c == '\r'); } void clear_eol(std::istream& input) { - char c = input.peek(); - while (input.good() && is_eol(c)) - { - input.get(c); - c = input.peek(); - } + char c = input.peek(); + while (input.good() && is_eol(c)) + { + input.get(c); + c = input.peek(); + } } static unsigned get_till_eol(std::istream& input, char *buf, unsigned bufsize) { - unsigned count = 0; - while (count < bufsize && input.good()) - { - char c = input.get(); - buf[count++] = c; - if (is_eol(c)) - break; - } - return count; + unsigned count = 0; + while (count < bufsize && input.good()) + { + char c = input.get(); + buf[count++] = c; + if (is_eol(c)) + break; + } + return count; } S32 LLSDXMLParser::Impl::parse(std::istream& input, LLSD& data) { - XML_Status status; - - static const int BUFFER_SIZE = 1024; - void* buffer = NULL; - int count = 0; - while (input.good() && !input.eof()) - { - buffer = XML_GetBuffer(mParser, BUFFER_SIZE); - - /* - * If we happened to end our last buffer right at the end of the llsd, but the - * stream is still going we will get a null buffer here. Check for mGracefullStop. - */ - if (!buffer) - { - break; - } - count = get_till_eol(input, (char *)buffer, BUFFER_SIZE); - if (!count) - { - break; - } - status = XML_ParseBuffer(mParser, count, false); - - if (status == XML_STATUS_ERROR) - { - break; - } - } - - // *FIX.: This code is buggy - if the stream was empty or not - // good, there is not buffer to parse, both the call to - // XML_ParseBuffer and the buffer manipulations are illegal - // futhermore, it isn't clear that the expat buffer semantics are - // preserved - - status = XML_ParseBuffer(mParser, 0, true); - if (status == XML_STATUS_ERROR && !mGracefullStop) - { - if (buffer) - { - ((char*) buffer)[count ? count - 1 : 0] = '\0'; + XML_Status status; + + static const int BUFFER_SIZE = 1024; + void* buffer = NULL; + int count = 0; + while (input.good() && !input.eof()) + { + buffer = XML_GetBuffer(mParser, BUFFER_SIZE); + + /* + * If we happened to end our last buffer right at the end of the llsd, but the + * stream is still going we will get a null buffer here. Check for mGracefullStop. + */ + if (!buffer) + { + break; + } + count = get_till_eol(input, (char *)buffer, BUFFER_SIZE); + if (!count) + { + break; + } + status = XML_ParseBuffer(mParser, count, false); + + if (status == XML_STATUS_ERROR) + { + break; + } + } + + // *FIX.: This code is buggy - if the stream was empty or not + // good, there is not buffer to parse, both the call to + // XML_ParseBuffer and the buffer manipulations are illegal + // futhermore, it isn't clear that the expat buffer semantics are + // preserved + + status = XML_ParseBuffer(mParser, 0, true); + if (status == XML_STATUS_ERROR && !mGracefullStop) + { + if (buffer) + { + ((char*) buffer)[count ? count - 1 : 0] = '\0'; if (mEmitErrors) { LL_INFOS() << "LLSDXMLParser::Impl::parse: XML_STATUS_ERROR parsing:" << (char*)buffer << LL_ENDL; } - } + } else { if (mEmitErrors) @@ -416,159 +416,159 @@ S32 LLSDXMLParser::Impl::parse(std::istream& input, LLSD& data) LL_INFOS() << "LLSDXMLParser::Impl::parse: XML_STATUS_ERROR, null buffer" << LL_ENDL; } } - data = LLSD(); - return LLSDParser::PARSE_FAILURE; - } + data = LLSD(); + return LLSDParser::PARSE_FAILURE; + } - clear_eol(input); - data = mResult; - return mParseCount; + clear_eol(input); + data = mResult; + return mParseCount; } S32 LLSDXMLParser::Impl::parseLines(std::istream& input, LLSD& data) { - XML_Status status = XML_STATUS_OK; - - data = LLSD(); - - static const int BUFFER_SIZE = 1024; - - //static char last_buffer[ BUFFER_SIZE ]; - //std::streamsize last_num_read; - - // Must get rid of any leading \n, otherwise the stream gets into an error/eof state - clear_eol(input); - - while( !mGracefullStop - && input.good() - && !input.eof()) - { - void* buffer = XML_GetBuffer(mParser, BUFFER_SIZE); - /* - * If we happened to end our last buffer right at the end of the llsd, but the - * stream is still going we will get a null buffer here. Check for mGracefullStop. - * -- I don't think this is actually true - zero 2008-05-09 - */ - if (!buffer) - { - break; - } - - // Get one line - input.getline((char*)buffer, BUFFER_SIZE); - std::streamsize num_read = input.gcount(); - - //memcpy( last_buffer, buffer, num_read ); - //last_num_read = num_read; - - if ( num_read > 0 ) - { - if (!input.good() ) - { // Clear state that's set when we run out of buffer - input.clear(); - } - - // Re-insert with the \n that was absorbed by getline() - char * text = (char *) buffer; - if ( text[num_read - 1] == 0) - { - text[num_read - 1] = '\n'; - } - } - - status = XML_ParseBuffer(mParser, (int)num_read, false); - if (status == XML_STATUS_ERROR) - { - break; - } - } - - if (status != XML_STATUS_ERROR - && !mGracefullStop) - { // Parse last bit - status = XML_ParseBuffer(mParser, 0, true); - } - - if (status == XML_STATUS_ERROR - && !mGracefullStop) - { - if (mEmitErrors) - { - LL_INFOS() << "LLSDXMLParser::Impl::parseLines: XML_STATUS_ERROR" << LL_ENDL; - } - return LLSDParser::PARSE_FAILURE; - } - - clear_eol(input); - data = mResult; - return mParseCount; + XML_Status status = XML_STATUS_OK; + + data = LLSD(); + + static const int BUFFER_SIZE = 1024; + + //static char last_buffer[ BUFFER_SIZE ]; + //std::streamsize last_num_read; + + // Must get rid of any leading \n, otherwise the stream gets into an error/eof state + clear_eol(input); + + while( !mGracefullStop + && input.good() + && !input.eof()) + { + void* buffer = XML_GetBuffer(mParser, BUFFER_SIZE); + /* + * If we happened to end our last buffer right at the end of the llsd, but the + * stream is still going we will get a null buffer here. Check for mGracefullStop. + * -- I don't think this is actually true - zero 2008-05-09 + */ + if (!buffer) + { + break; + } + + // Get one line + input.getline((char*)buffer, BUFFER_SIZE); + std::streamsize num_read = input.gcount(); + + //memcpy( last_buffer, buffer, num_read ); + //last_num_read = num_read; + + if ( num_read > 0 ) + { + if (!input.good() ) + { // Clear state that's set when we run out of buffer + input.clear(); + } + + // Re-insert with the \n that was absorbed by getline() + char * text = (char *) buffer; + if ( text[num_read - 1] == 0) + { + text[num_read - 1] = '\n'; + } + } + + status = XML_ParseBuffer(mParser, (int)num_read, false); + if (status == XML_STATUS_ERROR) + { + break; + } + } + + if (status != XML_STATUS_ERROR + && !mGracefullStop) + { // Parse last bit + status = XML_ParseBuffer(mParser, 0, true); + } + + if (status == XML_STATUS_ERROR + && !mGracefullStop) + { + if (mEmitErrors) + { + LL_INFOS() << "LLSDXMLParser::Impl::parseLines: XML_STATUS_ERROR" << LL_ENDL; + } + return LLSDParser::PARSE_FAILURE; + } + + clear_eol(input); + data = mResult; + return mParseCount; } void LLSDXMLParser::Impl::reset() { - mResult.clear(); - mParseCount = 0; - - mInLLSDElement = false; - mDepth = 0; - - mGracefullStop = false; - - mStack.clear(); - - mSkipping = false; - - mCurrentKey.clear(); - - XML_ParserReset(mParser, "utf-8"); - XML_SetUserData(mParser, this); - XML_SetElementHandler(mParser, sStartElementHandler, sEndElementHandler); - XML_SetCharacterDataHandler(mParser, sCharacterDataHandler); + mResult.clear(); + mParseCount = 0; + + mInLLSDElement = false; + mDepth = 0; + + mGracefullStop = false; + + mStack.clear(); + + mSkipping = false; + + mCurrentKey.clear(); + + XML_ParserReset(mParser, "utf-8"); + XML_SetUserData(mParser, this); + XML_SetElementHandler(mParser, sStartElementHandler, sEndElementHandler); + XML_SetCharacterDataHandler(mParser, sCharacterDataHandler); } void LLSDXMLParser::Impl::startSkipping() { - mSkipping = true; - mSkipThrough = mDepth; + mSkipping = true; + mSkipThrough = mDepth; } const XML_Char* LLSDXMLParser::Impl::findAttribute(const XML_Char* name, const XML_Char** pairs) { - while (NULL != pairs && NULL != *pairs) - { - if(0 == strcmp(name, *pairs)) - { - return *(pairs + 1); - } - pairs += 2; - } - return NULL; + while (NULL != pairs && NULL != *pairs) + { + if(0 == strcmp(name, *pairs)) + { + return *(pairs + 1); + } + pairs += 2; + } + return NULL; } void LLSDXMLParser::Impl::parsePart(const char* buf, llssize len) { - if ( buf != NULL - && len > 0 ) - { - XML_Status status = XML_Parse(mParser, buf, len, false); - if (status == XML_STATUS_ERROR) - { - LL_INFOS() << "Unexpected XML parsing error at start" << LL_ENDL; - } - } + if ( buf != NULL + && len > 0 ) + { + XML_Status status = XML_Parse(mParser, buf, len, false); + if (status == XML_STATUS_ERROR) + { + LL_INFOS() << "Unexpected XML parsing error at start" << LL_ENDL; + } + } } // Performance testing code -//#define XML_PARSER_PERFORMANCE_TESTS +//#define XML_PARSER_PERFORMANCE_TESTS #ifdef XML_PARSER_PERFORMANCE_TESTS extern U64 totalTime(); -U64 readElementTime = 0; +U64 readElementTime = 0; U64 startElementTime = 0; U64 endElementTime = 0; U64 charDataTime = 0; @@ -577,333 +577,333 @@ U64 parseTime = 0; class XML_Timer { public: - XML_Timer( U64 * sum ) : mSum( sum ) - { - mStart = totalTime(); - } - ~XML_Timer() - { - *mSum += (totalTime() - mStart); - } - - U64 * mSum; - U64 mStart; + XML_Timer( U64 * sum ) : mSum( sum ) + { + mStart = totalTime(); + } + ~XML_Timer() + { + *mSum += (totalTime() - mStart); + } + + U64 * mSum; + U64 mStart; }; #endif // XML_PARSER_PERFORMANCE_TESTS void LLSDXMLParser::Impl::startElementHandler(const XML_Char* name, const XML_Char** attributes) { - #ifdef XML_PARSER_PERFORMANCE_TESTS - XML_Timer timer( &startElementTime ); - #endif // XML_PARSER_PERFORMANCE_TESTS - - ++mDepth; - if (mSkipping) - { - return; - } - - Element element = readElement(name); - - mCurrentContent.clear(); - - switch (element) - { - case ELEMENT_LLSD: - if (mInLLSDElement) { return startSkipping(); } - mInLLSDElement = true; - return; - - case ELEMENT_KEY: - if (mStack.empty() || !(mStack.back()->isMap())) - { - return startSkipping(); - } - return; - - case ELEMENT_BINARY: - { - const XML_Char* encoding = findAttribute("encoding", attributes); - if(encoding && strcmp("base64", encoding) != 0) { return startSkipping(); } - break; - } - - default: - // all rest are values, fall through - ; - } - - - if (!mInLLSDElement) { return startSkipping(); } - - if (mStack.empty()) - { - mStack.push_back(&mResult); - } - else if (mStack.back()->isMap()) - { - if (mCurrentKey.empty()) { return startSkipping(); } - - LLSD& map = *mStack.back(); - LLSD& newElement = map[mCurrentKey]; - mStack.push_back(&newElement); - - mCurrentKey.clear(); - } - else if (mStack.back()->isArray()) - { - LLSD& array = *mStack.back(); - array.append(LLSD()); - LLSD& newElement = array[array.size()-1]; - mStack.push_back(&newElement); - } - else { - // improperly nested value in a non-structure - return startSkipping(); - } - - ++mParseCount; - switch (element) - { - case ELEMENT_MAP: - *mStack.back() = LLSD::emptyMap(); - break; - - case ELEMENT_ARRAY: - *mStack.back() = LLSD::emptyArray(); - break; - - default: - // all the other values will be set in the end element handler - ; - } + #ifdef XML_PARSER_PERFORMANCE_TESTS + XML_Timer timer( &startElementTime ); + #endif // XML_PARSER_PERFORMANCE_TESTS + + ++mDepth; + if (mSkipping) + { + return; + } + + Element element = readElement(name); + + mCurrentContent.clear(); + + switch (element) + { + case ELEMENT_LLSD: + if (mInLLSDElement) { return startSkipping(); } + mInLLSDElement = true; + return; + + case ELEMENT_KEY: + if (mStack.empty() || !(mStack.back()->isMap())) + { + return startSkipping(); + } + return; + + case ELEMENT_BINARY: + { + const XML_Char* encoding = findAttribute("encoding", attributes); + if(encoding && strcmp("base64", encoding) != 0) { return startSkipping(); } + break; + } + + default: + // all rest are values, fall through + ; + } + + + if (!mInLLSDElement) { return startSkipping(); } + + if (mStack.empty()) + { + mStack.push_back(&mResult); + } + else if (mStack.back()->isMap()) + { + if (mCurrentKey.empty()) { return startSkipping(); } + + LLSD& map = *mStack.back(); + LLSD& newElement = map[mCurrentKey]; + mStack.push_back(&newElement); + + mCurrentKey.clear(); + } + else if (mStack.back()->isArray()) + { + LLSD& array = *mStack.back(); + array.append(LLSD()); + LLSD& newElement = array[array.size()-1]; + mStack.push_back(&newElement); + } + else { + // improperly nested value in a non-structure + return startSkipping(); + } + + ++mParseCount; + switch (element) + { + case ELEMENT_MAP: + *mStack.back() = LLSD::emptyMap(); + break; + + case ELEMENT_ARRAY: + *mStack.back() = LLSD::emptyArray(); + break; + + default: + // all the other values will be set in the end element handler + ; + } } void LLSDXMLParser::Impl::endElementHandler(const XML_Char* name) { - #ifdef XML_PARSER_PERFORMANCE_TESTS - XML_Timer timer( &endElementTime ); - #endif // XML_PARSER_PERFORMANCE_TESTS - - --mDepth; - if (mSkipping) - { - if (mDepth < mSkipThrough) - { - mSkipping = false; - } - return; - } - - Element element = readElement(name); - - switch (element) - { - case ELEMENT_LLSD: - if (mInLLSDElement) - { - mInLLSDElement = false; - mGracefullStop = true; - XML_StopParser(mParser, false); - } - return; - - case ELEMENT_KEY: - mCurrentKey = mCurrentContent; - return; - - default: - // all rest are values, fall through - ; - } - - if (!mInLLSDElement) { return; } - - LLSD& value = *mStack.back(); - mStack.pop_back(); - - switch (element) - { - case ELEMENT_UNDEF: - value.clear(); - break; - - case ELEMENT_BOOL: - value = (mCurrentContent == "true" || mCurrentContent == "1"); - break; - - 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; - } - else - { - value = LLSD(mCurrentContent).asInteger(); - } - } - break; - - case ELEMENT_REAL: - { - 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; - - case ELEMENT_STRING: - value = mCurrentContent; - break; - - case ELEMENT_UUID: - value = LLSD(mCurrentContent).asUUID(); - break; - - case ELEMENT_DATE: - value = LLSD(mCurrentContent).asDate(); - break; - - case ELEMENT_URI: - value = LLSD(mCurrentContent).asURI(); - break; - - case ELEMENT_BINARY: - { - // 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], stripped.c_str()); - data.resize(len); - value = data; - break; - } - - case ELEMENT_UNKNOWN: - value.clear(); - break; - - default: - // other values, map and array, have already been set - break; - } - - mCurrentContent.clear(); + #ifdef XML_PARSER_PERFORMANCE_TESTS + XML_Timer timer( &endElementTime ); + #endif // XML_PARSER_PERFORMANCE_TESTS + + --mDepth; + if (mSkipping) + { + if (mDepth < mSkipThrough) + { + mSkipping = false; + } + return; + } + + Element element = readElement(name); + + switch (element) + { + case ELEMENT_LLSD: + if (mInLLSDElement) + { + mInLLSDElement = false; + mGracefullStop = true; + XML_StopParser(mParser, false); + } + return; + + case ELEMENT_KEY: + mCurrentKey = mCurrentContent; + return; + + default: + // all rest are values, fall through + ; + } + + if (!mInLLSDElement) { return; } + + LLSD& value = *mStack.back(); + mStack.pop_back(); + + switch (element) + { + case ELEMENT_UNDEF: + value.clear(); + break; + + case ELEMENT_BOOL: + value = (mCurrentContent == "true" || mCurrentContent == "1"); + break; + + 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; + } + else + { + value = LLSD(mCurrentContent).asInteger(); + } + } + break; + + case ELEMENT_REAL: + { + 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; + + case ELEMENT_STRING: + value = mCurrentContent; + break; + + case ELEMENT_UUID: + value = LLSD(mCurrentContent).asUUID(); + break; + + case ELEMENT_DATE: + value = LLSD(mCurrentContent).asDate(); + break; + + case ELEMENT_URI: + value = LLSD(mCurrentContent).asURI(); + break; + + case ELEMENT_BINARY: + { + // 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], stripped.c_str()); + data.resize(len); + value = data; + break; + } + + case ELEMENT_UNKNOWN: + value.clear(); + break; + + default: + // other values, map and array, have already been set + break; + } + + mCurrentContent.clear(); } void LLSDXMLParser::Impl::characterDataHandler(const XML_Char* data, int length) { - #ifdef XML_PARSER_PERFORMANCE_TESTS - XML_Timer timer( &charDataTime ); - #endif // XML_PARSER_PERFORMANCE_TESTS + #ifdef XML_PARSER_PERFORMANCE_TESTS + XML_Timer timer( &charDataTime ); + #endif // XML_PARSER_PERFORMANCE_TESTS - mCurrentContent.append(data, length); + mCurrentContent.append(data, length); } void LLSDXMLParser::Impl::sStartElementHandler( - void* userData, const XML_Char* name, const XML_Char** attributes) + void* userData, const XML_Char* name, const XML_Char** attributes) { - ((LLSDXMLParser::Impl*)userData)->startElementHandler(name, attributes); + ((LLSDXMLParser::Impl*)userData)->startElementHandler(name, attributes); } void LLSDXMLParser::Impl::sEndElementHandler( - void* userData, const XML_Char* name) + void* userData, const XML_Char* name) { - ((LLSDXMLParser::Impl*)userData)->endElementHandler(name); + ((LLSDXMLParser::Impl*)userData)->endElementHandler(name); } void LLSDXMLParser::Impl::sCharacterDataHandler( - void* userData, const XML_Char* data, int length) + void* userData, const XML_Char* data, int length) { - ((LLSDXMLParser::Impl*)userData)->characterDataHandler(data, length); + ((LLSDXMLParser::Impl*)userData)->characterDataHandler(data, length); } /* - This code is time critical - - This is a sample of tag occurances of text in simstate file with ~8000 objects. - A tag pair (something) counts is counted as two: - - key - 2680178 - real - 1818362 - integer - 906078 - array - 295682 - map - 191818 - uuid - 177903 - binary - 175748 - string - 53482 - undef - 40353 - boolean - 33874 - llsd - 16332 - uri - 38 - date - 1 + This code is time critical + + This is a sample of tag occurances of text in simstate file with ~8000 objects. + A tag pair (something) counts is counted as two: + + key - 2680178 + real - 1818362 + integer - 906078 + array - 295682 + map - 191818 + uuid - 177903 + binary - 175748 + string - 53482 + undef - 40353 + boolean - 33874 + llsd - 16332 + uri - 38 + date - 1 */ LLSDXMLParser::Impl::Element LLSDXMLParser::Impl::readElement(const XML_Char* name) { - #ifdef XML_PARSER_PERFORMANCE_TESTS - XML_Timer timer( &readElementTime ); - #endif // XML_PARSER_PERFORMANCE_TESTS - - XML_Char c = *name; - switch (c) - { - case 'k': - if (strcmp(name, "key") == 0) { return ELEMENT_KEY; } - break; - case 'r': - if (strcmp(name, "real") == 0) { return ELEMENT_REAL; } - break; - case 'i': - if (strcmp(name, "integer") == 0) { return ELEMENT_INTEGER; } - break; - case 'a': - if (strcmp(name, "array") == 0) { return ELEMENT_ARRAY; } - break; - case 'm': - if (strcmp(name, "map") == 0) { return ELEMENT_MAP; } - break; - case 'u': - if (strcmp(name, "uuid") == 0) { return ELEMENT_UUID; } - if (strcmp(name, "undef") == 0) { return ELEMENT_UNDEF; } - if (strcmp(name, "uri") == 0) { return ELEMENT_URI; } - break; - case 'b': - if (strcmp(name, "binary") == 0) { return ELEMENT_BINARY; } - if (strcmp(name, "boolean") == 0) { return ELEMENT_BOOL; } - break; - case 's': - if (strcmp(name, "string") == 0) { return ELEMENT_STRING; } - break; - case 'l': - if (strcmp(name, "llsd") == 0) { return ELEMENT_LLSD; } - break; - case 'd': - if (strcmp(name, "date") == 0) { return ELEMENT_DATE; } - break; - } - return ELEMENT_UNKNOWN; + #ifdef XML_PARSER_PERFORMANCE_TESTS + XML_Timer timer( &readElementTime ); + #endif // XML_PARSER_PERFORMANCE_TESTS + + XML_Char c = *name; + switch (c) + { + case 'k': + if (strcmp(name, "key") == 0) { return ELEMENT_KEY; } + break; + case 'r': + if (strcmp(name, "real") == 0) { return ELEMENT_REAL; } + break; + case 'i': + if (strcmp(name, "integer") == 0) { return ELEMENT_INTEGER; } + break; + case 'a': + if (strcmp(name, "array") == 0) { return ELEMENT_ARRAY; } + break; + case 'm': + if (strcmp(name, "map") == 0) { return ELEMENT_MAP; } + break; + case 'u': + if (strcmp(name, "uuid") == 0) { return ELEMENT_UUID; } + if (strcmp(name, "undef") == 0) { return ELEMENT_UNDEF; } + if (strcmp(name, "uri") == 0) { return ELEMENT_URI; } + break; + case 'b': + if (strcmp(name, "binary") == 0) { return ELEMENT_BINARY; } + if (strcmp(name, "boolean") == 0) { return ELEMENT_BOOL; } + break; + case 's': + if (strcmp(name, "string") == 0) { return ELEMENT_STRING; } + break; + case 'l': + if (strcmp(name, "llsd") == 0) { return ELEMENT_LLSD; } + break; + case 'd': + if (strcmp(name, "date") == 0) { return ELEMENT_DATE; } + break; + } + return ELEMENT_UNKNOWN; } @@ -919,34 +919,34 @@ LLSDXMLParser::LLSDXMLParser(bool emit_errors /* = true */) : impl(* new Impl(em LLSDXMLParser::~LLSDXMLParser() { - delete &impl; + delete &impl; } void LLSDXMLParser::parsePart(const char *buf, llssize len) { - impl.parsePart(buf, len); + impl.parsePart(buf, len); } // virtual S32 LLSDXMLParser::doParse(std::istream& input, LLSD& data, S32 max_depth) const { - LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD + LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD - #ifdef XML_PARSER_PERFORMANCE_TESTS - XML_Timer timer( &parseTime ); - #endif // XML_PARSER_PERFORMANCE_TESTS + #ifdef XML_PARSER_PERFORMANCE_TESTS + XML_Timer timer( &parseTime ); + #endif // XML_PARSER_PERFORMANCE_TESTS - if (mParseLines) - { - // Use line-based reading (faster code) - return impl.parseLines(input, data); - } + if (mParseLines) + { + // Use line-based reading (faster code) + return impl.parseLines(input, data); + } - return impl.parse(input, data); + return impl.parse(input, data); } -// virtual +// virtual void LLSDXMLParser::doReset() { - impl.reset(); + impl.reset(); } diff --git a/indra/llcommon/llsdserialize_xml.h b/indra/llcommon/llsdserialize_xml.h index dcc5f3d3c7..6c1a74c0e3 100644 --- a/indra/llcommon/llsdserialize_xml.h +++ b/indra/llcommon/llsdserialize_xml.h @@ -1,25 +1,25 @@ -/** +/** * @file llsdserialize_xml.h * @brief XML parsers and formatters for LLSD * * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcommon/llsdutil.cpp b/indra/llcommon/llsdutil.cpp index e98fc0285a..efce458117 100644 --- a/indra/llcommon/llsdutil.cpp +++ b/indra/llcommon/llsdutil.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llsdutil.cpp * @author Phoenix * @date 2006-05-24 @@ -7,21 +7,21 @@ * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -32,12 +32,12 @@ #include #if LL_WINDOWS -# define WIN32_LEAN_AND_MEAN -# include // for htonl +# define WIN32_LEAN_AND_MEAN +# include // for htonl #elif LL_LINUX -# include +# include #elif LL_DARWIN -# include +# include #endif #include "llsdserialize.h" @@ -51,152 +51,152 @@ // U32 LLSD ll_sd_from_U32(const U32 val) { - std::vector v; - U32 net_order = htonl(val); + std::vector v; + U32 net_order = htonl(val); - v.resize(4); - memcpy(&(v[0]), &net_order, 4); /* Flawfinder: ignore */ + v.resize(4); + memcpy(&(v[0]), &net_order, 4); /* Flawfinder: ignore */ - return LLSD(v); + return LLSD(v); } U32 ll_U32_from_sd(const LLSD& sd) { - U32 ret; - std::vector v = sd.asBinary(); - if (v.size() < 4) - { - return 0; - } - memcpy(&ret, &(v[0]), 4); /* Flawfinder: ignore */ - ret = ntohl(ret); - return ret; + U32 ret; + std::vector v = sd.asBinary(); + if (v.size() < 4) + { + return 0; + } + memcpy(&ret, &(v[0]), 4); /* Flawfinder: ignore */ + ret = ntohl(ret); + return ret; } //U64 LLSD ll_sd_from_U64(const U64 val) { - std::vector v; - U32 high, low; + std::vector v; + U32 high, low; - high = (U32)(val >> 32); - low = (U32)val; - high = htonl(high); - low = htonl(low); + high = (U32)(val >> 32); + low = (U32)val; + high = htonl(high); + low = htonl(low); - v.resize(8); - memcpy(&(v[0]), &high, 4); /* Flawfinder: ignore */ - memcpy(&(v[4]), &low, 4); /* Flawfinder: ignore */ + v.resize(8); + memcpy(&(v[0]), &high, 4); /* Flawfinder: ignore */ + memcpy(&(v[4]), &low, 4); /* Flawfinder: ignore */ - return LLSD(v); + return LLSD(v); } U64 ll_U64_from_sd(const LLSD& sd) { - U32 high, low; - std::vector v = sd.asBinary(); + U32 high, low; + std::vector v = sd.asBinary(); - if (v.size() < 8) - { - return 0; - } + if (v.size() < 8) + { + return 0; + } - memcpy(&high, &(v[0]), 4); /* Flawfinder: ignore */ - memcpy(&low, &(v[4]), 4); /* Flawfinder: ignore */ - high = ntohl(high); - low = ntohl(low); + memcpy(&high, &(v[0]), 4); /* Flawfinder: ignore */ + memcpy(&low, &(v[4]), 4); /* Flawfinder: ignore */ + high = ntohl(high); + low = ntohl(low); - return ((U64)high) << 32 | low; + return ((U64)high) << 32 | low; } // IP Address (stored in net order in a U32, so don't need swizzling) LLSD ll_sd_from_ipaddr(const U32 val) { - std::vector v; + std::vector v; - v.resize(4); - memcpy(&(v[0]), &val, 4); /* Flawfinder: ignore */ + v.resize(4); + memcpy(&(v[0]), &val, 4); /* Flawfinder: ignore */ - return LLSD(v); + return LLSD(v); } U32 ll_ipaddr_from_sd(const LLSD& sd) { - U32 ret; - std::vector v = sd.asBinary(); - if (v.size() < 4) - { - return 0; - } - memcpy(&ret, &(v[0]), 4); /* Flawfinder: ignore */ - return ret; + U32 ret; + std::vector v = sd.asBinary(); + if (v.size() < 4) + { + return 0; + } + memcpy(&ret, &(v[0]), 4); /* Flawfinder: ignore */ + return ret; } // Converts an LLSD binary to an LLSD string LLSD ll_string_from_binary(const LLSD& sd) { - std::vector value = sd.asBinary(); - std::string str; - str.resize(value.size()); - memcpy(&str[0], &value[0], value.size()); - return str; + std::vector value = sd.asBinary(); + std::string str; + str.resize(value.size()); + memcpy(&str[0], &value[0], value.size()); + return str; } // Converts an LLSD string to an LLSD binary LLSD ll_binary_from_string(const LLSD& sd) { - std::vector binary_value; + std::vector binary_value; - std::string string_value = sd.asString(); - for (const U8 c : string_value) - { - binary_value.push_back(c); - } + std::string string_value = sd.asString(); + for (const U8 c : string_value) + { + binary_value.push_back(c); + } - binary_value.push_back('\0'); + binary_value.push_back('\0'); - return binary_value; + return binary_value; } char* ll_print_sd(const LLSD& sd) { - const U32 bufferSize = 10 * 1024; - static char buffer[bufferSize]; - std::ostringstream stream; - //stream.rdbuf()->pubsetbuf(buffer, bufferSize); - stream << LLSDOStreamer(sd); - stream << std::ends; - strncpy(buffer, stream.str().c_str(), bufferSize); - buffer[bufferSize - 1] = '\0'; - return buffer; + const U32 bufferSize = 10 * 1024; + static char buffer[bufferSize]; + std::ostringstream stream; + //stream.rdbuf()->pubsetbuf(buffer, bufferSize); + stream << LLSDOStreamer(sd); + stream << std::ends; + strncpy(buffer, stream.str().c_str(), bufferSize); + buffer[bufferSize - 1] = '\0'; + return buffer; } char* ll_pretty_print_sd_ptr(const LLSD* sd) { - if (sd) - { - return ll_pretty_print_sd(*sd); - } - return NULL; + if (sd) + { + return ll_pretty_print_sd(*sd); + } + return NULL; } char* ll_pretty_print_sd(const LLSD& sd) { - const U32 bufferSize = 100 * 1024; - static char buffer[bufferSize]; - std::ostringstream stream; - //stream.rdbuf()->pubsetbuf(buffer, bufferSize); - stream << LLSDOStreamer(sd, LLSDFormatter::OPTIONS_PRETTY); - stream << std::ends; - strncpy(buffer, stream.str().c_str(), bufferSize); - buffer[bufferSize - 1] = '\0'; - return buffer; + const U32 bufferSize = 100 * 1024; + static char buffer[bufferSize]; + std::ostringstream stream; + //stream.rdbuf()->pubsetbuf(buffer, bufferSize); + stream << LLSDOStreamer(sd, LLSDFormatter::OPTIONS_PRETTY); + stream << std::ends; + strncpy(buffer, stream.str().c_str(), bufferSize); + buffer[bufferSize - 1] = '\0'; + return buffer; } std::string ll_stream_notation_sd(const LLSD& sd) { - std::ostringstream stream; - stream << LLSDOStreamer(sd); + std::ostringstream stream; + stream << LLSDOStreamer(sd); return stream.str(); } @@ -210,121 +210,121 @@ std::string ll_stream_notation_sd(const LLSD& sd) //of the same value. Ordering of arrays matters //Otherwise, returns true BOOL compare_llsd_with_template( - const LLSD& llsd_to_test, - const LLSD& template_llsd, - LLSD& resultant_llsd) + const LLSD& llsd_to_test, + const LLSD& template_llsd, + LLSD& resultant_llsd) { LL_PROFILE_ZONE_SCOPED - if ( - llsd_to_test.isUndefined() && - template_llsd.isDefined() ) - { - resultant_llsd = template_llsd; - return TRUE; - } - else if ( llsd_to_test.type() != template_llsd.type() ) - { - resultant_llsd = LLSD(); - return FALSE; - } - - if ( llsd_to_test.isArray() ) - { - //they are both arrays - //we loop over all the items in the template - //verifying that the to_test has a subset (in the same order) - //any shortcoming in the testing_llsd are just taken - //to be the rest of the template - LLSD data; - LLSD::array_const_iterator test_iter; - LLSD::array_const_iterator template_iter; - - resultant_llsd = LLSD::emptyArray(); - test_iter = llsd_to_test.beginArray(); - - for ( - template_iter = template_llsd.beginArray(); - (template_iter != template_llsd.endArray() && - test_iter != llsd_to_test.endArray()); - ++template_iter) - { - if ( !compare_llsd_with_template( - *test_iter, - *template_iter, - data) ) - { - resultant_llsd = LLSD(); - return FALSE; - } - else - { - resultant_llsd.append(data); - } - - ++test_iter; - } - - //so either the test or the template ended - //we do another loop now to the end of the template - //grabbing the default values - for (; - template_iter != template_llsd.endArray(); - ++template_iter) - { - resultant_llsd.append(*template_iter); - } - } - else if ( llsd_to_test.isMap() ) - { - //now we loop over the keys of the two maps - //any excess is taken from the template - //excess is ignored in the test - LLSD value; - LLSD::map_const_iterator template_iter; - - resultant_llsd = LLSD::emptyMap(); - for ( - template_iter = template_llsd.beginMap(); - template_iter != template_llsd.endMap(); - ++template_iter) - { - if ( llsd_to_test.has(template_iter->first) ) - { - //the test LLSD has the same key - if ( !compare_llsd_with_template( - llsd_to_test[template_iter->first], - template_iter->second, - value) ) - { - resultant_llsd = LLSD(); - return FALSE; - } - else - { - resultant_llsd[template_iter->first] = value; - } - } - else - { - //test llsd doesn't have it...take the - //template as default value - resultant_llsd[template_iter->first] = - template_iter->second; - } - } - } - else - { - //of same type...take the test llsd's value - resultant_llsd = llsd_to_test; - } - - - return TRUE; + if ( + llsd_to_test.isUndefined() && + template_llsd.isDefined() ) + { + resultant_llsd = template_llsd; + return TRUE; + } + else if ( llsd_to_test.type() != template_llsd.type() ) + { + resultant_llsd = LLSD(); + return FALSE; + } + + if ( llsd_to_test.isArray() ) + { + //they are both arrays + //we loop over all the items in the template + //verifying that the to_test has a subset (in the same order) + //any shortcoming in the testing_llsd are just taken + //to be the rest of the template + LLSD data; + LLSD::array_const_iterator test_iter; + LLSD::array_const_iterator template_iter; + + resultant_llsd = LLSD::emptyArray(); + test_iter = llsd_to_test.beginArray(); + + for ( + template_iter = template_llsd.beginArray(); + (template_iter != template_llsd.endArray() && + test_iter != llsd_to_test.endArray()); + ++template_iter) + { + if ( !compare_llsd_with_template( + *test_iter, + *template_iter, + data) ) + { + resultant_llsd = LLSD(); + return FALSE; + } + else + { + resultant_llsd.append(data); + } + + ++test_iter; + } + + //so either the test or the template ended + //we do another loop now to the end of the template + //grabbing the default values + for (; + template_iter != template_llsd.endArray(); + ++template_iter) + { + resultant_llsd.append(*template_iter); + } + } + else if ( llsd_to_test.isMap() ) + { + //now we loop over the keys of the two maps + //any excess is taken from the template + //excess is ignored in the test + LLSD value; + LLSD::map_const_iterator template_iter; + + resultant_llsd = LLSD::emptyMap(); + for ( + template_iter = template_llsd.beginMap(); + template_iter != template_llsd.endMap(); + ++template_iter) + { + if ( llsd_to_test.has(template_iter->first) ) + { + //the test LLSD has the same key + if ( !compare_llsd_with_template( + llsd_to_test[template_iter->first], + template_iter->second, + value) ) + { + resultant_llsd = LLSD(); + return FALSE; + } + else + { + resultant_llsd[template_iter->first] = value; + } + } + else + { + //test llsd doesn't have it...take the + //template as default value + resultant_llsd[template_iter->first] = + template_iter->second; + } + } + } + else + { + //of same type...take the test llsd's value + resultant_llsd = llsd_to_test; + } + + + return TRUE; } -// filter_llsd_with_template() is a direct clone (copy-n-paste) of +// filter_llsd_with_template() is a direct clone (copy-n-paste) of // compare_llsd_with_template with the following differences: // (1) bool vs BOOL return types // (2) A map with the key value "*" is a special value and maps any key in the @@ -333,171 +333,171 @@ BOOL compare_llsd_with_template( // for *all* the elements of the test array. If the template array is of // different size, compare_llsd_with_template() semantics apply. bool filter_llsd_with_template( - const LLSD & llsd_to_test, - const LLSD & template_llsd, - LLSD & resultant_llsd) + const LLSD & llsd_to_test, + const LLSD & template_llsd, + LLSD & resultant_llsd) { LL_PROFILE_ZONE_SCOPED - if (llsd_to_test.isUndefined() && template_llsd.isDefined()) - { - resultant_llsd = template_llsd; - return true; - } - else if (llsd_to_test.type() != template_llsd.type()) - { - resultant_llsd = LLSD(); - return false; - } - - if (llsd_to_test.isArray()) - { - //they are both arrays - //we loop over all the items in the template - //verifying that the to_test has a subset (in the same order) - //any shortcoming in the testing_llsd are just taken - //to be the rest of the template - LLSD data; - LLSD::array_const_iterator test_iter; - LLSD::array_const_iterator template_iter; - - resultant_llsd = LLSD::emptyArray(); - test_iter = llsd_to_test.beginArray(); - - if (1 == template_llsd.size()) - { - // If the template has a single item, treat it as - // the template for *all* items in the test LLSD. - template_iter = template_llsd.beginArray(); - - for (; test_iter != llsd_to_test.endArray(); ++test_iter) - { - if (! filter_llsd_with_template(*test_iter, *template_iter, data)) - { - resultant_llsd = LLSD(); - return false; - } - else - { - resultant_llsd.append(data); - } - } - } - else - { - // Traditional compare_llsd_with_template matching - - for (template_iter = template_llsd.beginArray(); - template_iter != template_llsd.endArray() && - test_iter != llsd_to_test.endArray(); - ++template_iter, ++test_iter) - { - if (! filter_llsd_with_template(*test_iter, *template_iter, data)) - { - resultant_llsd = LLSD(); - return false; - } - else - { - resultant_llsd.append(data); - } - } - - //so either the test or the template ended - //we do another loop now to the end of the template - //grabbing the default values - for (; - template_iter != template_llsd.endArray(); - ++template_iter) - { - resultant_llsd.append(*template_iter); - } - } - } - else if (llsd_to_test.isMap()) - { - resultant_llsd = LLSD::emptyMap(); - - //now we loop over the keys of the two maps - //any excess is taken from the template - //excess is ignored in the test - - // Special tag for wildcarded LLSD map key templates - const LLSD::String wildcard_tag("*"); - - const bool template_has_wildcard = template_llsd.has(wildcard_tag); - LLSD wildcard_value; - LLSD value; - - const LLSD::map_const_iterator template_iter_end(template_llsd.endMap()); - for (LLSD::map_const_iterator template_iter(template_llsd.beginMap()); - template_iter_end != template_iter; - ++template_iter) - { - if (wildcard_tag == template_iter->first) - { - wildcard_value = template_iter->second; - } - else if (llsd_to_test.has(template_iter->first)) - { - //the test LLSD has the same key - if (! filter_llsd_with_template(llsd_to_test[template_iter->first], - template_iter->second, - value)) - { - resultant_llsd = LLSD(); - return false; - } - else - { - resultant_llsd[template_iter->first] = value; - } - } - else if (! template_has_wildcard) - { - // test llsd doesn't have it...take the - // template as default value - resultant_llsd[template_iter->first] = template_iter->second; - } - } - if (template_has_wildcard) - { - LLSD sub_value; - LLSD::map_const_iterator test_iter; - - for (test_iter = llsd_to_test.beginMap(); - test_iter != llsd_to_test.endMap(); - ++test_iter) - { - if (resultant_llsd.has(test_iter->first)) - { - // Final value has test key, assume more specific - // template matched and we shouldn't modify it again. - continue; - } - else if (! filter_llsd_with_template(test_iter->second, - wildcard_value, - sub_value)) - { - // Test value doesn't match wildcarded template - resultant_llsd = LLSD(); - return false; - } - else - { - // Test value matches template, add the actuals. - resultant_llsd[test_iter->first] = sub_value; - } - } - } - } - else - { - //of same type...take the test llsd's value - resultant_llsd = llsd_to_test; - } - - return true; + if (llsd_to_test.isUndefined() && template_llsd.isDefined()) + { + resultant_llsd = template_llsd; + return true; + } + else if (llsd_to_test.type() != template_llsd.type()) + { + resultant_llsd = LLSD(); + return false; + } + + if (llsd_to_test.isArray()) + { + //they are both arrays + //we loop over all the items in the template + //verifying that the to_test has a subset (in the same order) + //any shortcoming in the testing_llsd are just taken + //to be the rest of the template + LLSD data; + LLSD::array_const_iterator test_iter; + LLSD::array_const_iterator template_iter; + + resultant_llsd = LLSD::emptyArray(); + test_iter = llsd_to_test.beginArray(); + + if (1 == template_llsd.size()) + { + // If the template has a single item, treat it as + // the template for *all* items in the test LLSD. + template_iter = template_llsd.beginArray(); + + for (; test_iter != llsd_to_test.endArray(); ++test_iter) + { + if (! filter_llsd_with_template(*test_iter, *template_iter, data)) + { + resultant_llsd = LLSD(); + return false; + } + else + { + resultant_llsd.append(data); + } + } + } + else + { + // Traditional compare_llsd_with_template matching + + for (template_iter = template_llsd.beginArray(); + template_iter != template_llsd.endArray() && + test_iter != llsd_to_test.endArray(); + ++template_iter, ++test_iter) + { + if (! filter_llsd_with_template(*test_iter, *template_iter, data)) + { + resultant_llsd = LLSD(); + return false; + } + else + { + resultant_llsd.append(data); + } + } + + //so either the test or the template ended + //we do another loop now to the end of the template + //grabbing the default values + for (; + template_iter != template_llsd.endArray(); + ++template_iter) + { + resultant_llsd.append(*template_iter); + } + } + } + else if (llsd_to_test.isMap()) + { + resultant_llsd = LLSD::emptyMap(); + + //now we loop over the keys of the two maps + //any excess is taken from the template + //excess is ignored in the test + + // Special tag for wildcarded LLSD map key templates + const LLSD::String wildcard_tag("*"); + + const bool template_has_wildcard = template_llsd.has(wildcard_tag); + LLSD wildcard_value; + LLSD value; + + const LLSD::map_const_iterator template_iter_end(template_llsd.endMap()); + for (LLSD::map_const_iterator template_iter(template_llsd.beginMap()); + template_iter_end != template_iter; + ++template_iter) + { + if (wildcard_tag == template_iter->first) + { + wildcard_value = template_iter->second; + } + else if (llsd_to_test.has(template_iter->first)) + { + //the test LLSD has the same key + if (! filter_llsd_with_template(llsd_to_test[template_iter->first], + template_iter->second, + value)) + { + resultant_llsd = LLSD(); + return false; + } + else + { + resultant_llsd[template_iter->first] = value; + } + } + else if (! template_has_wildcard) + { + // test llsd doesn't have it...take the + // template as default value + resultant_llsd[template_iter->first] = template_iter->second; + } + } + if (template_has_wildcard) + { + LLSD sub_value; + LLSD::map_const_iterator test_iter; + + for (test_iter = llsd_to_test.beginMap(); + test_iter != llsd_to_test.endMap(); + ++test_iter) + { + if (resultant_llsd.has(test_iter->first)) + { + // Final value has test key, assume more specific + // template matched and we shouldn't modify it again. + continue; + } + else if (! filter_llsd_with_template(test_iter->second, + wildcard_value, + sub_value)) + { + // Test value doesn't match wildcarded template + resultant_llsd = LLSD(); + return false; + } + else + { + // Test value matches template, add the actuals. + resultant_llsd[test_iter->first] = sub_value; + } + } + } + } + else + { + //of same type...take the test llsd's value + resultant_llsd = llsd_to_test; + } + + return true; } /***************************************************************************** @@ -944,9 +944,9 @@ LLSD drill(const LLSD& blob, const LLSD& path) } // namespace llsd -// Construct a deep partial clone of of an LLSD object. primitive types share +// Construct a deep partial clone of of an LLSD object. primitive types share // references, however maps, arrays and binary objects are duplicated. An optional -// filter may be include to exclude/include keys in a map. +// filter may be include to exclude/include keys in a map. LLSD llsd_clone(LLSD value, LLSD filter) { LL_PROFILE_ZONE_SCOPED diff --git a/indra/llcommon/llsdutil.h b/indra/llcommon/llsdutil.h index fdcc052bd0..aa497c53c7 100644 --- a/indra/llcommon/llsdutil.h +++ b/indra/llcommon/llsdutil.h @@ -1,4 +1,4 @@ -/** +/** * @file llsdutil.h * @author Phoenix * @date 2006-05-24 @@ -7,21 +7,21 @@ * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -73,11 +73,11 @@ LL_COMMON_API std::string ll_stream_notation_sd(const LLSD& sd); //Otherwise, returns true LL_COMMON_API BOOL compare_llsd_with_template( - const LLSD& llsd_to_test, - const LLSD& template_llsd, - LLSD& resultant_llsd); + const LLSD& llsd_to_test, + const LLSD& template_llsd, + LLSD& resultant_llsd); -// filter_llsd_with_template() is a direct clone (copy-n-paste) of +// filter_llsd_with_template() is a direct clone (copy-n-paste) of // compare_llsd_with_template with the following differences: // (1) bool vs BOOL return types // (2) A map with the key value "*" is a special value and maps any key in the @@ -86,9 +86,9 @@ LL_COMMON_API BOOL compare_llsd_with_template( // for *all* the elements of the test array. If the template array is of // different size, compare_llsd_with_template() semantics apply. bool filter_llsd_with_template( - const LLSD & llsd_to_test, - const LLSD & template_llsd, - LLSD & resultant_llsd); + const LLSD & llsd_to_test, + const LLSD & template_llsd, + LLSD & resultant_llsd); /** * Recursively determine whether a given LLSD data block "matches" another @@ -164,12 +164,12 @@ inline bool operator!=(const LLSD& lhs, const LLSD& rhs) // there is no need for casting. template LLSD llsd_copy_array(Input iter, Input end) { - LLSD dest; - for (; iter != end; ++iter) - { - dest.append(*iter); - } - return dest; + LLSD dest; + for (; iter != end; ++iter) + { + dest.append(*iter); + } + return dest; } namespace llsd @@ -526,19 +526,19 @@ private: } // namespace llsd -// Creates a deep clone of an LLSD object. Maps, Arrays and binary objects +// Creates a deep clone of an LLSD object. Maps, Arrays and binary objects // are duplicated, atomic primitives (Boolean, Integer, Real, etc) simply -// use a shared reference. -// Optionally a filter may be specified to control what is duplicated. The +// use a shared reference. +// Optionally a filter may be specified to control what is duplicated. The // map takes the form "keyname/boolean". -// If the value is true the value will be duplicated otherwise it will be skipped +// If the value is true the value will be duplicated otherwise it will be skipped // when encountered in a map. A key name of "*" can be specified as a wild card // and will specify the default behavior. If no wild card is given and the clone // encounters a name not in the filter, that value will be skipped. LLSD llsd_clone(LLSD value, LLSD filter = LLSD()); -// Creates a shallow copy of a map or array. If passed any other type of LLSD -// object it simply returns that value. See llsd_clone for a description of +// Creates a shallow copy of a map or array. If passed any other type of LLSD +// object it simply returns that value. See llsd_clone for a description of // the filter parameter. LLSD llsd_shallow(LLSD value, LLSD filter = LLSD()); @@ -561,7 +561,7 @@ struct hash { typedef LLSD argument_type; typedef std::size_t result_type; - result_type operator()(argument_type const& s) const + result_type operator()(argument_type const& s) const { result_type seed(0); diff --git a/indra/llcommon/llsimplehash.h b/indra/llcommon/llsimplehash.h index 727b4568d8..530d566466 100644 --- a/indra/llcommon/llsimplehash.h +++ b/indra/llcommon/llsimplehash.h @@ -1,24 +1,24 @@ -/** +/** * @file llsimplehash.h * * $LicenseInfo:firstyear=2003&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -32,124 +32,124 @@ template class LLSimpleHashEntry { protected: - HASH_KEY_TYPE mHashKey; - LLSimpleHashEntry* mNextEntry; + HASH_KEY_TYPE mHashKey; + LLSimpleHashEntry* mNextEntry; public: - LLSimpleHashEntry(HASH_KEY_TYPE key) : - mHashKey(key), - mNextEntry(0) - { - } - virtual ~LLSimpleHashEntry() - { - } - HASH_KEY_TYPE getHashKey() const - { - return mHashKey; - } - LLSimpleHashEntry* getNextEntry() const - { - return mNextEntry; - } - void setNextEntry(LLSimpleHashEntry* next) - { - mNextEntry = next; - } + LLSimpleHashEntry(HASH_KEY_TYPE key) : + mHashKey(key), + mNextEntry(0) + { + } + virtual ~LLSimpleHashEntry() + { + } + HASH_KEY_TYPE getHashKey() const + { + return mHashKey; + } + LLSimpleHashEntry* getNextEntry() const + { + return mNextEntry; + } + void setNextEntry(LLSimpleHashEntry* next) + { + mNextEntry = next; + } }; template class LL_COMMON_API LLSimpleHash { public: - LLSimpleHash() - { - llassert(TABLE_SIZE); - llassert((TABLE_SIZE ^ (TABLE_SIZE-1)) == (TABLE_SIZE | (TABLE_SIZE-1))); // power of 2 - memset(mEntryTable, 0, sizeof(mEntryTable)); - } - virtual ~LLSimpleHash() - { - } + LLSimpleHash() + { + llassert(TABLE_SIZE); + llassert((TABLE_SIZE ^ (TABLE_SIZE-1)) == (TABLE_SIZE | (TABLE_SIZE-1))); // power of 2 + memset(mEntryTable, 0, sizeof(mEntryTable)); + } + virtual ~LLSimpleHash() + { + } + + virtual int getIndex(HASH_KEY_TYPE key) + { + return key & (TABLE_SIZE-1); + } + + bool insert(LLSimpleHashEntry* entry) + { + llassert(entry->getNextEntry() == 0); + int index = getIndex(entry->getHashKey()); + entry->setNextEntry(mEntryTable[index]); + mEntryTable[index] = entry; + return true; + } + LLSimpleHashEntry* find(HASH_KEY_TYPE key) + { + int index = getIndex(key); + LLSimpleHashEntry* res = mEntryTable[index]; + while(res && (res->getHashKey() != key)) + { + res = res->getNextEntry(); + } + return res; + } + bool erase(LLSimpleHashEntry* entry) + { + return erase(entry->getHashKey()); + } + bool erase(HASH_KEY_TYPE key) + { + int index = getIndex(key); + LLSimpleHashEntry* prev = 0; + LLSimpleHashEntry* res = mEntryTable[index]; + while(res && (res->getHashKey() != key)) + { + prev = res; + res = res->getNextEntry(); + } + if (res) + { + LLSimpleHashEntry* next = res->getNextEntry(); + if (prev) + { + prev->setNextEntry(next); + } + else + { + mEntryTable[index] = next; + } + return true; + } + else + { + return false; + } + } + // Removes and returns an arbitrary ("first") element from the table + // Used for deleting the entire table. + LLSimpleHashEntry* pop_element() + { + for (int i=0; i* entry = mEntryTable[i]; + if (entry) + { + mEntryTable[i] = entry->getNextEntry(); + return entry; + } + } + return 0; + } + // debugging + LLSimpleHashEntry* get_element_at_index(S32 index) const + { + return mEntryTable[index]; + } + - virtual int getIndex(HASH_KEY_TYPE key) - { - return key & (TABLE_SIZE-1); - } - - bool insert(LLSimpleHashEntry* entry) - { - llassert(entry->getNextEntry() == 0); - int index = getIndex(entry->getHashKey()); - entry->setNextEntry(mEntryTable[index]); - mEntryTable[index] = entry; - return true; - } - LLSimpleHashEntry* find(HASH_KEY_TYPE key) - { - int index = getIndex(key); - LLSimpleHashEntry* res = mEntryTable[index]; - while(res && (res->getHashKey() != key)) - { - res = res->getNextEntry(); - } - return res; - } - bool erase(LLSimpleHashEntry* entry) - { - return erase(entry->getHashKey()); - } - bool erase(HASH_KEY_TYPE key) - { - int index = getIndex(key); - LLSimpleHashEntry* prev = 0; - LLSimpleHashEntry* res = mEntryTable[index]; - while(res && (res->getHashKey() != key)) - { - prev = res; - res = res->getNextEntry(); - } - if (res) - { - LLSimpleHashEntry* next = res->getNextEntry(); - if (prev) - { - prev->setNextEntry(next); - } - else - { - mEntryTable[index] = next; - } - return true; - } - else - { - return false; - } - } - // Removes and returns an arbitrary ("first") element from the table - // Used for deleting the entire table. - LLSimpleHashEntry* pop_element() - { - for (int i=0; i* entry = mEntryTable[i]; - if (entry) - { - mEntryTable[i] = entry->getNextEntry(); - return entry; - } - } - return 0; - } - // debugging - LLSimpleHashEntry* get_element_at_index(S32 index) const - { - return mEntryTable[index]; - } - - private: - LLSimpleHashEntry* mEntryTable[TABLE_SIZE]; + LLSimpleHashEntry* mEntryTable[TABLE_SIZE]; }; #endif // LL_LLSIMPLEHASH_H diff --git a/indra/llcommon/llsingleton.cpp b/indra/llcommon/llsingleton.cpp index 5f1a89670e..d00e703a10 100644 --- a/indra/llcommon/llsingleton.cpp +++ b/indra/llcommon/llsingleton.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llsingleton.cpp * @author Brad Kittenbrink * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -363,7 +363,7 @@ LLSingletonBase::vec_t LLSingletonBase::dep_sort() // should happen basically once: for deleteAll(). typedef LLDependencies SingletonDeps; SingletonDeps sdeps; - // Lock while traversing the master list + // Lock while traversing the master list MasterList::LockedMaster master; for (LLSingletonBase* sp : master.get()) { @@ -455,7 +455,7 @@ std::ostream& operator<<(std::ostream& out, const LLSingletonBase::string_params return out; } -} // anonymous namespace +} // anonymous namespace //static void LLSingletonBase::logwarns(const string_params& args) diff --git a/indra/llcommon/llsingleton.h b/indra/llcommon/llsingleton.h index 64027c16c7..91c05bd5ed 100644 --- a/indra/llcommon/llsingleton.h +++ b/indra/llcommon/llsingleton.h @@ -1,24 +1,24 @@ -/** +/** * @file llsingleton.h * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -841,7 +841,7 @@ private: \ // Relatively unsafe singleton implementation that is much faster // and simpler than LLSingleton, but has no dependency tracking -// or inherent thread safety and requires manual invocation of +// or inherent thread safety and requires manual invocation of // createInstance before first use. template class LLSimpleton diff --git a/indra/llcommon/llsmoothstep.h b/indra/llcommon/llsmoothstep.h index 1f97a3ec89..70686c60e2 100644 --- a/indra/llcommon/llsmoothstep.h +++ b/indra/llcommon/llsmoothstep.h @@ -1,25 +1,25 @@ -/** +/** * @file llsmoothstep.h * @brief Smoothstep - transition from 0 to 1 - function, first and second derivatives all continuous (smooth) * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -31,15 +31,15 @@ template inline LLDATATYPE llsmoothstep(const LLDATATYPE& edge0, const LLDATATYPE& edge1, const LLDATATYPE& value) { if (value < edge0) - return (LLDATATYPE)0; + return (LLDATATYPE)0; - if (value >= edge1) - return (LLDATATYPE)1; + if (value >= edge1) + return (LLDATATYPE)1; - // Scale/bias into [0..1] range - LLDATATYPE scaled_value = (value - edge0) / (edge1 - edge0); + // Scale/bias into [0..1] range + LLDATATYPE scaled_value = (value - edge0) / (edge1 - edge0); - return scaled_value * scaled_value * (3 - 2 * scaled_value); + return scaled_value * scaled_value * (3 - 2 * scaled_value); } #endif // LL_LLSMOOTHSTEP_H diff --git a/indra/llcommon/llstacktrace.cpp b/indra/llcommon/llstacktrace.cpp index 80057bf0f2..1fe7f0f25f 100644 --- a/indra/llcommon/llstacktrace.cpp +++ b/indra/llcommon/llstacktrace.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llstacktrace.cpp * @brief stack tracing functionality * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -50,113 +50,113 @@ static RtlCaptureStackBackTrace_Function* const RtlCaptureStackBackTrace_fn = bool ll_get_stack_trace(std::vector& lines) { - const S32 MAX_STACK_DEPTH = 32; - const S32 STRING_NAME_LENGTH = 200; - const S32 FRAME_SKIP = 2; - static BOOL symbolsLoaded = false; - static BOOL firstCall = true; - - HANDLE hProc = GetCurrentProcess(); - - // load the symbols if they're not loaded - if(!symbolsLoaded && firstCall) - { - symbolsLoaded = SymInitialize(hProc, NULL, true); - firstCall = false; - } - - // if loaded, get the call stack - if(symbolsLoaded) - { - // create the frames to hold the addresses - void* frames[MAX_STACK_DEPTH]; - memset(frames, 0, sizeof(void*)*MAX_STACK_DEPTH); - S32 depth = 0; - - // get the addresses - depth = RtlCaptureStackBackTrace_fn(FRAME_SKIP, MAX_STACK_DEPTH, frames, NULL); - - IMAGEHLP_LINE64 line; - memset(&line, 0, sizeof(IMAGEHLP_LINE64)); - line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); - - // create something to hold address info - PIMAGEHLP_SYMBOL64 pSym; - pSym = (PIMAGEHLP_SYMBOL64)malloc(sizeof(IMAGEHLP_SYMBOL64) + STRING_NAME_LENGTH); - memset(pSym, 0, sizeof(IMAGEHLP_SYMBOL64) + STRING_NAME_LENGTH); - pSym->MaxNameLength = STRING_NAME_LENGTH; - pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64); - - // get address info for each address frame - // and store - for(S32 i=0; i < depth; i++) - { - std::stringstream stack_line; - BOOL ret; - - DWORD64 addr = (DWORD64)frames[i]; - ret = SymGetSymFromAddr64(hProc, addr, 0, pSym); - if(ret) - { - stack_line << pSym->Name << " "; - } - - DWORD dummy; - ret = SymGetLineFromAddr64(hProc, addr, &dummy, &line); - if(ret) - { - std::string file_name = line.FileName; - std::string::size_type index = file_name.rfind("\\"); - stack_line << file_name.substr(index + 1, file_name.size()) << ":" << line.LineNumber; - } - - lines.push_back(stack_line.str()); - } - - free(pSym); - - // TODO: figure out a way to cleanup symbol loading - // Not hugely necessary, however. - //SymCleanup(hProc); - return true; - } - else - { - lines.push_back("Stack Trace Failed. PDB symbol info not loaded"); - } - - return false; + const S32 MAX_STACK_DEPTH = 32; + const S32 STRING_NAME_LENGTH = 200; + const S32 FRAME_SKIP = 2; + static BOOL symbolsLoaded = false; + static BOOL firstCall = true; + + HANDLE hProc = GetCurrentProcess(); + + // load the symbols if they're not loaded + if(!symbolsLoaded && firstCall) + { + symbolsLoaded = SymInitialize(hProc, NULL, true); + firstCall = false; + } + + // if loaded, get the call stack + if(symbolsLoaded) + { + // create the frames to hold the addresses + void* frames[MAX_STACK_DEPTH]; + memset(frames, 0, sizeof(void*)*MAX_STACK_DEPTH); + S32 depth = 0; + + // get the addresses + depth = RtlCaptureStackBackTrace_fn(FRAME_SKIP, MAX_STACK_DEPTH, frames, NULL); + + IMAGEHLP_LINE64 line; + memset(&line, 0, sizeof(IMAGEHLP_LINE64)); + line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); + + // create something to hold address info + PIMAGEHLP_SYMBOL64 pSym; + pSym = (PIMAGEHLP_SYMBOL64)malloc(sizeof(IMAGEHLP_SYMBOL64) + STRING_NAME_LENGTH); + memset(pSym, 0, sizeof(IMAGEHLP_SYMBOL64) + STRING_NAME_LENGTH); + pSym->MaxNameLength = STRING_NAME_LENGTH; + pSym->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL64); + + // get address info for each address frame + // and store + for(S32 i=0; i < depth; i++) + { + std::stringstream stack_line; + BOOL ret; + + DWORD64 addr = (DWORD64)frames[i]; + ret = SymGetSymFromAddr64(hProc, addr, 0, pSym); + if(ret) + { + stack_line << pSym->Name << " "; + } + + DWORD dummy; + ret = SymGetLineFromAddr64(hProc, addr, &dummy, &line); + if(ret) + { + std::string file_name = line.FileName; + std::string::size_type index = file_name.rfind("\\"); + stack_line << file_name.substr(index + 1, file_name.size()) << ":" << line.LineNumber; + } + + lines.push_back(stack_line.str()); + } + + free(pSym); + + // TODO: figure out a way to cleanup symbol loading + // Not hugely necessary, however. + //SymCleanup(hProc); + return true; + } + else + { + lines.push_back("Stack Trace Failed. PDB symbol info not loaded"); + } + + return false; } void ll_get_stack_trace_internal(std::vector& lines) { - const S32 MAX_STACK_DEPTH = 100; - const S32 STRING_NAME_LENGTH = 256; + const S32 MAX_STACK_DEPTH = 100; + const S32 STRING_NAME_LENGTH = 256; - HANDLE process = GetCurrentProcess(); - SymInitialize( process, NULL, TRUE ); + HANDLE process = GetCurrentProcess(); + SymInitialize( process, NULL, TRUE ); - void *stack[MAX_STACK_DEPTH]; + void *stack[MAX_STACK_DEPTH]; - unsigned short frames = RtlCaptureStackBackTrace_fn( 0, MAX_STACK_DEPTH, stack, NULL ); - SYMBOL_INFO *symbol = (SYMBOL_INFO*)calloc(sizeof(SYMBOL_INFO) + STRING_NAME_LENGTH * sizeof(char), 1); - symbol->MaxNameLen = STRING_NAME_LENGTH-1; - symbol->SizeOfStruct = sizeof(SYMBOL_INFO); + unsigned short frames = RtlCaptureStackBackTrace_fn( 0, MAX_STACK_DEPTH, stack, NULL ); + SYMBOL_INFO *symbol = (SYMBOL_INFO*)calloc(sizeof(SYMBOL_INFO) + STRING_NAME_LENGTH * sizeof(char), 1); + symbol->MaxNameLen = STRING_NAME_LENGTH-1; + symbol->SizeOfStruct = sizeof(SYMBOL_INFO); - for(unsigned int i = 0; i < frames; i++) - { - SymFromAddr(process, (DWORD64)(stack[i]), 0, symbol); - lines.push_back(symbol->Name); - } + for(unsigned int i = 0; i < frames; i++) + { + SymFromAddr(process, (DWORD64)(stack[i]), 0, symbol); + lines.push_back(symbol->Name); + } - free( symbol ); + free( symbol ); } #else bool ll_get_stack_trace(std::vector& lines) { - return false; + return false; } void ll_get_stack_trace_internal(std::vector& lines) diff --git a/indra/llcommon/llstacktrace.h b/indra/llcommon/llstacktrace.h index 335765386a..693eeced63 100644 --- a/indra/llcommon/llstacktrace.h +++ b/indra/llcommon/llstacktrace.h @@ -1,25 +1,25 @@ -/** +/** * @file llstacktrace.h * @brief stack trace functions * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcommon/llstatenums.h b/indra/llcommon/llstatenums.h index 6515a3e3cb..99f3d3c870 100644 --- a/indra/llcommon/llstatenums.h +++ b/indra/llcommon/llstatenums.h @@ -1,24 +1,24 @@ -/** +/** * @file llstatenums.h * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcommon/llstaticstringtable.h b/indra/llcommon/llstaticstringtable.h index d7e0e8a08d..66ba3487c4 100644 --- a/indra/llcommon/llstaticstringtable.h +++ b/indra/llcommon/llstaticstringtable.h @@ -1,4 +1,4 @@ -/** +/** * @file llstringtable.h * @brief The LLStringTable class provides a _fast_ method for finding * unique copies of strings. @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -36,45 +36,45 @@ class LLStaticHashedString { public: - LLStaticHashedString(const std::string& s) - { - string_hash = makehash(s); - string = s; - } + LLStaticHashedString(const std::string& s) + { + string_hash = makehash(s); + string = s; + } - const std::string& String() const { return string; } - size_t Hash() const { return string_hash; } + const std::string& String() const { return string; } + size_t Hash() const { return string_hash; } - bool operator==(const LLStaticHashedString& b) const { return Hash() == b.Hash(); } + bool operator==(const LLStaticHashedString& b) const { return Hash() == b.Hash(); } protected: - size_t makehash(const std::string& s) - { - size_t len = s.size(); - const char* c = s.c_str(); - size_t hashval = 0; - for (size_t i=0; i class LL_COMMON_API LLStaticStringTable - : public boost::unordered_map< LLStaticHashedString, MappedObject, LLStaticStringHasher > + : public boost::unordered_map< LLStaticHashedString, MappedObject, LLStaticStringHasher > { }; diff --git a/indra/llcommon/llstl.h b/indra/llcommon/llstl.h index 25131291f9..3a6efd7d34 100644 --- a/indra/llcommon/llstl.h +++ b/indra/llcommon/llstl.h @@ -1,25 +1,25 @@ -/** +/** * @file llstl.h * @brief helper object & functions for use with the stl. * * $LicenseInfo:firstyear=2003&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -41,39 +41,39 @@ #include #endif // Use to compare the first element only of a pair -// e.g. typedef std::set, compare_pair > some_pair_set_t; +// e.g. typedef std::set, compare_pair > some_pair_set_t; template struct compare_pair_first { - bool operator()(const std::pair& a, const std::pair& b) const - { - return a.first < b.first; - } + bool operator()(const std::pair& a, const std::pair& b) const + { + return a.first < b.first; + } }; template struct compare_pair_greater { - bool operator()(const std::pair& a, const std::pair& b) const - { - if (!(a.first < b.first)) - return true; - else if (!(b.first < a.first)) - return false; - else - return !(a.second < b.second); - } + bool operator()(const std::pair& a, const std::pair& b) const + { + if (!(a.first < b.first)) + return true; + else if (!(b.first < a.first)) + return false; + else + return !(a.second < b.second); + } }; // Use to compare the contents of two pointers (e.g. std::string*) template struct compare_pointer_contents { - typedef const T* Tptr; - bool operator()(const Tptr& a, const Tptr& b) const - { - return *a < *b; - } + typedef const T* Tptr; + bool operator()(const Tptr& a, const Tptr& b) const + { + return *a < *b; + } }; // DeletePointer is a simple helper for deleting all pointers in a container. @@ -86,40 +86,40 @@ struct compare_pointer_contents struct DeletePointer { - template void operator()(T* ptr) const - { - delete ptr; - } + template void operator()(T* ptr) const + { + delete ptr; + } }; struct DeletePointerArray { - template void operator()(T* ptr) const - { - delete[] ptr; - } + template void operator()(T* ptr) const + { + delete[] ptr; + } }; // DeletePairedPointer is a simple helper for deleting all pointers in a map. // The general form is: // // std::for_each(somemap.begin(), somemap.end(), DeletePairedPointer()); -// somemap.clear(); // Don't leave dangling pointers around +// somemap.clear(); // Don't leave dangling pointers around struct DeletePairedPointer { - template void operator()(T &ptr) const - { - delete ptr.second; - ptr.second = NULL; - } + template void operator()(T &ptr) const + { + delete ptr.second; + ptr.second = NULL; + } }; struct DeletePairedPointerArray { - template void operator()(T &ptr) const - { - delete[] ptr.second; - ptr.second = NULL; - } + template void operator()(T &ptr) const + { + delete[] ptr.second; + ptr.second = NULL; + } }; @@ -144,22 +144,22 @@ struct DeletePairedPointerArray template struct DeletePointerFunctor { - bool operator()(T* ptr) const - { - delete ptr; - return true; - } + bool operator()(T* ptr) const + { + delete ptr; + return true; + } }; // See notes about DeleteArray for why you should consider avoiding this. template struct DeleteArrayFunctor { - bool operator()(T* ptr) const - { - delete[] ptr; - return true; - } + bool operator()(T* ptr) const + { + delete[] ptr; + return true; + } }; // CopyNewPointer is a simple helper which accepts a pointer, and @@ -169,91 +169,91 @@ struct DeleteArrayFunctor struct CopyNewPointer { - template T* operator()(const T* ptr) const - { - return new T(*ptr); - } + template T* operator()(const T* ptr) const + { + return new T(*ptr); + } }; template void delete_and_clear(std::list& list) { - std::for_each(list.begin(), list.end(), DeletePointer()); - list.clear(); + std::for_each(list.begin(), list.end(), DeletePointer()); + list.clear(); } template void delete_and_clear(std::vector& vector) { - std::for_each(vector.begin(), vector.end(), DeletePointer()); - vector.clear(); + std::for_each(vector.begin(), vector.end(), DeletePointer()); + vector.clear(); } template void delete_and_clear(std::set& set) { - std::for_each(set.begin(), set.end(), DeletePointer()); - set.clear(); + std::for_each(set.begin(), set.end(), DeletePointer()); + set.clear(); } template void delete_and_clear(std::map& map) { - std::for_each(map.begin(), map.end(), DeletePairedPointer()); - map.clear(); + std::for_each(map.begin(), map.end(), DeletePairedPointer()); + map.clear(); } template void delete_and_clear(T*& ptr) { - delete ptr; - ptr = NULL; + delete ptr; + ptr = NULL; } template void delete_and_clear_array(T*& ptr) { - delete[] ptr; - ptr = NULL; + delete[] ptr; + ptr = NULL; } // Simple function to help with finding pointers in maps. // For example: -// typedef map_t; +// typedef map_t; // std::map foo; -// foo[18] = "there"; -// foo[2] = "hello"; -// const char* bar = get_ptr_in_map(foo, 2); // bar -> "hello" +// foo[18] = "there"; +// foo[2] = "hello"; +// const char* bar = get_ptr_in_map(foo, 2); // bar -> "hello" // const char* baz = get_ptr_in_map(foo, 3); // baz == NULL template inline T* get_ptr_in_map(const std::map& inmap, const K& key) { - // Typedef here avoids warnings because of new c++ naming rules. - typedef typename std::map::const_iterator map_iter; - map_iter iter = inmap.find(key); - if(iter == inmap.end()) - { - return NULL; - } - else - { - return iter->second; - } + // Typedef here avoids warnings because of new c++ naming rules. + typedef typename std::map::const_iterator map_iter; + map_iter iter = inmap.find(key); + if(iter == inmap.end()) + { + return NULL; + } + else + { + return iter->second; + } }; // helper function which returns true if key is in inmap. template inline bool is_in_map(const std::map& inmap, const K& key) { - if(inmap.find(key) == inmap.end()) - { - return false; - } - else - { - return true; - } + if(inmap.find(key) == inmap.end()) + { + return false; + } + else + { + return true; + } } // Similar to get_ptr_in_map, but for any type with a valid T(0) constructor. @@ -263,17 +263,17 @@ inline bool is_in_map(const std::map& inmap, const K& key) template inline T get_if_there(const std::map& inmap, const K& key, T default_value) { - // Typedef here avoids warnings because of new c++ naming rules. - typedef typename std::map::const_iterator map_iter; - map_iter iter = inmap.find(key); - if(iter == inmap.end()) - { - return default_value; - } - else - { - return iter->second; - } + // Typedef here avoids warnings because of new c++ naming rules. + typedef typename std::map::const_iterator map_iter; + map_iter iter = inmap.find(key); + if(iter == inmap.end()) + { + return default_value; + } + else + { + return iter->second; + } }; // Useful for replacing the removeObj() functionality of LLDynamicArray @@ -288,22 +288,22 @@ inline T get_if_there(const std::map& inmap, const K& key, T default_value) template inline typename std::vector::iterator vector_replace_with_last(std::vector& invec, typename std::vector::iterator iter) { - typename std::vector::iterator last = invec.end(); --last; - if (iter == invec.end()) - { - return iter; - } - else if (iter == last) - { - invec.pop_back(); - return invec.end(); - } - else - { - *iter = *last; - invec.pop_back(); - return iter; - } + typename std::vector::iterator last = invec.end(); --last; + if (iter == invec.end()) + { + return iter; + } + else if (iter == last) + { + invec.pop_back(); + return invec.end(); + } + else + { + *iter = *last; + invec.pop_back(); + return iter; + } }; // Example: @@ -311,55 +311,55 @@ inline typename std::vector::iterator vector_replace_with_last(std::vector template inline bool vector_replace_with_last(std::vector& invec, const T& val) { - typename std::vector::iterator iter = std::find(invec.begin(), invec.end(), val); - if (iter != invec.end()) - { - typename std::vector::iterator last = invec.end(); --last; - *iter = *last; - invec.pop_back(); - return true; - } - return false; + typename std::vector::iterator iter = std::find(invec.begin(), invec.end(), val); + if (iter != invec.end()) + { + typename std::vector::iterator last = invec.end(); --last; + *iter = *last; + invec.pop_back(); + return true; + } + return false; } // Append N elements to the vector and return a pointer to the first new element. template inline T* vector_append(std::vector& invec, S32 N) { - U32 sz = invec.size(); - invec.resize(sz+N); - return &(invec[sz]); + U32 sz = invec.size(); + invec.resize(sz+N); + return &(invec[sz]); } // call function f to n members starting at first. similar to std::for_each template Function ll_for_n(InputIter first, Size n, Function f) { - for ( ; n > 0; --n, ++first) - f(*first); - return f; + for ( ; n > 0; --n, ++first) + f(*first); + return f; } // copy first to result n times, incrementing each as we go template OutputIter ll_copy_n(InputIter first, Size n, OutputIter result) { - for ( ; n > 0; --n, ++result, ++first) - *result = *first; - return result; + for ( ; n > 0; --n, ++result, ++first) + *result = *first; + return result; } // set *result = op(*f) for n elements of f template OutputIter ll_transform_n( - InputIter first, - Size n, - OutputIter result, - UnaryOp op) -{ - for ( ; n > 0; --n, ++result, ++first) - *result = op(*first); - return result; + InputIter first, + Size n, + OutputIter result, + UnaryOp op) +{ + for ( ; n > 0; --n, ++result, ++first) + *result = op(*first); + return result; } @@ -448,7 +448,7 @@ protected: _Operation3 _M_op3; public: ll_binary_compose(const _Operation1& __x, const _Operation2& __y, - const _Operation3& __z) + const _Operation3& __z) : _M_op1(__x), _M_op2(__y), _M_op3(__z) { } template auto @@ -495,17 +495,17 @@ template class llbinder2nd { protected: - _Operation op; - _Arg2 value; + _Operation op; + _Arg2 value; public: - llbinder2nd(const _Operation& __x, - const _Arg2& __y) - : op(__x), value(__y) {} - template - auto - operator()(const _Arg1& __x) const { - return op(__x, value); - } + llbinder2nd(const _Operation& __x, + const _Arg2& __y) + : op(__x), value(__y) {} + template + auto + operator()(const _Arg1& __x) const { + return op(__x, value); + } }; template @@ -544,23 +544,23 @@ bool before(const std::type_info* lhs, const std::type_info* rhs) */ namespace std { - template <> - struct less - { - bool operator()(const std::type_info* lhs, const std::type_info* rhs) const - { - return before(lhs, rhs); - } - }; - - template <> - struct less - { - bool operator()(std::type_info* lhs, std::type_info* rhs) const - { - return before(lhs, rhs); - } - }; + template <> + struct less + { + bool operator()(const std::type_info* lhs, const std::type_info* rhs) const + { + return before(lhs, rhs); + } + }; + + template <> + struct less + { + bool operator()(std::type_info* lhs, std::type_info* rhs) const + { + return before(lhs, rhs); + } + }; } // std diff --git a/indra/llcommon/llstreamqueue.cpp b/indra/llcommon/llstreamqueue.cpp index 1116a2b6a2..981d913749 100644 --- a/indra/llcommon/llstreamqueue.cpp +++ b/indra/llcommon/llstreamqueue.cpp @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2012-01-05 * @brief Implementation for llstreamqueue. - * + * * $LicenseInfo:firstyear=2012&license=viewerlgpl$ * Copyright (c) 2012, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/llstreamqueue.h b/indra/llcommon/llstreamqueue.h index 0726bad175..a09bf4cb4b 100644 --- a/indra/llcommon/llstreamqueue.h +++ b/indra/llcommon/llstreamqueue.h @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2012-01-04 * @brief Definition of LLStreamQueue - * + * * $LicenseInfo:firstyear=2012&license=viewerlgpl$ * Copyright (c) 2012, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/llstreamtools.cpp b/indra/llcommon/llstreamtools.cpp index bc32b6fd9e..1021b08ad1 100644 --- a/indra/llcommon/llstreamtools.cpp +++ b/indra/llcommon/llstreamtools.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llstreamtools.cpp * @brief some helper functions for parsing legacy simstate and asset files. * * $LicenseInfo:firstyear=2005&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -39,275 +39,275 @@ // skips spaces and tabs bool skip_whitespace(std::istream& input_stream) { - int c = input_stream.peek(); - while (('\t' == c || ' ' == c) && input_stream.good()) - { - input_stream.get(); - c = input_stream.peek(); - } - return input_stream.good(); + int c = input_stream.peek(); + while (('\t' == c || ' ' == c) && input_stream.good()) + { + input_stream.get(); + c = input_stream.peek(); + } + return input_stream.good(); } // skips whitespace, newlines, and carriage returns bool skip_emptyspace(std::istream& input_stream) { - int c = input_stream.peek(); - while ( input_stream.good() - && ('\t' == c || ' ' == c || '\n' == c || '\r' == c) ) - { - input_stream.get(); - c = input_stream.peek(); - } - return input_stream.good(); + int c = input_stream.peek(); + while ( input_stream.good() + && ('\t' == c || ' ' == c || '\n' == c || '\r' == c) ) + { + input_stream.get(); + c = input_stream.peek(); + } + return input_stream.good(); } // skips emptyspace and lines that start with a # bool skip_comments_and_emptyspace(std::istream& input_stream) { - while (skip_emptyspace(input_stream)) - { - int c = input_stream.peek(); - if ('#' == c ) - { - while ('\n' != c && input_stream.good()) - { - c = input_stream.get(); - } - } - else - { - break; - } - } - return input_stream.good(); + while (skip_emptyspace(input_stream)) + { + int c = input_stream.peek(); + if ('#' == c ) + { + while ('\n' != c && input_stream.good()) + { + c = input_stream.get(); + } + } + else + { + break; + } + } + return input_stream.good(); } bool skip_line(std::istream& input_stream) { - int c; - do - { - c = input_stream.get(); - } while ('\n' != c && input_stream.good()); - return input_stream.good(); + int c; + do + { + c = input_stream.get(); + } while ('\n' != c && input_stream.good()); + return input_stream.good(); } bool skip_to_next_word(std::istream& input_stream) { - int c = input_stream.peek(); - while ( input_stream.good() - && ( (c >= 'a' && c <= 'z') - || (c >= 'A' && c <= 'Z') - || (c >= '0' && c <= '9') - || '_' == c ) ) - { - input_stream.get(); - c = input_stream.peek(); - } - while ( input_stream.good() - && !( (c >= 'a' && c <= 'z') - || (c >= 'A' && c <= 'Z') - || (c >= '0' && c <= '9') - || '_' == c ) ) - { - input_stream.get(); - c = input_stream.peek(); - } - return input_stream.good(); + int c = input_stream.peek(); + while ( input_stream.good() + && ( (c >= 'a' && c <= 'z') + || (c >= 'A' && c <= 'Z') + || (c >= '0' && c <= '9') + || '_' == c ) ) + { + input_stream.get(); + c = input_stream.peek(); + } + while ( input_stream.good() + && !( (c >= 'a' && c <= 'z') + || (c >= 'A' && c <= 'Z') + || (c >= '0' && c <= '9') + || '_' == c ) ) + { + input_stream.get(); + c = input_stream.peek(); + } + return input_stream.good(); } bool skip_to_end_of_next_keyword(const char* keyword, std::istream& input_stream) { - auto key_length = strlen(keyword); /*Flawfinder: ignore*/ - if (0 == key_length) - { - return false; - } - while (input_stream.good()) - { - skip_emptyspace(input_stream); - int c = input_stream.get(); - if (keyword[0] != c) - { - skip_line(input_stream); - } - else - { - int key_index = 1; - while ( key_index < key_length - && keyword[key_index - 1] == c - && input_stream.good()) - { - key_index++; - c = input_stream.get(); - } - - if (key_index == key_length - && keyword[key_index-1] == c) - { - c = input_stream.peek(); - if (' ' == c || '\t' == c || '\r' == c || '\n' == c) - { - return true; - } - else - { - skip_line(input_stream); - } - } - else - { - skip_line(input_stream); - } - } - } - return false; + auto key_length = strlen(keyword); /*Flawfinder: ignore*/ + if (0 == key_length) + { + return false; + } + while (input_stream.good()) + { + skip_emptyspace(input_stream); + int c = input_stream.get(); + if (keyword[0] != c) + { + skip_line(input_stream); + } + else + { + int key_index = 1; + while ( key_index < key_length + && keyword[key_index - 1] == c + && input_stream.good()) + { + key_index++; + c = input_stream.get(); + } + + if (key_index == key_length + && keyword[key_index-1] == c) + { + c = input_stream.peek(); + if (' ' == c || '\t' == c || '\r' == c || '\n' == c) + { + return true; + } + else + { + skip_line(input_stream); + } + } + else + { + skip_line(input_stream); + } + } + } + return false; } /* skip_to_start_of_next_keyword() is disabled -- might tickle corruption bug in windows iostream bool skip_to_start_of_next_keyword(const char* keyword, std::istream& input_stream) { - int key_length = strlen(keyword); - if (0 == key_length) - { - return false; - } - while (input_stream.good()) - { - skip_emptyspace(input_stream); - int c = input_stream.get(); - if (keyword[0] != c) - { - skip_line(input_stream); - } - else - { - int key_index = 1; - while ( key_index < key_length - && keyword[key_index - 1] == c - && input_stream.good()) - { - key_index++; - c = input_stream.get(); - } - - if (key_index == key_length - && keyword[key_index-1] == c) - { - c = input_stream.peek(); - if (' ' == c || '\t' == c || '\r' == c || '\n' == c) - { - // put the keyword back onto the stream - for (int index = key_length - 1; index >= 0; index--) - { - input_stream.putback(keyword[index]); - } - return true; - } - else - { - skip_line(input_stream); - break; - } - } - else - { - skip_line(input_stream); - } - } - } - return false; + int key_length = strlen(keyword); + if (0 == key_length) + { + return false; + } + while (input_stream.good()) + { + skip_emptyspace(input_stream); + int c = input_stream.get(); + if (keyword[0] != c) + { + skip_line(input_stream); + } + else + { + int key_index = 1; + while ( key_index < key_length + && keyword[key_index - 1] == c + && input_stream.good()) + { + key_index++; + c = input_stream.get(); + } + + if (key_index == key_length + && keyword[key_index-1] == c) + { + c = input_stream.peek(); + if (' ' == c || '\t' == c || '\r' == c || '\n' == c) + { + // put the keyword back onto the stream + for (int index = key_length - 1; index >= 0; index--) + { + input_stream.putback(keyword[index]); + } + return true; + } + else + { + skip_line(input_stream); + break; + } + } + else + { + skip_line(input_stream); + } + } + } + return false; } */ bool get_word(std::string& output_string, std::istream& input_stream) { - skip_emptyspace(input_stream); - int c = input_stream.peek(); - while ( !isspace(c) - && '\n' != c - && '\r' != c - && input_stream.good() ) - { - output_string += c; - input_stream.get(); - c = input_stream.peek(); - } - return input_stream.good(); + skip_emptyspace(input_stream); + int c = input_stream.peek(); + while ( !isspace(c) + && '\n' != c + && '\r' != c + && input_stream.good() ) + { + output_string += c; + input_stream.get(); + c = input_stream.peek(); + } + return input_stream.good(); } bool get_word(std::string& output_string, std::istream& input_stream, int n) { - skip_emptyspace(input_stream); - int char_count = 0; - int c = input_stream.peek(); - while (!isspace(c) - && '\n' != c - && '\r' != c - && input_stream.good() - && char_count < n) - { - char_count++; - output_string += c; - input_stream.get(); - c = input_stream.peek(); - } - return input_stream.good(); + skip_emptyspace(input_stream); + int char_count = 0; + int c = input_stream.peek(); + while (!isspace(c) + && '\n' != c + && '\r' != c + && input_stream.good() + && char_count < n) + { + char_count++; + output_string += c; + input_stream.get(); + c = input_stream.peek(); + } + return input_stream.good(); } // get everything up to and including the next newline bool get_line(std::string& output_string, std::istream& input_stream) { - output_string.clear(); - int c = input_stream.get(); - while (input_stream.good()) - { - output_string += c; - if ('\n' == c) - { - break; - } - c = input_stream.get(); - } - return input_stream.good(); + output_string.clear(); + int c = input_stream.get(); + while (input_stream.good()) + { + output_string += c; + if ('\n' == c) + { + break; + } + c = input_stream.get(); + } + return input_stream.good(); } // get everything up to and including the next newline -// up to the next n characters. +// up to the next n characters. // add a newline on the end if bail before actual line ending bool get_line(std::string& output_string, std::istream& input_stream, int n) { - output_string.clear(); - int char_count = 0; - int c = input_stream.get(); - while (input_stream.good() && char_count < n) - { - char_count++; - output_string += c; - if ('\n' == c) - { - break; - } - if (char_count >= n) - { - output_string.append("\n"); - break; - } - c = input_stream.get(); - } - return input_stream.good(); + output_string.clear(); + int char_count = 0; + int c = input_stream.get(); + while (input_stream.good() && char_count < n) + { + char_count++; + output_string += c; + if ('\n' == c) + { + break; + } + if (char_count >= n) + { + output_string.append("\n"); + break; + } + c = input_stream.get(); + } + return input_stream.good(); } /* disabled -- might tickle bug in windows iostream // backs up the input_stream by line_size + 1 characters bool unget_line(const std::string& line, std::istream& input_stream) { - input_stream.putback('\n'); // unget the newline - for (int line_index = line.size()-1; line_index >= 0; line_index--) - { - input_stream.putback(line[line_index]); - } - return input_stream.good(); + input_stream.putback('\n'); // unget the newline + for (int line_index = line.size()-1; line_index >= 0; line_index--) + { + input_stream.putback(line[line_index]); + } + return input_stream.good(); } */ @@ -315,14 +315,14 @@ bool unget_line(const std::string& line, std::istream& input_stream) // returns true if removed last char bool remove_last_char(char c, std::string& line) { - auto line_size = line.size(); - if (line_size > 1 - && c == line[line_size - 1]) - { - line.replace(line_size - 1, 1, ""); - return true; - } - return false; + auto line_size = line.size(); + if (line_size > 1 + && c == line[line_size - 1]) + { + line.replace(line_size - 1, 1, ""); + return true; + } + return false; } // replaces escaped characters with the correct characters from left to right @@ -330,23 +330,23 @@ bool remove_last_char(char c, std::string& line) // "\\n" ---> '\n' (backslash n becomes carriage return) void unescape_string(std::string& line) { - auto line_size = line.size(); - for (size_t index = 0; line_size >= 1 && index < line_size - 1; ++index) - { - if ('\\' == line[index]) - { - if ('\\' == line[index + 1]) - { - line.replace(index, 2, "\\"); - line_size--; - } - else if ('n' == line[index + 1]) - { - line.replace(index, 2, "\n"); - line_size--; - } - } - } + auto line_size = line.size(); + for (size_t index = 0; line_size >= 1 && index < line_size - 1; ++index) + { + if ('\\' == line[index]) + { + if ('\\' == line[index + 1]) + { + line.replace(index, 2, "\\"); + line_size--; + } + else if ('n' == line[index + 1]) + { + line.replace(index, 2, "\n"); + line_size--; + } + } + } } // replaces unescaped characters with expanded equivalents from left to right @@ -354,164 +354,164 @@ void unescape_string(std::string& line) // '\n' ---> "\\n" (carriage return becomes backslash n) void escape_string(std::string& line) { - auto line_size = line.size(); - for (size_t index = 0; index < line_size; ++index) - { - if ('\\' == line[index]) - { - line.replace(index, 1, "\\\\"); - line_size++; - index++; - } - else if ('\n' == line[index]) - { - line.replace(index, 1, "\\n"); - line_size++; - index++; - } - } + auto line_size = line.size(); + for (size_t index = 0; index < line_size; ++index) + { + if ('\\' == line[index]) + { + line.replace(index, 1, "\\\\"); + line_size++; + index++; + } + else if ('\n' == line[index]) + { + line.replace(index, 1, "\\n"); + line_size++; + index++; + } + } } // removes '\n' characters void replace_newlines_with_whitespace(std::string& line) { - auto line_size = line.size(); - for (size_t index = 0; index < line_size; ++index) - { - if ('\n' == line[index]) - { - line.replace(index, 1, " "); - } - } + auto line_size = line.size(); + for (size_t index = 0; index < line_size; ++index) + { + if ('\n' == line[index]) + { + line.replace(index, 1, " "); + } + } } // erases any double-quote characters in 'line' void remove_double_quotes(std::string& line) { - auto line_size = line.size(); - for (size_t index = 0; index < line_size; ) - { - if ('"' == line[index]) - { - int count = 1; - while (index + count < line_size - && '"' == line[index + count]) - { - count++; - } - line.replace(index, count, ""); - line_size -= count; - } - else - { - index++; - } - } + auto line_size = line.size(); + for (size_t index = 0; index < line_size; ) + { + if ('"' == line[index]) + { + int count = 1; + while (index + count < line_size + && '"' == line[index + count]) + { + count++; + } + line.replace(index, count, ""); + line_size -= count; + } + else + { + index++; + } + } } // the 'keyword' is defined as the first word on a line // the 'value' is everything after the keyword on the same line // starting at the first non-whitespace and ending right before the newline -void get_keyword_and_value(std::string& keyword, - std::string& value, - const std::string& line) +void get_keyword_and_value(std::string& keyword, + std::string& value, + const std::string& line) { - // skip initial whitespace - auto line_size = line.size(); - size_t line_index = 0; - char c; - for ( ; line_index < line_size; ++line_index) - { - c = line[line_index]; - if (!LLStringOps::isSpace(c)) - { - break; - } - } - - // get the keyword - keyword.clear(); - for ( ; line_index < line_size; ++line_index) - { - c = line[line_index]; - if (LLStringOps::isSpace(c) || '\r' == c || '\n' == c) - { - break; - } - keyword += c; - } - - // get the value - value.clear(); - if (keyword.size() > 0 - && '\r' != line[line_index] - && '\n' != line[line_index]) - - { - // discard initial white spaces - while (line_index < line_size - && (' ' == line[line_index] - || '\t' == line[line_index]) ) - { - line_index++; - } - - for ( ; line_index < line_size; ++line_index) - { - c = line[line_index]; - if ('\r' == c || '\n' == c) - { - break; - } - value += c; - } - } + // skip initial whitespace + auto line_size = line.size(); + size_t line_index = 0; + char c; + for ( ; line_index < line_size; ++line_index) + { + c = line[line_index]; + if (!LLStringOps::isSpace(c)) + { + break; + } + } + + // get the keyword + keyword.clear(); + for ( ; line_index < line_size; ++line_index) + { + c = line[line_index]; + if (LLStringOps::isSpace(c) || '\r' == c || '\n' == c) + { + break; + } + keyword += c; + } + + // get the value + value.clear(); + if (keyword.size() > 0 + && '\r' != line[line_index] + && '\n' != line[line_index]) + + { + // discard initial white spaces + while (line_index < line_size + && (' ' == line[line_index] + || '\t' == line[line_index]) ) + { + line_index++; + } + + for ( ; line_index < line_size; ++line_index) + { + c = line[line_index]; + if ('\r' == c || '\n' == c) + { + break; + } + value += c; + } + } } std::streamsize fullread( - std::istream& istr, - char* buf, - std::streamsize requested) + std::istream& istr, + char* buf, + std::streamsize requested) { - std::streamsize got; - std::streamsize total = 0; - - istr.read(buf, requested); /*Flawfinder: ignore*/ - got = istr.gcount(); - total += got; - while(got && total < requested) - { - if(istr.fail()) - { - // If bad is true, not much we can doo -- it implies loss - // of stream integrity. Bail in that case, and otherwise - // clear and attempt to continue. - if(istr.bad()) return total; - istr.clear(); - } - istr.read(buf + total, requested - total); /*Flawfinder: ignore*/ - got = istr.gcount(); - total += got; - } - return total; + std::streamsize got; + std::streamsize total = 0; + + istr.read(buf, requested); /*Flawfinder: ignore*/ + got = istr.gcount(); + total += got; + while(got && total < requested) + { + if(istr.fail()) + { + // If bad is true, not much we can doo -- it implies loss + // of stream integrity. Bail in that case, and otherwise + // clear and attempt to continue. + if(istr.bad()) return total; + istr.clear(); + } + istr.read(buf + total, requested - total); /*Flawfinder: ignore*/ + got = istr.gcount(); + total += got; + } + return total; } std::istream& operator>>(std::istream& str, const char *tocheck) { - char c = '\0'; - const char *p; - p = tocheck; - while (*p && !str.bad()) - { - str.get(c); - if (c != *p) - { - str.setstate(std::ios::failbit); /*Flawfinder: ignore*/ - break; - } - p++; - } - return str; + char c = '\0'; + const char *p; + p = tocheck; + while (*p && !str.bad()) + { + str.get(c); + if (c != *p) + { + str.setstate(std::ios::failbit); /*Flawfinder: ignore*/ + break; + } + p++; + } + return str; } int cat_streambuf::underflow() diff --git a/indra/llcommon/llstreamtools.h b/indra/llcommon/llstreamtools.h index bb7bc20327..599484361b 100644 --- a/indra/llcommon/llstreamtools.h +++ b/indra/llcommon/llstreamtools.h @@ -1,25 +1,25 @@ -/** +/** * @file llstreamtools.h * @brief some helper functions for parsing legacy simstate and asset files. * * $LicenseInfo:firstyear=2005&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -49,11 +49,11 @@ LL_COMMON_API bool skip_line(std::istream& input_stream); // skips to beginning of next non-emptyspace LL_COMMON_API bool skip_to_next_word(std::istream& input_stream); -// skips to character after the end of next keyword +// skips to character after the end of next keyword // a 'keyword' is defined as the first word on a line LL_COMMON_API bool skip_to_end_of_next_keyword(const char* keyword, std::istream& input_stream); -// skip_to_start_of_next_keyword() is disabled -- might tickle corruption bug +// skip_to_start_of_next_keyword() is disabled -- might tickle corruption bug // in windows iostream // skips to beginning of next keyword // a 'keyword' is defined as the first word on a line @@ -65,7 +65,7 @@ LL_COMMON_API bool get_word(std::string& output_string, std::istream& input_stre LL_COMMON_API bool get_line(std::string& output_string, std::istream& input_stream); // characters are pulled out of input_stream (up to a max of 'n') -// and appended to output_string +// and appended to output_string // returns result of input_stream.good() after characters are pulled LL_COMMON_API bool get_word(std::string& output_string, std::istream& input_stream, int n); LL_COMMON_API bool get_line(std::string& output_string, std::istream& input_stream, int n); @@ -81,13 +81,13 @@ LL_COMMON_API bool get_line(std::string& output_string, std::istream& input_stre LL_COMMON_API bool remove_last_char(char c, std::string& line); // replaces escaped characters with the correct characters from left to right -// "\\" ---> '\\' -// "\n" ---> '\n' +// "\\" ---> '\\' +// "\n" ---> '\n' LL_COMMON_API void unescape_string(std::string& line); // replaces unescaped characters with expanded equivalents from left to right -// '\\' ---> "\\" -// '\n' ---> "\n" +// '\\' ---> "\\" +// '\n' ---> "\n" LL_COMMON_API void escape_string(std::string& line); // replaces each '\n' character with ' ' @@ -99,18 +99,18 @@ LL_COMMON_API void remove_double_quotes(std::string& line); // the 'keyword' is defined as the first word on a line // the 'value' is everything after the keyword on the same line // starting at the first non-whitespace and ending right before the newline -LL_COMMON_API void get_keyword_and_value(std::string& keyword, - std::string& value, - const std::string& line); +LL_COMMON_API void get_keyword_and_value(std::string& keyword, + std::string& value, + const std::string& line); // continue to read from the stream until you really can't // read anymore or until we hit the count. Some istream // implimentations have a max that they will read. // Returns the number of bytes read. LL_COMMON_API std::streamsize fullread( - std::istream& istr, - char* buf, - std::streamsize requested); + std::istream& istr, + char* buf, + std::streamsize requested); LL_COMMON_API std::istream& operator>>(std::istream& str, const char *tocheck); diff --git a/indra/llcommon/llstrider.h b/indra/llcommon/llstrider.h index ed9284d2c5..6c76ab8104 100644 --- a/indra/llcommon/llstrider.h +++ b/indra/llcommon/llstrider.h @@ -1,24 +1,24 @@ -/** +/** * @file llstrider.h * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -30,38 +30,38 @@ template class LLStrider { - union - { - Object* mObjectp; - U8* mBytep; - }; - U32 mSkip; + union + { + Object* mObjectp; + U8* mBytep; + }; + U32 mSkip; public: - LLStrider() { mObjectp = NULL; mSkip = sizeof(Object); } - ~LLStrider() { } + LLStrider() { mObjectp = NULL; mSkip = sizeof(Object); } + ~LLStrider() { } - const LLStrider& operator = (Object *first) { mObjectp = first; return *this;} - void setStride (S32 skipBytes) { mSkip = (skipBytes ? skipBytes : sizeof(Object));} + const LLStrider& operator = (Object *first) { mObjectp = first; return *this;} + void setStride (S32 skipBytes) { mSkip = (skipBytes ? skipBytes : sizeof(Object));} - LLStrider operator+(const S32& index) - { - LLStrider ret; - ret.mBytep = mBytep + mSkip*index; - ret.mSkip = mSkip; + LLStrider operator+(const S32& index) + { + LLStrider ret; + ret.mBytep = mBytep + mSkip*index; + ret.mSkip = mSkip; - return ret; - } + return ret; + } - void skip(const U32 index) { mBytep += mSkip*index;} - U32 getSkip() const { return mSkip; } - Object* get() { return mObjectp; } - Object* operator->() { return mObjectp; } - Object& operator *() { return *mObjectp; } - Object* operator ++(int) { Object* old = mObjectp; mBytep += mSkip; return old; } - Object* operator +=(int i) { mBytep += mSkip*i; return mObjectp; } + void skip(const U32 index) { mBytep += mSkip*index;} + U32 getSkip() const { return mSkip; } + Object* get() { return mObjectp; } + Object* operator->() { return mObjectp; } + Object& operator *() { return *mObjectp; } + Object* operator ++(int) { Object* old = mObjectp; mBytep += mSkip; return old; } + Object* operator +=(int i) { mBytep += mSkip*i; return mObjectp; } - Object& operator[](U32 index) { return *(Object*)(mBytep + (mSkip * index)); } + Object& operator[](U32 index) { return *(Object*)(mBytep + (mSkip * index)); } }; #endif // LL_LLSTRIDER_H diff --git a/indra/llcommon/llstring.cpp b/indra/llcommon/llstring.cpp index a746cc11ec..a743ae1589 100644 --- a/indra/llcommon/llstring.cpp +++ b/indra/llcommon/llstring.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llstring.cpp * @brief String utility functions and the std::string class. * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -40,85 +40,85 @@ std::string ll_safe_string(const char* in) { - if(in) return std::string(in); - return std::string(); + if(in) return std::string(in); + return std::string(); } std::string ll_safe_string(const char* in, S32 maxlen) { - if(in && maxlen > 0 ) return std::string(in, maxlen); + if(in && maxlen > 0 ) return std::string(in, maxlen); - return std::string(); + return std::string(); } bool is_char_hex(char hex) { - if((hex >= '0') && (hex <= '9')) - { - return true; - } - else if((hex >= 'a') && (hex <='f')) - { - return true; - } - else if((hex >= 'A') && (hex <='F')) - { - return true; - } - return false; // uh - oh, not hex any more... + if((hex >= '0') && (hex <= '9')) + { + return true; + } + else if((hex >= 'a') && (hex <='f')) + { + return true; + } + else if((hex >= 'A') && (hex <='F')) + { + return true; + } + return false; // uh - oh, not hex any more... } U8 hex_as_nybble(char hex) { - if((hex >= '0') && (hex <= '9')) - { - return (U8)(hex - '0'); - } - else if((hex >= 'a') && (hex <='f')) - { - return (U8)(10 + hex - 'a'); - } - else if((hex >= 'A') && (hex <='F')) - { - return (U8)(10 + hex - 'A'); - } - return 0; // uh - oh, not hex any more... + if((hex >= '0') && (hex <= '9')) + { + return (U8)(hex - '0'); + } + else if((hex >= 'a') && (hex <='f')) + { + return (U8)(10 + hex - 'a'); + } + else if((hex >= 'A') && (hex <='F')) + { + return (U8)(10 + hex - 'A'); + } + return 0; // uh - oh, not hex any more... } bool iswindividual(llwchar elem) -{ - U32 cur_char = (U32)elem; - bool result = false; - if (0x2E80<= cur_char && cur_char <= 0x9FFF) - { - result = true; - } - else if (0xAC00<= cur_char && cur_char <= 0xD7A0 ) - { - result = true; - } - else if (0xF900<= cur_char && cur_char <= 0xFA60 ) - { - result = true; - } - return result; +{ + U32 cur_char = (U32)elem; + bool result = false; + if (0x2E80<= cur_char && cur_char <= 0x9FFF) + { + result = true; + } + else if (0xAC00<= cur_char && cur_char <= 0xD7A0 ) + { + result = true; + } + else if (0xF900<= cur_char && cur_char <= 0xFA60 ) + { + result = true; + } + return result; } bool _read_file_into_string(std::string& str, const std::string& filename) { - llifstream ifs(filename.c_str(), llifstream::binary); - if (!ifs.is_open()) - { - LL_INFOS() << "Unable to open file " << filename << LL_ENDL; - return false; - } + llifstream ifs(filename.c_str(), llifstream::binary); + if (!ifs.is_open()) + { + LL_INFOS() << "Unable to open file " << filename << LL_ENDL; + return false; + } - std::ostringstream oss; + std::ostringstream oss; - oss << ifs.rdbuf(); - str = oss.str(); - ifs.close(); - return true; + oss << ifs.rdbuf(); + str = oss.str(); + ifs.close(); + return true; } @@ -131,179 +131,179 @@ bool _read_file_into_string(std::string& str, const std::string& filename) std::ostream& operator<<(std::ostream &s, const LLWString &wstr) { - std::string utf8_str = wstring_to_utf8str(wstr); - s << utf8_str; - return s; + std::string utf8_str = wstring_to_utf8str(wstr); + s << utf8_str; + return s; } std::string rawstr_to_utf8(const std::string& raw) { - LLWString wstr(utf8str_to_wstring(raw)); - return wstring_to_utf8str(wstr); + LLWString wstr(utf8str_to_wstring(raw)); + return wstring_to_utf8str(wstr); } std::ptrdiff_t wchar_to_utf8chars(llwchar in_char, char* outchars) { - U32 cur_char = (U32)in_char; - char* base = outchars; - if (cur_char < 0x80) - { - *outchars++ = (U8)cur_char; - } - else if (cur_char < 0x800) - { - *outchars++ = 0xC0 | (cur_char >> 6); - *outchars++ = 0x80 | (cur_char & 0x3F); - } - else if (cur_char < 0x10000) - { - *outchars++ = 0xE0 | (cur_char >> 12); - *outchars++ = 0x80 | ((cur_char >> 6) & 0x3F); - *outchars++ = 0x80 | (cur_char & 0x3F); - } - else if (cur_char < 0x200000) - { - *outchars++ = 0xF0 | (cur_char >> 18); - *outchars++ = 0x80 | ((cur_char >> 12) & 0x3F); - *outchars++ = 0x80 | ((cur_char >> 6) & 0x3F); - *outchars++ = 0x80 | (cur_char & 0x3F); - } - else if (cur_char < 0x4000000) - { - *outchars++ = 0xF8 | (cur_char >> 24); - *outchars++ = 0x80 | ((cur_char >> 18) & 0x3F); - *outchars++ = 0x80 | ((cur_char >> 12) & 0x3F); - *outchars++ = 0x80 | ((cur_char >> 6) & 0x3F); - *outchars++ = 0x80 | (cur_char & 0x3F); - } - else if (cur_char < 0x80000000) - { - *outchars++ = 0xFC | (cur_char >> 30); - *outchars++ = 0x80 | ((cur_char >> 24) & 0x3F); - *outchars++ = 0x80 | ((cur_char >> 18) & 0x3F); - *outchars++ = 0x80 | ((cur_char >> 12) & 0x3F); - *outchars++ = 0x80 | ((cur_char >> 6) & 0x3F); - *outchars++ = 0x80 | (cur_char & 0x3F); - } - else - { - LL_WARNS() << "Invalid Unicode character " << cur_char << "!" << LL_ENDL; - *outchars++ = LL_UNKNOWN_CHAR; - } - return outchars - base; -} + U32 cur_char = (U32)in_char; + char* base = outchars; + if (cur_char < 0x80) + { + *outchars++ = (U8)cur_char; + } + else if (cur_char < 0x800) + { + *outchars++ = 0xC0 | (cur_char >> 6); + *outchars++ = 0x80 | (cur_char & 0x3F); + } + else if (cur_char < 0x10000) + { + *outchars++ = 0xE0 | (cur_char >> 12); + *outchars++ = 0x80 | ((cur_char >> 6) & 0x3F); + *outchars++ = 0x80 | (cur_char & 0x3F); + } + else if (cur_char < 0x200000) + { + *outchars++ = 0xF0 | (cur_char >> 18); + *outchars++ = 0x80 | ((cur_char >> 12) & 0x3F); + *outchars++ = 0x80 | ((cur_char >> 6) & 0x3F); + *outchars++ = 0x80 | (cur_char & 0x3F); + } + else if (cur_char < 0x4000000) + { + *outchars++ = 0xF8 | (cur_char >> 24); + *outchars++ = 0x80 | ((cur_char >> 18) & 0x3F); + *outchars++ = 0x80 | ((cur_char >> 12) & 0x3F); + *outchars++ = 0x80 | ((cur_char >> 6) & 0x3F); + *outchars++ = 0x80 | (cur_char & 0x3F); + } + else if (cur_char < 0x80000000) + { + *outchars++ = 0xFC | (cur_char >> 30); + *outchars++ = 0x80 | ((cur_char >> 24) & 0x3F); + *outchars++ = 0x80 | ((cur_char >> 18) & 0x3F); + *outchars++ = 0x80 | ((cur_char >> 12) & 0x3F); + *outchars++ = 0x80 | ((cur_char >> 6) & 0x3F); + *outchars++ = 0x80 | (cur_char & 0x3F); + } + else + { + LL_WARNS() << "Invalid Unicode character " << cur_char << "!" << LL_ENDL; + *outchars++ = LL_UNKNOWN_CHAR; + } + return outchars - base; +} auto utf16chars_to_wchar(const U16* inchars, llwchar* outchar) { - const U16* base = inchars; - U16 cur_char = *inchars++; - llwchar char32 = cur_char; - if ((cur_char >= 0xD800) && (cur_char <= 0xDFFF)) - { - // Surrogates - char32 = ((llwchar)(cur_char - 0xD800)) << 10; - cur_char = *inchars++; - char32 += (llwchar)(cur_char - 0xDC00) + 0x0010000UL; - } - else - { - char32 = (llwchar)cur_char; - } - *outchar = char32; - return inchars - base; + const U16* base = inchars; + U16 cur_char = *inchars++; + llwchar char32 = cur_char; + if ((cur_char >= 0xD800) && (cur_char <= 0xDFFF)) + { + // Surrogates + char32 = ((llwchar)(cur_char - 0xD800)) << 10; + cur_char = *inchars++; + char32 += (llwchar)(cur_char - 0xDC00) + 0x0010000UL; + } + else + { + char32 = (llwchar)cur_char; + } + *outchar = char32; + return inchars - base; } llutf16string wstring_to_utf16str(const llwchar* utf32str, size_t len) { - llutf16string out; - - S32 i = 0; - while (i < len) - { - U32 cur_char = utf32str[i]; - if (cur_char > 0xFFFF) - { - out += (0xD7C0 + (cur_char >> 10)); - out += (0xDC00 | (cur_char & 0x3FF)); - } - else - { - out += cur_char; - } - i++; - } - return out; + llutf16string out; + + S32 i = 0; + while (i < len) + { + U32 cur_char = utf32str[i]; + if (cur_char > 0xFFFF) + { + out += (0xD7C0 + (cur_char >> 10)); + out += (0xDC00 | (cur_char & 0x3FF)); + } + else + { + out += cur_char; + } + i++; + } + return out; } llutf16string utf8str_to_utf16str( const char* utf8str, size_t len ) { - LLWString wstr = utf8str_to_wstring ( utf8str, len ); - return wstring_to_utf16str ( wstr ); + LLWString wstr = utf8str_to_wstring ( utf8str, len ); + return wstring_to_utf16str ( wstr ); } LLWString utf16str_to_wstring(const U16* utf16str, size_t len) { - LLWString wout; - if (len == 0) return wout; + LLWString wout; + if (len == 0) return wout; - S32 i = 0; - const U16* chars16 = utf16str; - while (i < len) - { - llwchar cur_char; - i += utf16chars_to_wchar(chars16+i, &cur_char); - wout += cur_char; - } - return wout; + S32 i = 0; + const U16* chars16 = utf16str; + while (i < len) + { + llwchar cur_char; + i += utf16chars_to_wchar(chars16+i, &cur_char); + wout += cur_char; + } + return wout; } // Length in llwchar (UTF-32) of the first len units (16 bits) of the given UTF-16 string. S32 utf16str_wstring_length(const llutf16string &utf16str, const S32 utf16_len) { - S32 surrogate_pairs = 0; - // ... craziness to make gcc happy (llutf16string.c_str() is tweaked on linux): - const U16 *const utf16_chars = &(*(utf16str.begin())); - S32 i = 0; - while (i < utf16_len) - { - const U16 c = utf16_chars[i++]; - if (c >= 0xD800 && c <= 0xDBFF) // See http://en.wikipedia.org/wiki/UTF-16 - { // Have first byte of a surrogate pair - if (i >= utf16_len) - { - break; - } - const U16 d = utf16_chars[i]; - if (d >= 0xDC00 && d <= 0xDFFF) - { // Have valid second byte of a surrogate pair - surrogate_pairs++; - i++; - } - } - } - return utf16_len - surrogate_pairs; + S32 surrogate_pairs = 0; + // ... craziness to make gcc happy (llutf16string.c_str() is tweaked on linux): + const U16 *const utf16_chars = &(*(utf16str.begin())); + S32 i = 0; + while (i < utf16_len) + { + const U16 c = utf16_chars[i++]; + if (c >= 0xD800 && c <= 0xDBFF) // See http://en.wikipedia.org/wiki/UTF-16 + { // Have first byte of a surrogate pair + if (i >= utf16_len) + { + break; + } + const U16 d = utf16_chars[i]; + if (d >= 0xDC00 && d <= 0xDFFF) + { // Have valid second byte of a surrogate pair + surrogate_pairs++; + i++; + } + } + } + return utf16_len - surrogate_pairs; } // Length in utf16string (UTF-16) of wlen wchars beginning at woffset. S32 wstring_utf16_length(const LLWString &wstr, const S32 woffset, const S32 wlen) { - const S32 end = llmin((S32)wstr.length(), woffset + wlen); - if (end < woffset) - { - return 0; - } - else - { - S32 length = end - woffset; - for (S32 i = woffset; i < end; i++) - { - if (wstr[i] >= 0x10000) - { - length++; - } - } - return length; - } + const S32 end = llmin((S32)wstr.length(), woffset + wlen); + if (end < woffset) + { + return 0; + } + else + { + S32 length = end - woffset; + for (S32 i = woffset; i < end; i++) + { + if (wstr[i] >= 0x10000) + { + length++; + } + } + return length; + } } // Given a wstring and an offset in it, returns the length as wstring (i.e., @@ -311,56 +311,56 @@ S32 wstring_utf16_length(const LLWString &wstr, const S32 woffset, const S32 wle // and whose equivalent utf-16 string does not exceeds the given utf16_length. S32 wstring_wstring_length_from_utf16_length(const LLWString & wstr, const S32 woffset, const S32 utf16_length, BOOL *unaligned) { - const auto end = wstr.length(); - BOOL u = FALSE; - S32 n = woffset + utf16_length; - S32 i = woffset; - while (i < end) - { - if (wstr[i] >= 0x10000) - { - --n; - } - if (i >= n) - { - u = (i > n); - break; - } - i++; - } - if (unaligned) - { - *unaligned = u; - } - return i - woffset; + const auto end = wstr.length(); + BOOL u = FALSE; + S32 n = woffset + utf16_length; + S32 i = woffset; + while (i < end) + { + if (wstr[i] >= 0x10000) + { + --n; + } + if (i >= n) + { + u = (i > n); + break; + } + i++; + } + if (unaligned) + { + *unaligned = u; + } + return i - woffset; } S32 wchar_utf8_length(const llwchar wc) { - if (wc < 0x80) - { - return 1; - } - else if (wc < 0x800) - { - return 2; - } - else if (wc < 0x10000) - { - return 3; - } - else if (wc < 0x200000) - { - return 4; - } - else if (wc < 0x4000000) - { - return 5; - } - else - { - return 6; - } + if (wc < 0x80) + { + return 1; + } + else if (wc < 0x800) + { + return 2; + } + else if (wc < 0x10000) + { + return 3; + } + else if (wc < 0x200000) + { + return 4; + } + else if (wc < 0x4000000) + { + return 5; + } + else + { + return 6; + } } std::string wchar_utf8_preview(const llwchar wc) @@ -390,179 +390,179 @@ std::string wchar_utf8_preview(const llwchar wc) S32 wstring_utf8_length(const LLWString& wstr) { - S32 len = 0; - for (S32 i = 0; i < (S32)wstr.length(); i++) - { - len += wchar_utf8_length(wstr[i]); - } - return len; + S32 len = 0; + for (S32 i = 0; i < (S32)wstr.length(); i++) + { + len += wchar_utf8_length(wstr[i]); + } + return len; } LLWString utf8str_to_wstring(const char* utf8str, size_t len) { - LLWString wout; - - S32 i = 0; - while (i < len) - { - llwchar unichar; - U8 cur_char = utf8str[i]; - - if (cur_char < 0x80) - { - // Ascii character, just add it - unichar = cur_char; - } - else - { - S32 cont_bytes = 0; - if ((cur_char >> 5) == 0x6) // Two byte UTF8 -> 1 UTF32 - { - unichar = (0x1F&cur_char); - cont_bytes = 1; - } - else if ((cur_char >> 4) == 0xe) // Three byte UTF8 -> 1 UTF32 - { - unichar = (0x0F&cur_char); - cont_bytes = 2; - } - else if ((cur_char >> 3) == 0x1e) // Four byte UTF8 -> 1 UTF32 - { - unichar = (0x07&cur_char); - cont_bytes = 3; - } - else if ((cur_char >> 2) == 0x3e) // Five byte UTF8 -> 1 UTF32 - { - unichar = (0x03&cur_char); - cont_bytes = 4; - } - else if ((cur_char >> 1) == 0x7e) // Six byte UTF8 -> 1 UTF32 - { - unichar = (0x01&cur_char); - cont_bytes = 5; - } - else - { - wout += LL_UNKNOWN_CHAR; - ++i; - continue; - } - - // Check that this character doesn't go past the end of the string - auto end = (len < (i + cont_bytes)) ? len : (i + cont_bytes); - do - { - ++i; - - cur_char = utf8str[i]; - if ( (cur_char >> 6) == 0x2 ) - { - unichar <<= 6; - unichar += (0x3F&cur_char); - } - else - { - // Malformed sequence - roll back to look at this as a new char - unichar = LL_UNKNOWN_CHAR; - --i; - break; - } - } while(i < end); - - // Handle overlong characters and NULL characters - if ( ((cont_bytes == 1) && (unichar < 0x80)) - || ((cont_bytes == 2) && (unichar < 0x800)) - || ((cont_bytes == 3) && (unichar < 0x10000)) - || ((cont_bytes == 4) && (unichar < 0x200000)) - || ((cont_bytes == 5) && (unichar < 0x4000000)) ) - { - unichar = LL_UNKNOWN_CHAR; - } - } - - wout += unichar; - ++i; - } - return wout; + LLWString wout; + + S32 i = 0; + while (i < len) + { + llwchar unichar; + U8 cur_char = utf8str[i]; + + if (cur_char < 0x80) + { + // Ascii character, just add it + unichar = cur_char; + } + else + { + S32 cont_bytes = 0; + if ((cur_char >> 5) == 0x6) // Two byte UTF8 -> 1 UTF32 + { + unichar = (0x1F&cur_char); + cont_bytes = 1; + } + else if ((cur_char >> 4) == 0xe) // Three byte UTF8 -> 1 UTF32 + { + unichar = (0x0F&cur_char); + cont_bytes = 2; + } + else if ((cur_char >> 3) == 0x1e) // Four byte UTF8 -> 1 UTF32 + { + unichar = (0x07&cur_char); + cont_bytes = 3; + } + else if ((cur_char >> 2) == 0x3e) // Five byte UTF8 -> 1 UTF32 + { + unichar = (0x03&cur_char); + cont_bytes = 4; + } + else if ((cur_char >> 1) == 0x7e) // Six byte UTF8 -> 1 UTF32 + { + unichar = (0x01&cur_char); + cont_bytes = 5; + } + else + { + wout += LL_UNKNOWN_CHAR; + ++i; + continue; + } + + // Check that this character doesn't go past the end of the string + auto end = (len < (i + cont_bytes)) ? len : (i + cont_bytes); + do + { + ++i; + + cur_char = utf8str[i]; + if ( (cur_char >> 6) == 0x2 ) + { + unichar <<= 6; + unichar += (0x3F&cur_char); + } + else + { + // Malformed sequence - roll back to look at this as a new char + unichar = LL_UNKNOWN_CHAR; + --i; + break; + } + } while(i < end); + + // Handle overlong characters and NULL characters + if ( ((cont_bytes == 1) && (unichar < 0x80)) + || ((cont_bytes == 2) && (unichar < 0x800)) + || ((cont_bytes == 3) && (unichar < 0x10000)) + || ((cont_bytes == 4) && (unichar < 0x200000)) + || ((cont_bytes == 5) && (unichar < 0x4000000)) ) + { + unichar = LL_UNKNOWN_CHAR; + } + } + + wout += unichar; + ++i; + } + return wout; } std::string wstring_to_utf8str(const llwchar* utf32str, size_t len) { - std::string out; + std::string out; - S32 i = 0; - while (i < len) - { - char tchars[8]; /* Flawfinder: ignore */ - auto n = wchar_to_utf8chars(utf32str[i], tchars); - tchars[n] = 0; - out += tchars; - i++; - } - return out; + S32 i = 0; + while (i < len) + { + char tchars[8]; /* Flawfinder: ignore */ + auto n = wchar_to_utf8chars(utf32str[i], tchars); + tchars[n] = 0; + out += tchars; + i++; + } + return out; } std::string utf16str_to_utf8str(const U16* utf16str, size_t len) { - return wstring_to_utf8str(utf16str_to_wstring(utf16str, len)); + return wstring_to_utf8str(utf16str_to_wstring(utf16str, len)); } std::string utf8str_trim(const std::string& utf8str) { - LLWString wstr = utf8str_to_wstring(utf8str); - LLWStringUtil::trim(wstr); - return wstring_to_utf8str(wstr); + LLWString wstr = utf8str_to_wstring(utf8str); + LLWStringUtil::trim(wstr); + return wstring_to_utf8str(wstr); } std::string utf8str_tolower(const std::string& utf8str) { - LLWString out_str = utf8str_to_wstring(utf8str); - LLWStringUtil::toLower(out_str); - return wstring_to_utf8str(out_str); + LLWString out_str = utf8str_to_wstring(utf8str); + LLWStringUtil::toLower(out_str); + return wstring_to_utf8str(out_str); } S32 utf8str_compare_insensitive(const std::string& lhs, const std::string& rhs) { - LLWString wlhs = utf8str_to_wstring(lhs); - LLWString wrhs = utf8str_to_wstring(rhs); - return LLWStringUtil::compareInsensitive(wlhs, wrhs); + LLWString wlhs = utf8str_to_wstring(lhs); + LLWString wrhs = utf8str_to_wstring(rhs); + return LLWStringUtil::compareInsensitive(wlhs, wrhs); } std::string utf8str_truncate(const std::string& utf8str, const S32 max_len) { - if (0 == max_len) - { - return std::string(); - } - if ((S32)utf8str.length() <= max_len) - { - return utf8str; - } - else - { - S32 cur_char = max_len; - - // If we're ASCII, we don't need to do anything - if ((U8)utf8str[cur_char] > 0x7f) - { - // If first two bits are (10), it's the tail end of a multibyte char. We need to shift back - // to the first character - while (0x80 == (0xc0 & utf8str[cur_char])) - { - cur_char--; - // Keep moving forward until we hit the first char; - if (cur_char == 0) - { - // Make sure we don't trash memory if we've got a bogus string. - break; - } - } - } - // The byte index we're on is one we want to get rid of, so we only want to copy up to (cur_char-1) chars - return utf8str.substr(0, cur_char); - } + if (0 == max_len) + { + return std::string(); + } + if ((S32)utf8str.length() <= max_len) + { + return utf8str; + } + else + { + S32 cur_char = max_len; + + // If we're ASCII, we don't need to do anything + if ((U8)utf8str[cur_char] > 0x7f) + { + // If first two bits are (10), it's the tail end of a multibyte char. We need to shift back + // to the first character + while (0x80 == (0xc0 & utf8str[cur_char])) + { + cur_char--; + // Keep moving forward until we hit the first char; + if (cur_char == 0) + { + // Make sure we don't trash memory if we've got a bogus string. + break; + } + } + } + // The byte index we're on is one we want to get rid of, so we only want to copy up to (cur_char-1) chars + return utf8str.substr(0, cur_char); + } } std::string utf8str_symbol_truncate(const std::string& utf8str, const S32 symbol_len) @@ -593,56 +593,56 @@ std::string utf8str_symbol_truncate(const std::string& utf8str, const S32 symbol } std::string utf8str_substChar( - const std::string& utf8str, - const llwchar target_char, - const llwchar replace_char) -{ - LLWString wstr = utf8str_to_wstring(utf8str); - LLWStringUtil::replaceChar(wstr, target_char, replace_char); - //wstr = wstring_substChar(wstr, target_char, replace_char); - return wstring_to_utf8str(wstr); + const std::string& utf8str, + const llwchar target_char, + const llwchar replace_char) +{ + LLWString wstr = utf8str_to_wstring(utf8str); + LLWStringUtil::replaceChar(wstr, target_char, replace_char); + //wstr = wstring_substChar(wstr, target_char, replace_char); + return wstring_to_utf8str(wstr); } std::string utf8str_makeASCII(const std::string& utf8str) { - LLWString wstr = utf8str_to_wstring(utf8str); - LLWStringUtil::_makeASCII(wstr); - return wstring_to_utf8str(wstr); + LLWString wstr = utf8str_to_wstring(utf8str); + LLWStringUtil::_makeASCII(wstr); + return wstring_to_utf8str(wstr); } std::string mbcsstring_makeASCII(const std::string& wstr) { - // Replace non-ASCII chars with replace_char - std::string out_str = wstr; - for (S32 i = 0; i < (S32)out_str.length(); i++) - { - if ((U8)out_str[i] > 0x7f) - { - out_str[i] = LL_UNKNOWN_CHAR; - } - } - return out_str; + // Replace non-ASCII chars with replace_char + std::string out_str = wstr; + for (S32 i = 0; i < (S32)out_str.length(); i++) + { + if ((U8)out_str[i] > 0x7f) + { + out_str[i] = LL_UNKNOWN_CHAR; + } + } + return out_str; } std::string utf8str_removeCRLF(const std::string& utf8str) { - if (0 == utf8str.length()) - { - return std::string(); - } - const char CR = 13; - - std::string out; - out.reserve(utf8str.length()); - const S32 len = (S32)utf8str.length(); - for( S32 i = 0; i < len; i++ ) - { - if( utf8str[i] != CR ) - { - out.push_back(utf8str[i]); - } - } - return out; + if (0 == utf8str.length()) + { + return std::string(); + } + const char CR = 13; + + std::string out; + out.reserve(utf8str.length()); + const S32 len = (S32)utf8str.length(); + for( S32 i = 0; i < len; i++ ) + { + if( utf8str[i] != CR ) + { + out.push_back(utf8str[i]); + } + } + return out; } llwchar utf8str_to_wchar(const std::string& utf8str, size_t offset, size_t length) @@ -766,63 +766,63 @@ unsigned int ll_wstring_default_code_page() std::string ll_convert_wide_to_string(const wchar_t* in, size_t len_in, unsigned int code_page) { - std::string out; - if(in) - { - int len_out = WideCharToMultiByte( - code_page, - 0, - in, - len_in, - NULL, - 0, - 0, - 0); - // We will need two more bytes for the double NULL ending - // created in WideCharToMultiByte(). - char* pout = new char [len_out + 2]; - memset(pout, 0, len_out + 2); - if(pout) - { - WideCharToMultiByte( - code_page, - 0, - in, - len_in, - pout, - len_out, - 0, - 0); - out.assign(pout); - delete[] pout; - } - } - return out; + std::string out; + if(in) + { + int len_out = WideCharToMultiByte( + code_page, + 0, + in, + len_in, + NULL, + 0, + 0, + 0); + // We will need two more bytes for the double NULL ending + // created in WideCharToMultiByte(). + char* pout = new char [len_out + 2]; + memset(pout, 0, len_out + 2); + if(pout) + { + WideCharToMultiByte( + code_page, + 0, + in, + len_in, + pout, + len_out, + 0, + 0); + out.assign(pout); + delete[] pout; + } + } + return out; } std::wstring ll_convert_string_to_wide(const char* in, size_t len, unsigned int code_page) { - // From review: - // We can preallocate a wide char buffer that is the same length (in wchar_t elements) as the utf8 input, - // plus one for a null terminator, and be guaranteed to not overflow. + // From review: + // We can preallocate a wide char buffer that is the same length (in wchar_t elements) as the utf8 input, + // plus one for a null terminator, and be guaranteed to not overflow. - // Normally, I'd call that sort of thing premature optimization, - // but we *are* seeing string operations taking a bunch of time, especially when constructing widgets. -// int output_str_len = MultiByteToWideChar(code_page, 0, in.c_str(), in.length(), NULL, 0); + // Normally, I'd call that sort of thing premature optimization, + // but we *are* seeing string operations taking a bunch of time, especially when constructing widgets. +// int output_str_len = MultiByteToWideChar(code_page, 0, in.c_str(), in.length(), NULL, 0); - // reserve an output buffer that will be destroyed on exit, with a place - // to put NULL terminator - std::vector w_out(len + 1); + // reserve an output buffer that will be destroyed on exit, with a place + // to put NULL terminator + std::vector w_out(len + 1); - memset(&w_out[0], 0, w_out.size()); - int real_output_str_len = MultiByteToWideChar(code_page, 0, in, len, - &w_out[0], w_out.size() - 1); + memset(&w_out[0], 0, w_out.size()); + int real_output_str_len = MultiByteToWideChar(code_page, 0, in, len, + &w_out[0], w_out.size() - 1); - //looks like MultiByteToWideChar didn't add null terminator to converted string, see EXT-4858. - w_out[real_output_str_len] = 0; + //looks like MultiByteToWideChar didn't add null terminator to converted string, see EXT-4858. + w_out[real_output_str_len] = 0; - // construct string from our temporary output buffer - return {&w_out[0]}; + // construct string from our temporary output buffer + return {&w_out[0]}; } LLWString ll_convert_wide_to_wstring(const wchar_t* in, size_t len) @@ -846,11 +846,11 @@ std::wstring ll_convert_wstring_to_wide(const llwchar* in, size_t len) std::string ll_convert_string_to_utf8_string(const std::string& in) { - // If you pass code_page, you must also pass length, otherwise the code - // page parameter will be mistaken for length. - auto w_mesg = ll_convert_string_to_wide(in, in.length(), CP_ACP); - // CP_UTF8 is default -- see ll_wstring_default_code_page() above. - return ll_convert_wide_to_string(w_mesg); + // If you pass code_page, you must also pass length, otherwise the code + // page parameter will be mistaken for length. + auto w_mesg = ll_convert_string_to_wide(in, in.length(), CP_ACP); + // CP_UTF8 is default -- see ll_wstring_default_code_page() above. + return ll_convert_wide_to_string(w_mesg); } namespace @@ -973,244 +973,244 @@ std::string LLStringOps::sPM; // static bool LLStringOps::isEmoji(llwchar wch) { - int ublock = ublock_getCode(wch); - switch (ublock) - { - case UBLOCK_GENERAL_PUNCTUATION: - case UBLOCK_LETTERLIKE_SYMBOLS: - case UBLOCK_ARROWS: - case UBLOCK_MISCELLANEOUS_TECHNICAL: - case UBLOCK_ENCLOSED_ALPHANUMERICS: - case UBLOCK_GEOMETRIC_SHAPES: - case UBLOCK_MISCELLANEOUS_SYMBOLS: - case UBLOCK_DINGBATS: - case UBLOCK_CJK_SYMBOLS_AND_PUNCTUATION: - case UBLOCK_ENCLOSED_CJK_LETTERS_AND_MONTHS: - case UBLOCK_MISCELLANEOUS_SYMBOLS_AND_PICTOGRAPHS: - case UBLOCK_EMOTICONS: - case UBLOCK_TRANSPORT_AND_MAP_SYMBOLS: + int ublock = ublock_getCode(wch); + switch (ublock) + { + case UBLOCK_GENERAL_PUNCTUATION: + case UBLOCK_LETTERLIKE_SYMBOLS: + case UBLOCK_ARROWS: + case UBLOCK_MISCELLANEOUS_TECHNICAL: + case UBLOCK_ENCLOSED_ALPHANUMERICS: + case UBLOCK_GEOMETRIC_SHAPES: + case UBLOCK_MISCELLANEOUS_SYMBOLS: + case UBLOCK_DINGBATS: + case UBLOCK_CJK_SYMBOLS_AND_PUNCTUATION: + case UBLOCK_ENCLOSED_CJK_LETTERS_AND_MONTHS: + case UBLOCK_MISCELLANEOUS_SYMBOLS_AND_PICTOGRAPHS: + case UBLOCK_EMOTICONS: + case UBLOCK_TRANSPORT_AND_MAP_SYMBOLS: #if U_ICU_VERSION_MAJOR_NUM > 56 - // Boost uses ICU so we can't update it independently - case UBLOCK_SUPPLEMENTAL_SYMBOLS_AND_PICTOGRAPHS: + // Boost uses ICU so we can't update it independently + case UBLOCK_SUPPLEMENTAL_SYMBOLS_AND_PICTOGRAPHS: #endif // U_ICU_VERSION_MAJOR_NUM > 56 - return true; - default: + return true; + default: #if U_ICU_VERSION_MAJOR_NUM > 56 - return false; + return false; #else - // See https://en.wikipedia.org/wiki/Supplemental_Symbols_and_Pictographs - return wch >= 0x1F900 && wch <= 0x1F9FF; + // See https://en.wikipedia.org/wiki/Supplemental_Symbols_and_Pictographs + return wch >= 0x1F900 && wch <= 0x1F9FF; #endif // U_ICU_VERSION_MAJOR_NUM > 56 - } + } } -S32 LLStringOps::collate(const llwchar* a, const llwchar* b) -{ - #if LL_WINDOWS - // in Windows, wide string functions operator on 16-bit strings, - // not the proper 32 bit wide string - return strcmp(wstring_to_utf8str(LLWString(a)).c_str(), wstring_to_utf8str(LLWString(b)).c_str()); - #else - return wcscoll(a, b); - #endif +S32 LLStringOps::collate(const llwchar* a, const llwchar* b) +{ + #if LL_WINDOWS + // in Windows, wide string functions operator on 16-bit strings, + // not the proper 32 bit wide string + return strcmp(wstring_to_utf8str(LLWString(a)).c_str(), wstring_to_utf8str(LLWString(b)).c_str()); + #else + return wcscoll(a, b); + #endif } void LLStringOps::setupDatetimeInfo (bool daylight) { - time_t nowT, localT, gmtT; - struct tm * tmpT; - - nowT = time (NULL); - - tmpT = gmtime (&nowT); - gmtT = mktime (tmpT); - - tmpT = localtime (&nowT); - localT = mktime (tmpT); - - sLocalTimeOffset = (long) (gmtT - localT); - if (tmpT->tm_isdst) - { - sLocalTimeOffset -= 60 * 60; // 1 hour - } - - sPacificDaylightTime = daylight; - sPacificTimeOffset = (sPacificDaylightTime? 7 : 8 ) * 60 * 60; - - datetimeToCodes["wkday"] = "%a"; // Thu - datetimeToCodes["weekday"] = "%A"; // Thursday - datetimeToCodes["year4"] = "%Y"; // 2009 - datetimeToCodes["year"] = "%Y"; // 2009 - datetimeToCodes["year2"] = "%y"; // 09 - datetimeToCodes["mth"] = "%b"; // Aug - datetimeToCodes["month"] = "%B"; // August - datetimeToCodes["mthnum"] = "%m"; // 08 - datetimeToCodes["day"] = "%d"; // 31 - datetimeToCodes["sday"] = "%-d"; // 9 - datetimeToCodes["hour24"] = "%H"; // 14 - datetimeToCodes["hour"] = "%H"; // 14 - datetimeToCodes["hour12"] = "%I"; // 02 - datetimeToCodes["min"] = "%M"; // 59 - datetimeToCodes["ampm"] = "%p"; // AM - datetimeToCodes["second"] = "%S"; // 59 - datetimeToCodes["timezone"] = "%Z"; // PST + time_t nowT, localT, gmtT; + struct tm * tmpT; + + nowT = time (NULL); + + tmpT = gmtime (&nowT); + gmtT = mktime (tmpT); + + tmpT = localtime (&nowT); + localT = mktime (tmpT); + + sLocalTimeOffset = (long) (gmtT - localT); + if (tmpT->tm_isdst) + { + sLocalTimeOffset -= 60 * 60; // 1 hour + } + + sPacificDaylightTime = daylight; + sPacificTimeOffset = (sPacificDaylightTime? 7 : 8 ) * 60 * 60; + + datetimeToCodes["wkday"] = "%a"; // Thu + datetimeToCodes["weekday"] = "%A"; // Thursday + datetimeToCodes["year4"] = "%Y"; // 2009 + datetimeToCodes["year"] = "%Y"; // 2009 + datetimeToCodes["year2"] = "%y"; // 09 + datetimeToCodes["mth"] = "%b"; // Aug + datetimeToCodes["month"] = "%B"; // August + datetimeToCodes["mthnum"] = "%m"; // 08 + datetimeToCodes["day"] = "%d"; // 31 + datetimeToCodes["sday"] = "%-d"; // 9 + datetimeToCodes["hour24"] = "%H"; // 14 + datetimeToCodes["hour"] = "%H"; // 14 + datetimeToCodes["hour12"] = "%I"; // 02 + datetimeToCodes["min"] = "%M"; // 59 + datetimeToCodes["ampm"] = "%p"; // AM + datetimeToCodes["second"] = "%S"; // 59 + datetimeToCodes["timezone"] = "%Z"; // PST } void tokenizeStringToArray(const std::string& data, std::vector& output) { - output.clear(); - size_t length = data.size(); - - // tokenize it and put it in the array - std::string cur_word; - for(size_t i = 0; i < length; ++i) - { - if(data[i] == ':') - { - output.push_back(cur_word); - cur_word.clear(); - } - else - { - cur_word.append(1, data[i]); - } - } - output.push_back(cur_word); + output.clear(); + size_t length = data.size(); + + // tokenize it and put it in the array + std::string cur_word; + for(size_t i = 0; i < length; ++i) + { + if(data[i] == ':') + { + output.push_back(cur_word); + cur_word.clear(); + } + else + { + cur_word.append(1, data[i]); + } + } + output.push_back(cur_word); } void LLStringOps::setupWeekDaysNames(const std::string& data) { - tokenizeStringToArray(data,sWeekDayList); + tokenizeStringToArray(data,sWeekDayList); } void LLStringOps::setupWeekDaysShortNames(const std::string& data) { - tokenizeStringToArray(data,sWeekDayShortList); + tokenizeStringToArray(data,sWeekDayShortList); } void LLStringOps::setupMonthNames(const std::string& data) { - tokenizeStringToArray(data,sMonthList); + tokenizeStringToArray(data,sMonthList); } void LLStringOps::setupMonthShortNames(const std::string& data) { - tokenizeStringToArray(data,sMonthShortList); + tokenizeStringToArray(data,sMonthShortList); } void LLStringOps::setupDayFormat(const std::string& data) { - sDayFormat = data; + sDayFormat = data; } std::string LLStringOps::getDatetimeCode (std::string key) { - std::map::iterator iter; + std::map::iterator iter; - iter = datetimeToCodes.find (key); - if (iter != datetimeToCodes.end()) - { - return iter->second; - } - else - { - return std::string(""); - } + iter = datetimeToCodes.find (key); + if (iter != datetimeToCodes.end()) + { + return iter->second; + } + else + { + return std::string(""); + } } std::string LLStringOps::getReadableNumber(F64 num) { if (fabs(num)>=1e9) { - return llformat("%.2lfB", num / 1e9); + return llformat("%.2lfB", num / 1e9); } else if (fabs(num)>=1e6) { - return llformat("%.2lfM", num / 1e6); + return llformat("%.2lfM", num / 1e6); } else if (fabs(num)>=1e3) { - return llformat("%.2lfK", num / 1e3); + return llformat("%.2lfK", num / 1e3); } else { - return llformat("%.2lf", num); + return llformat("%.2lf", num); } } namespace LLStringFn { - // NOTE - this restricts output to ascii - void replace_nonprintable_in_ascii(std::basic_string& string, char replacement) - { - const char MIN = 0x20; - std::basic_string::size_type len = string.size(); - for(std::basic_string::size_type ii = 0; ii < len; ++ii) - { - if(string[ii] < MIN) - { - string[ii] = replacement; - } - } - } - - - // NOTE - this restricts output to ascii - void replace_nonprintable_and_pipe_in_ascii(std::basic_string& str, - char replacement) - { - const char MIN = 0x20; - const char PIPE = 0x7c; - std::basic_string::size_type len = str.size(); - for(std::basic_string::size_type ii = 0; ii < len; ++ii) - { - if( (str[ii] < MIN) || (str[ii] == PIPE) ) - { - str[ii] = replacement; - } - } - } - - // 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& instr) - { - std::string output; - 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 - const unsigned char c = (unsigned char)*it; - if ( c >= (unsigned char)0x20 // SPACE - || c == (unsigned char)0x09 // TAB - || c == (unsigned char)0x0a // LINE_FEED - || c == (unsigned char)0x0d ) // CARRIAGE_RETURN - { - output.push_back(c); - } - ++it; - } - return output; - } - - /** - * @brief Replace all control characters (c < 0x20) with replacement in - * string. - */ - void replace_ascii_controlchars(std::basic_string& string, char replacement) - { - const unsigned char MIN = 0x20; - std::basic_string::size_type len = string.size(); - for(std::basic_string::size_type ii = 0; ii < len; ++ii) - { - const unsigned char c = (unsigned char) string[ii]; - if(c < MIN) - { - string[ii] = replacement; - } - } - } + // NOTE - this restricts output to ascii + void replace_nonprintable_in_ascii(std::basic_string& string, char replacement) + { + const char MIN = 0x20; + std::basic_string::size_type len = string.size(); + for(std::basic_string::size_type ii = 0; ii < len; ++ii) + { + if(string[ii] < MIN) + { + string[ii] = replacement; + } + } + } + + + // NOTE - this restricts output to ascii + void replace_nonprintable_and_pipe_in_ascii(std::basic_string& str, + char replacement) + { + const char MIN = 0x20; + const char PIPE = 0x7c; + std::basic_string::size_type len = str.size(); + for(std::basic_string::size_type ii = 0; ii < len; ++ii) + { + if( (str[ii] < MIN) || (str[ii] == PIPE) ) + { + str[ii] = replacement; + } + } + } + + // 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& instr) + { + std::string output; + 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 + const unsigned char c = (unsigned char)*it; + if ( c >= (unsigned char)0x20 // SPACE + || c == (unsigned char)0x09 // TAB + || c == (unsigned char)0x0a // LINE_FEED + || c == (unsigned char)0x0d ) // CARRIAGE_RETURN + { + output.push_back(c); + } + ++it; + } + return output; + } + + /** + * @brief Replace all control characters (c < 0x20) with replacement in + * string. + */ + void replace_ascii_controlchars(std::basic_string& string, char replacement) + { + const unsigned char MIN = 0x20; + std::basic_string::size_type len = string.size(); + for(std::basic_string::size_type ii = 0; ii < len; ++ii) + { + const unsigned char c = (unsigned char) string[ii]; + if(c < MIN) + { + string[ii] = replacement; + } + } + } } //////////////////////////////////////////////////////////// @@ -1220,268 +1220,268 @@ template<> S32 LLStringUtil::format(std::string& s, const format_map_t& substitutions); //static -template<> +template<> void LLStringUtil::getTokens(const std::string& instr, std::vector& tokens, const std::string& delims) { - // Starting at offset 0, scan forward for the next non-delimiter. We're - // done when the only characters left in 'instr' are delimiters. - for (std::string::size_type begIdx, endIdx = 0; - (begIdx = instr.find_first_not_of (delims, endIdx)) != std::string::npos; ) - { - // Found a non-delimiter. After that, find the next delimiter. - endIdx = instr.find_first_of (delims, begIdx); - if (endIdx == std::string::npos) - { - // No more delimiters: this token extends to the end of the string. - endIdx = instr.length(); - } - - // extract the token between begIdx and endIdx; substr() needs length - std::string currToken(instr.substr(begIdx, endIdx - begIdx)); - LLStringUtil::trim (currToken); - tokens.push_back(currToken); - // next scan past delimiters starts at endIdx - } -} - -template<> + // Starting at offset 0, scan forward for the next non-delimiter. We're + // done when the only characters left in 'instr' are delimiters. + for (std::string::size_type begIdx, endIdx = 0; + (begIdx = instr.find_first_not_of (delims, endIdx)) != std::string::npos; ) + { + // Found a non-delimiter. After that, find the next delimiter. + endIdx = instr.find_first_of (delims, begIdx); + if (endIdx == std::string::npos) + { + // No more delimiters: this token extends to the end of the string. + endIdx = instr.length(); + } + + // extract the token between begIdx and endIdx; substr() needs length + std::string currToken(instr.substr(begIdx, endIdx - begIdx)); + LLStringUtil::trim (currToken); + tokens.push_back(currToken); + // next scan past delimiters starts at endIdx + } +} + +template<> LLStringUtil::size_type LLStringUtil::getSubstitution(const std::string& instr, size_type& start, std::vector& tokens) { - const std::string delims (","); - - // Find the first [ - size_type pos1 = instr.find('[', start); - if (pos1 == std::string::npos) - return std::string::npos; - - //Find the first ] after the initial [ - size_type pos2 = instr.find(']', pos1); - if (pos2 == std::string::npos) - return std::string::npos; - - // Find the last [ before ] in case of nested [[]] - 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; + const std::string delims (","); + + // Find the first [ + size_type pos1 = instr.find('[', start); + if (pos1 == std::string::npos) + return std::string::npos; + + //Find the first ] after the initial [ + size_type pos2 = instr.find(']', pos1); + if (pos2 == std::string::npos) + return std::string::npos; + + // Find the last [ before ] in case of nested [[]] + 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<> +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; + // 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<> +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; + // 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::setLocale(std::string inLocale) { - sLocale = inLocale; + sLocale = inLocale; }; //static template<> std::string LLStringUtil::getLocale(void) { - return sLocale; + return sLocale; }; // static -template<> +template<> void LLStringUtil::formatNumber(std::string& numStr, std::string decimals) { - std::stringstream strStream; - S32 intDecimals = 0; - - convertToS32 (decimals, intDecimals); - if (!sLocale.empty()) - { - // std::locale() throws if the locale is unknown! (EXT-7926) - try - { - strStream.imbue(std::locale(sLocale.c_str())); - } catch (const std::exception &) - { - LL_WARNS_ONCE("Locale") << "Cannot set locale to " << sLocale << LL_ENDL; - } - } - - 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(); - } - } + std::stringstream strStream; + S32 intDecimals = 0; + + convertToS32 (decimals, intDecimals); + if (!sLocale.empty()) + { + // std::locale() throws if the locale is unknown! (EXT-7926) + try + { + strStream.imbue(std::locale(sLocale.c_str())); + } catch (const std::exception &) + { + LL_WARNS_ONCE("Locale") << "Cannot set locale to " << sLocale << LL_ENDL; + } + } + + 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<> +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::getPacificTimeOffset(); - } - - // if never fell into those two ifs above, param must be utc - if (secFromEpoch < 0) secFromEpoch = 0; - - LLDate datetime((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 = ""; // user knows their own timezone - } - else - { + std::string param, S32 secFromEpoch) +{ + if (param == "local") // local + { + secFromEpoch -= LLStringOps::getLocalTimeOffset(); + } + else if (param != "utc") // slt + { + secFromEpoch -= LLStringOps::getPacificTimeOffset(); + } + + // if never fell into those two ifs above, param must be utc + if (secFromEpoch < 0) secFromEpoch = 0; + + LLDate datetime((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 = ""; // user knows their own timezone + } + else + { #if 0 - // EXT-1565 : Zai Lynch, James Linden : 15/Oct/09 - // [BSI] Feedback: Viewer clock mentions SLT, but would prefer it to show PST/PDT - // "slt" = Second Life Time, which is deprecated. - // If not utc or user local time, fallback to Pacific time - replacement = LLStringOps::getPacificDaylightTime() ? "PDT" : "PST"; + // EXT-1565 : Zai Lynch, James Linden : 15/Oct/09 + // [BSI] Feedback: Viewer clock mentions SLT, but would prefer it to show PST/PDT + // "slt" = Second Life Time, which is deprecated. + // If not utc or user local time, fallback to Pacific time + replacement = LLStringOps::getPacificDaylightTime() ? "PDT" : "PST"; #else - // SL-20370 : Steeltoe Linden : 29/Sep/23 - // Change "PDT" to "SLT" on menu bar - replacement = "SLT"; + // SL-20370 : Steeltoe Linden : 29/Sep/23 + // Change "PDT" to "SLT" on menu bar + replacement = "SLT"; #endif - } - return true; - } - - //EXT-7013 - //few codes are not suppotred by strtime function (example - weekdays for Japanise) - //so use predefined ones - - //if sWeekDayList is not empty than current locale doesn't support + } + return true; + } + + //EXT-7013 + //few codes are not suppotred by strtime function (example - weekdays for Japanise) + //so use predefined ones + + //if sWeekDayList is not empty than current locale doesn't support //weekday name. - time_t loc_seconds = (time_t) secFromEpoch; - if(LLStringOps::sWeekDayList.size() == 7 && code == "%A") - { - struct tm * gmt = gmtime (&loc_seconds); - replacement = LLStringOps::sWeekDayList[gmt->tm_wday]; - } - else if(LLStringOps::sWeekDayShortList.size() == 7 && code == "%a") - { - struct tm * gmt = gmtime (&loc_seconds); - replacement = LLStringOps::sWeekDayShortList[gmt->tm_wday]; - } - else if(LLStringOps::sMonthList.size() == 12 && code == "%B") - { - struct tm * gmt = gmtime (&loc_seconds); - replacement = LLStringOps::sMonthList[gmt->tm_mon]; - } - else if( !LLStringOps::sDayFormat.empty() && code == "%d" ) - { - struct tm * gmt = gmtime (&loc_seconds); - LLStringUtil::format_map_t args; - args["[MDAY]"] = llformat ("%d", gmt->tm_mday); - replacement = LLStringOps::sDayFormat; - LLStringUtil::format(replacement, args); - } - else if (code == "%-d") - { - struct tm * gmt = gmtime (&loc_seconds); - replacement = llformat ("%d", gmt->tm_mday); // day of the month without leading zero - } - else if( !LLStringOps::sAM.empty() && !LLStringOps::sPM.empty() && code == "%p" ) - { - struct tm * gmt = gmtime (&loc_seconds); - if(gmt->tm_hour<12) - { - replacement = LLStringOps::sAM; - } - else - { - replacement = LLStringOps::sPM; - } - } - else - { - replacement = datetime.toHTTPDateString(code); - } - - // *HACK: delete leading zero from hour string in case 'hour12' (code = %I) time format - // to show time without leading zero, e.g. 08:16 -> 8:16 (EXT-2738). - // We could have used '%l' format instead, but it's not supported by Windows. - if(code == "%I" && token == "hour12" && replacement.at(0) == '0') - { - replacement = replacement.at(1); - } - - return !code.empty(); + time_t loc_seconds = (time_t) secFromEpoch; + if(LLStringOps::sWeekDayList.size() == 7 && code == "%A") + { + struct tm * gmt = gmtime (&loc_seconds); + replacement = LLStringOps::sWeekDayList[gmt->tm_wday]; + } + else if(LLStringOps::sWeekDayShortList.size() == 7 && code == "%a") + { + struct tm * gmt = gmtime (&loc_seconds); + replacement = LLStringOps::sWeekDayShortList[gmt->tm_wday]; + } + else if(LLStringOps::sMonthList.size() == 12 && code == "%B") + { + struct tm * gmt = gmtime (&loc_seconds); + replacement = LLStringOps::sMonthList[gmt->tm_mon]; + } + else if( !LLStringOps::sDayFormat.empty() && code == "%d" ) + { + struct tm * gmt = gmtime (&loc_seconds); + LLStringUtil::format_map_t args; + args["[MDAY]"] = llformat ("%d", gmt->tm_mday); + replacement = LLStringOps::sDayFormat; + LLStringUtil::format(replacement, args); + } + else if (code == "%-d") + { + struct tm * gmt = gmtime (&loc_seconds); + replacement = llformat ("%d", gmt->tm_mday); // day of the month without leading zero + } + else if( !LLStringOps::sAM.empty() && !LLStringOps::sPM.empty() && code == "%p" ) + { + struct tm * gmt = gmtime (&loc_seconds); + if(gmt->tm_hour<12) + { + replacement = LLStringOps::sAM; + } + else + { + replacement = LLStringOps::sPM; + } + } + else + { + replacement = datetime.toHTTPDateString(code); + } + + // *HACK: delete leading zero from hour string in case 'hour12' (code = %I) time format + // to show time without leading zero, e.g. 08:16 -> 8:16 (EXT-2738). + // We could have used '%l' format instead, but it's not supported by Windows. + if(code == "%I" && token == "hour12" && replacement.at(0) == '0') + { + replacement = replacement.at(1); + } + + return !code.empty(); } // LLStringUtil::format recogizes the following patterns. @@ -1493,146 +1493,146 @@ bool LLStringUtil::formatDatetime(std::string& replacement, std::string token, // static -template<> +template<> S32 LLStringUtil::format(std::string& s, const format_map_t& substitutions) { LL_PROFILE_ZONE_SCOPED_CATEGORY_STRING; - S32 res = 0; - - std::string output; - std::vector 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() == 0) - { - found_replacement = false; - } - else 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, use the string as is - // e.g. "hello [MISSING_REPLACEMENT]" or "-=[Stylized Name]=-" - output += std::string(s, key_start, start-key_start); - } - tokens.clear(); - } - // send the remainder of the string (with no further matches for bracketed names) - output += std::string(s, start); - s = output; - return res; + S32 res = 0; + + std::string output; + std::vector 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() == 0) + { + found_replacement = false; + } + else 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, use the string as is + // e.g. "hello [MISSING_REPLACEMENT]" or "-=[Stylized Name]=-" + output += std::string(s, key_start, start-key_start); + } + 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<> +template<> S32 LLStringUtil::format(std::string& s, const LLSD& substitutions) { LL_PROFILE_ZONE_SCOPED_CATEGORY_STRING; - S32 res = 0; - - if (!substitutions.isMap()) - { - return res; - } - - std::string output; - std::vector 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() == 0) - { - found_replacement = false; - } - else 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, use the string as is - // e.g. "hello [MISSING_REPLACEMENT]" or "-=[Stylized Name]=-" - output += std::string(s, key_start, start-key_start); - } - tokens.clear(); - } - // send the remainder of the string (with no further matches for bracketed names) - output += std::string(s, start); - s = output; - return res; + S32 res = 0; + + if (!substitutions.isMap()) + { + return res; + } + + std::string output; + std::vector 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() == 0) + { + found_replacement = false; + } + else 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, use the string as is + // e.g. "hello [MISSING_REPLACEMENT]" or "-=[Stylized Name]=-" + output += std::string(s, key_start, start-key_start); + } + tokens.clear(); + } + // send the remainder of the string (with no further matches for bracketed names) + output += std::string(s, start); + s = output; + return res; } //////////////////////////////////////////////////////////// @@ -1640,102 +1640,102 @@ S32 LLStringUtil::format(std::string& s, const LLSD& substitutions) #ifdef _DEBUG -template +template void LLStringUtilBase::testHarness() { - std::string s1; - - llassert( s1.c_str() == NULL ); - llassert( s1.size() == 0 ); - llassert( s1.empty() ); - - std::string s2( "hello"); - llassert( !strcmp( s2.c_str(), "hello" ) ); - llassert( s2.size() == 5 ); - llassert( !s2.empty() ); - std::string s3( s2 ); - - llassert( "hello" == s2 ); - llassert( s2 == "hello" ); - llassert( s2 > "gello" ); - llassert( "gello" < s2 ); - llassert( "gello" != s2 ); - llassert( s2 != "gello" ); - - std::string s4 = s2; - llassert( !s4.empty() ); - s4.empty(); - llassert( s4.empty() ); - - std::string s5(""); - llassert( s5.empty() ); - - llassert( isValidIndex(s5, 0) ); - llassert( !isValidIndex(s5, 1) ); - - s3 = s2; - s4 = "hello again"; - - s4 += "!"; - s4 += s4; - llassert( s4 == "hello again!hello again!" ); - - - std::string s6 = s2 + " " + s2; - std::string s7 = s6; - llassert( s6 == s7 ); - llassert( !( s6 != s7) ); - llassert( !(s6 < s7) ); - llassert( !(s6 > s7) ); - - llassert( !(s6 == "hi")); - llassert( s6 == "hello hello"); - llassert( s6 < "hi"); - - llassert( s6[1] == 'e' ); - s6[1] = 'f'; - llassert( s6[1] == 'f' ); - - s2.erase( 4, 1 ); - llassert( s2 == "hell"); - s2.insert( 0, "y" ); - llassert( s2 == "yhell"); - s2.erase( 1, 3 ); - llassert( s2 == "yl"); - s2.insert( 1, "awn, don't yel"); - llassert( s2 == "yawn, don't yell"); - - std::string s8 = s2.substr( 6, 5 ); - llassert( s8 == "don't" ); - - std::string s9 = " \t\ntest \t\t\n "; - trim(s9); - llassert( s9 == "test" ); - - s8 = "abc123&*(ABC"; - - s9 = s8; - toUpper(s9); - llassert( s9 == "ABC123&*(ABC" ); - - s9 = s8; - toLower(s9); - llassert( s9 == "abc123&*(abc" ); - - - std::string s10( 10, 'x' ); - llassert( s10 == "xxxxxxxxxx" ); - - std::string s11( "monkey in the middle", 7, 2 ); - llassert( s11 == "in" ); - - std::string s12; //empty - s12 += "foo"; - llassert( s12 == "foo" ); - - std::string s13; //empty - s13 += 'f'; - llassert( s13 == "f" ); + std::string s1; + + llassert( s1.c_str() == NULL ); + llassert( s1.size() == 0 ); + llassert( s1.empty() ); + + std::string s2( "hello"); + llassert( !strcmp( s2.c_str(), "hello" ) ); + llassert( s2.size() == 5 ); + llassert( !s2.empty() ); + std::string s3( s2 ); + + llassert( "hello" == s2 ); + llassert( s2 == "hello" ); + llassert( s2 > "gello" ); + llassert( "gello" < s2 ); + llassert( "gello" != s2 ); + llassert( s2 != "gello" ); + + std::string s4 = s2; + llassert( !s4.empty() ); + s4.empty(); + llassert( s4.empty() ); + + std::string s5(""); + llassert( s5.empty() ); + + llassert( isValidIndex(s5, 0) ); + llassert( !isValidIndex(s5, 1) ); + + s3 = s2; + s4 = "hello again"; + + s4 += "!"; + s4 += s4; + llassert( s4 == "hello again!hello again!" ); + + + std::string s6 = s2 + " " + s2; + std::string s7 = s6; + llassert( s6 == s7 ); + llassert( !( s6 != s7) ); + llassert( !(s6 < s7) ); + llassert( !(s6 > s7) ); + + llassert( !(s6 == "hi")); + llassert( s6 == "hello hello"); + llassert( s6 < "hi"); + + llassert( s6[1] == 'e' ); + s6[1] = 'f'; + llassert( s6[1] == 'f' ); + + s2.erase( 4, 1 ); + llassert( s2 == "hell"); + s2.insert( 0, "y" ); + llassert( s2 == "yhell"); + s2.erase( 1, 3 ); + llassert( s2 == "yl"); + s2.insert( 1, "awn, don't yel"); + llassert( s2 == "yawn, don't yell"); + + std::string s8 = s2.substr( 6, 5 ); + llassert( s8 == "don't" ); + + std::string s9 = " \t\ntest \t\t\n "; + trim(s9); + llassert( s9 == "test" ); + + s8 = "abc123&*(ABC"; + + s9 = s8; + toUpper(s9); + llassert( s9 == "ABC123&*(ABC" ); + + s9 = s8; + toLower(s9); + llassert( s9 == "abc123&*(abc" ); + + + std::string s10( 10, 'x' ); + llassert( s10 == "xxxxxxxxxx" ); + + std::string s11( "monkey in the middle", 7, 2 ); + llassert( s11 == "in" ); + + std::string s12; //empty + s12 += "foo"; + llassert( s12 == "foo" ); + + std::string s13; //empty + s13 += 'f'; + llassert( s13 == "f" ); } diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h index be00aa277b..3829978ddf 100644 --- a/indra/llcommon/llstring.h +++ b/indra/llcommon/llstring.h @@ -1,25 +1,25 @@ -/** +/** * @file llstring.h * @brief String utility functions and std::string class. * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -59,85 +59,85 @@ namespace std template<> struct char_traits { - typedef U16 char_type; - typedef int int_type; - typedef streampos pos_type; - typedef streamoff off_type; - typedef mbstate_t state_type; - - static void - assign(char_type& __c1, const char_type& __c2) - { __c1 = __c2; } - - static bool - eq(const char_type& __c1, const char_type& __c2) - { return __c1 == __c2; } - - static bool - lt(const char_type& __c1, const char_type& __c2) - { return __c1 < __c2; } - - static int - compare(const char_type* __s1, const char_type* __s2, size_t __n) - { return memcmp(__s1, __s2, __n * sizeof(char_type)); } - - static size_t - length(const char_type* __s) - { - const char_type *cur_char = __s; - while (*cur_char != 0) - { - ++cur_char; - } - return cur_char - __s; - } - - static const char_type* - find(const char_type* __s, size_t __n, const char_type& __a) - { return static_cast(memchr(__s, __a, __n * sizeof(char_type))); } - - static char_type* - move(char_type* __s1, const char_type* __s2, size_t __n) - { return static_cast(memmove(__s1, __s2, __n * sizeof(char_type))); } - - static char_type* - copy(char_type* __s1, const char_type* __s2, size_t __n) - { return static_cast(memcpy(__s1, __s2, __n * sizeof(char_type))); } /* Flawfinder: ignore */ - - static char_type* - assign(char_type* __s, size_t __n, char_type __a) - { - // This isn't right. - //return static_cast(memset(__s, __a, __n * sizeof(char_type))); - - // I don't think there's a standard 'memset' for 16-bit values. - // Do this the old-fashioned way. - - size_t __i; - for(__i = 0; __i < __n; __i++) - { - __s[__i] = __a; - } - return __s; - } - - static char_type - to_char_type(const int_type& __c) - { return static_cast(__c); } - - static int_type - to_int_type(const char_type& __c) - { return static_cast(__c); } - - static bool - eq_int_type(const int_type& __c1, const int_type& __c2) - { return __c1 == __c2; } - - static int_type - eof() { return static_cast(EOF); } - - static int_type - not_eof(const int_type& __c) + typedef U16 char_type; + typedef int int_type; + typedef streampos pos_type; + typedef streamoff off_type; + typedef mbstate_t state_type; + + static void + assign(char_type& __c1, const char_type& __c2) + { __c1 = __c2; } + + static bool + eq(const char_type& __c1, const char_type& __c2) + { return __c1 == __c2; } + + static bool + lt(const char_type& __c1, const char_type& __c2) + { return __c1 < __c2; } + + static int + compare(const char_type* __s1, const char_type* __s2, size_t __n) + { return memcmp(__s1, __s2, __n * sizeof(char_type)); } + + static size_t + length(const char_type* __s) + { + const char_type *cur_char = __s; + while (*cur_char != 0) + { + ++cur_char; + } + return cur_char - __s; + } + + static const char_type* + find(const char_type* __s, size_t __n, const char_type& __a) + { return static_cast(memchr(__s, __a, __n * sizeof(char_type))); } + + static char_type* + move(char_type* __s1, const char_type* __s2, size_t __n) + { return static_cast(memmove(__s1, __s2, __n * sizeof(char_type))); } + + static char_type* + copy(char_type* __s1, const char_type* __s2, size_t __n) + { return static_cast(memcpy(__s1, __s2, __n * sizeof(char_type))); } /* Flawfinder: ignore */ + + static char_type* + assign(char_type* __s, size_t __n, char_type __a) + { + // This isn't right. + //return static_cast(memset(__s, __a, __n * sizeof(char_type))); + + // I don't think there's a standard 'memset' for 16-bit values. + // Do this the old-fashioned way. + + size_t __i; + for(__i = 0; __i < __n; __i++) + { + __s[__i] = __a; + } + return __s; + } + + static char_type + to_char_type(const int_type& __c) + { return static_cast(__c); } + + static int_type + to_int_type(const char_type& __c) + { return static_cast(__c); } + + static bool + eq_int_type(const int_type& __c1, const int_type& __c2) + { return __c1 == __c2; } + + static int_type + eof() { return static_cast(EOF); } + + static int_type + not_eof(const int_type& __c) { return (__c == eof()) ? 0 : __c; } }; }; @@ -146,72 +146,72 @@ struct char_traits class LL_COMMON_API LLStringOps { private: - static long sPacificTimeOffset; - static long sLocalTimeOffset; - static bool sPacificDaylightTime; + static long sPacificTimeOffset; + static long sLocalTimeOffset; + static bool sPacificDaylightTime; - static std::map datetimeToCodes; + static std::map datetimeToCodes; public: - static std::vector sWeekDayList; - static std::vector sWeekDayShortList; - static std::vector sMonthList; - static std::vector sMonthShortList; - static std::string sDayFormat; + static std::vector sWeekDayList; + static std::vector sWeekDayShortList; + static std::vector sMonthList; + static std::vector sMonthShortList; + static std::string sDayFormat; - static std::string sAM; - static std::string sPM; + static std::string sAM; + static std::string sPM; - static char toUpper(char elem) { return toupper((unsigned char)elem); } - static llwchar toUpper(llwchar elem) { return towupper(elem); } - - static char toLower(char elem) { return tolower((unsigned char)elem); } - static llwchar toLower(llwchar elem) { return towlower(elem); } + static char toUpper(char elem) { return toupper((unsigned char)elem); } + static llwchar toUpper(llwchar elem) { return towupper(elem); } - static bool isSpace(char elem) { return isspace((unsigned char)elem) != 0; } - static bool isSpace(llwchar elem) { return iswspace(elem) != 0; } + static char toLower(char elem) { return tolower((unsigned char)elem); } + static llwchar toLower(llwchar elem) { return towlower(elem); } - static bool isUpper(char elem) { return isupper((unsigned char)elem) != 0; } - static bool isUpper(llwchar elem) { return iswupper(elem) != 0; } + static bool isSpace(char elem) { return isspace((unsigned char)elem) != 0; } + static bool isSpace(llwchar elem) { return iswspace(elem) != 0; } - static bool isLower(char elem) { return islower((unsigned char)elem) != 0; } - static bool isLower(llwchar elem) { return iswlower(elem) != 0; } + static bool isUpper(char elem) { return isupper((unsigned char)elem) != 0; } + static bool isUpper(llwchar elem) { return iswupper(elem) != 0; } - static bool isDigit(char a) { return isdigit((unsigned char)a) != 0; } - static bool isDigit(llwchar a) { return iswdigit(a) != 0; } + static bool isLower(char elem) { return islower((unsigned char)elem) != 0; } + static bool isLower(llwchar elem) { return iswlower(elem) != 0; } - static bool isPunct(char a) { return ispunct((unsigned char)a) != 0; } - static bool isPunct(llwchar a) { return iswpunct(a) != 0; } + static bool isDigit(char a) { return isdigit((unsigned char)a) != 0; } + static bool isDigit(llwchar a) { return iswdigit(a) != 0; } - static bool isAlpha(char a) { return isalpha((unsigned char)a) != 0; } - static bool isAlpha(llwchar a) { return iswalpha(a) != 0; } + static bool isPunct(char a) { return ispunct((unsigned char)a) != 0; } + static bool isPunct(llwchar a) { return iswpunct(a) != 0; } - static bool isAlnum(char a) { return isalnum((unsigned char)a) != 0; } - static bool isAlnum(llwchar a) { return iswalnum(a) != 0; } + static bool isAlpha(char a) { return isalpha((unsigned char)a) != 0; } + static bool isAlpha(llwchar a) { return iswalpha(a) != 0; } - static bool isEmoji(llwchar wch); + static bool isAlnum(char a) { return isalnum((unsigned char)a) != 0; } + static bool isAlnum(llwchar a) { return iswalnum(a) != 0; } - static S32 collate(const char* a, const char* b) { return strcoll(a, b); } - static S32 collate(const llwchar* a, const llwchar* b); + static bool isEmoji(llwchar wch); - static void setupDatetimeInfo(bool pacific_daylight_time); + static S32 collate(const char* a, const char* b) { return strcoll(a, b); } + static S32 collate(const llwchar* a, const llwchar* b); - static void setupWeekDaysNames(const std::string& data); - static void setupWeekDaysShortNames(const std::string& data); - static void setupMonthNames(const std::string& data); - static void setupMonthShortNames(const std::string& data); - static void setupDayFormat(const std::string& data); + static void setupDatetimeInfo(bool pacific_daylight_time); + static void setupWeekDaysNames(const std::string& data); + static void setupWeekDaysShortNames(const std::string& data); + static void setupMonthNames(const std::string& data); + static void setupMonthShortNames(const std::string& data); + static void setupDayFormat(const std::string& data); - static long getPacificTimeOffset(void) { return sPacificTimeOffset;} - static long getLocalTimeOffset(void) { return sLocalTimeOffset;} - // Is the Pacific time zone (aka server time zone) - // currently in daylight savings time? - static bool getPacificDaylightTime(void) { return sPacificDaylightTime;} - static std::string getDatetimeCode (std::string key); + static long getPacificTimeOffset(void) { return sPacificTimeOffset;} + static long getLocalTimeOffset(void) { return sLocalTimeOffset;} + // Is the Pacific time zone (aka server time zone) + // currently in daylight savings time? + static bool getPacificDaylightTime(void) { return sPacificDaylightTime;} - // Express a value like 1234567 as "1.23M" + static std::string getDatetimeCode (std::string key); + + // Express a value like 1234567 as "1.23M" static std::string getReadableNumber(F64 num); }; @@ -228,216 +228,216 @@ LL_COMMON_API std::string ll_safe_string(const char* in, S32 maxlen); class LLFormatMapString { public: - LLFormatMapString() {}; - LLFormatMapString(const char* s) : mString(ll_safe_string(s)) {}; - LLFormatMapString(const std::string& s) : mString(s) {}; - operator std::string() const { return mString; } - bool operator<(const LLFormatMapString& rhs) const { return mString < rhs.mString; } - std::size_t length() const { return mString.length(); } - + LLFormatMapString() {}; + LLFormatMapString(const char* s) : mString(ll_safe_string(s)) {}; + LLFormatMapString(const std::string& s) : mString(s) {}; + operator std::string() const { return mString; } + bool operator<(const LLFormatMapString& rhs) const { return mString < rhs.mString; } + std::size_t length() const { return mString.length(); } + private: - std::string mString; + std::string mString; }; template class LLStringUtilBase { private: - static std::string sLocale; + static std::string sLocale; public: - typedef std::basic_string string_type; - typedef typename string_type::size_type size_type; - + typedef std::basic_string string_type; + typedef typename string_type::size_type size_type; + public: - ///////////////////////////////////////////////////////////////////////////////////////// - // Static Utility functions that operate on std::strings - - static const string_type null; - - typedef std::map format_map_t; - /// considers any sequence of delims as a single field separator - LL_COMMON_API static void getTokens(const string_type& instr, - std::vector& tokens, - const string_type& delims); - /// like simple scan overload, but returns scanned vector - static std::vector getTokens(const string_type& instr, - const string_type& delims); - /// add support for keep_delims and quotes (either could be empty string) - static void getTokens(const string_type& instr, - std::vector& tokens, - const string_type& drop_delims, - const string_type& keep_delims, - const string_type& quotes=string_type()); - /// like keep_delims-and-quotes overload, but returns scanned vector - static std::vector getTokens(const string_type& instr, - const string_type& drop_delims, - const string_type& keep_delims, - const string_type& quotes=string_type()); - /// add support for escapes (could be empty string) - static void getTokens(const string_type& instr, - std::vector& tokens, - const string_type& drop_delims, - const string_type& keep_delims, - const string_type& quotes, - const string_type& escapes); - /// like escapes overload, but returns scanned vector - static std::vector getTokens(const string_type& instr, - const string_type& drop_delims, - const string_type& keep_delims, - const string_type& quotes, - const string_type& escapes); - - LL_COMMON_API static void formatNumber(string_type& numStr, string_type decimals); - LL_COMMON_API static bool formatDatetime(string_type& replacement, string_type token, string_type param, S32 secFromEpoch); - LL_COMMON_API static S32 format(string_type& s, const format_map_t& substitutions); - LL_COMMON_API static S32 format(string_type& s, const LLSD& substitutions); - LL_COMMON_API static bool simpleReplacement(string_type& replacement, string_type token, const format_map_t& substitutions); - LL_COMMON_API static bool simpleReplacement(string_type& replacement, string_type token, const LLSD& substitutions); - LL_COMMON_API static void setLocale (std::string inLocale); - LL_COMMON_API static std::string getLocale (void); - - static bool isValidIndex(const string_type& string, size_type i) - { - return !string.empty() && (0 <= i) && (i <= string.size()); - } - - static bool contains(const string_type& string, T c, size_type i=0) - { - return string.find(c, i) != string_type::npos; - } - - static void trimHead(string_type& string); - static void trimTail(string_type& string); - static void trim(string_type& string) { trimHead(string); trimTail(string); } - static void truncate(string_type& string, size_type count); - - static void toUpper(string_type& string); - static void toLower(string_type& string); - - // True if this is the head of s. - static BOOL isHead( const string_type& string, const T* s ); - - /** - * @brief Returns true if string starts with substr - * - * If etither string or substr are empty, this method returns false. - */ - static bool startsWith( - const string_type& string, - const string_type& substr); - - /** - * @brief Returns true if string ends in substr - * - * If etither string or substr are empty, this method returns false. - */ - static bool endsWith( - const string_type& string, - const string_type& substr); - - /** - * get environment string value with proper Unicode handling - * (key is always UTF-8) - * detect absence by return value == dflt - */ - static string_type getenv(const std::string& key, const string_type& dflt=""); - /** - * get optional environment string value with proper Unicode handling - * (key is always UTF-8) - * detect absence by (! return value) - */ - static boost::optional getoptenv(const std::string& key); - - static void addCRLF(string_type& string); - static void removeCRLF(string_type& string); - static void removeWindowsCR(string_type& string); - - static void replaceTabsWithSpaces( string_type& string, size_type spaces_per_tab ); - static void replaceNonstandardASCII( string_type& string, T replacement ); - static void replaceChar( string_type& string, T target, T replacement ); - static void replaceString( string_type& string, string_type target, string_type replacement ); - static string_type capitalize(const string_type& str); - static void capitalize(string_type& str); - - static BOOL containsNonprintable(const string_type& string); - static void stripNonprintable(string_type& string); - - /** - * Double-quote an argument string if needed, unless it's already - * double-quoted. Decide whether it's needed based on the presence of any - * character in @a triggers (default space or double-quote). If we quote - * it, escape any embedded double-quote with the @a escape string (default - * backslash). - * - * Passing triggers="" means always quote, unless it's already double-quoted. - */ - static string_type quote(const string_type& str, - const string_type& triggers=" \"", - const string_type& escape="\\"); - - /** - * @brief Unsafe way to make ascii characters. You should probably - * only call this when interacting with the host operating system. - * The 1 byte std::string does not work correctly. - * The 2 and 4 byte std::string probably work, so LLWStringUtil::_makeASCII - * should work. - */ - static void _makeASCII(string_type& string); - - // Conversion to other data types - static BOOL convertToBOOL(const string_type& string, BOOL& value); - static BOOL convertToU8(const string_type& string, U8& value); - static BOOL convertToS8(const string_type& string, S8& value); - static BOOL convertToS16(const string_type& string, S16& value); - static BOOL convertToU16(const string_type& string, U16& value); - static BOOL convertToU32(const string_type& string, U32& value); - static BOOL convertToS32(const string_type& string, S32& value); - static BOOL convertToF32(const string_type& string, F32& value); - static BOOL convertToF64(const string_type& string, F64& value); - - ///////////////////////////////////////////////////////////////////////////////////////// - // Utility functions for working with char*'s and strings - - // Like strcmp but also handles empty strings. Uses - // current locale. - static S32 compareStrings(const T* lhs, const T* rhs); - static S32 compareStrings(const string_type& lhs, const string_type& rhs); - - // case insensitive version of above. Uses current locale on - // Win32, and falls back to a non-locale aware comparison on - // Linux. - static S32 compareInsensitive(const T* lhs, const T* rhs); - static S32 compareInsensitive(const string_type& lhs, const string_type& rhs); - - // Case sensitive comparison with good handling of numbers. Does not use current locale. - // a.k.a. strdictcmp() - static S32 compareDict(const string_type& a, const string_type& b); - - // Case *in*sensitive comparison with good handling of numbers. Does not use current locale. - // a.k.a. strdictcmp() - static S32 compareDictInsensitive(const string_type& a, const string_type& b); - - // Puts compareDict() in a form appropriate for LL container classes to use for sorting. - static BOOL precedesDict( const string_type& a, const string_type& b ); - - // A replacement for strncpy. - // If the dst buffer is dst_size bytes long or more, ensures that dst is null terminated and holds - // up to dst_size-1 characters of src. - static void copy(T* dst, const T* src, size_type dst_size); - - // Copies src into dst at a given offset. - static void copyInto(string_type& dst, const string_type& src, size_type offset); - - static bool isPartOfWord(T c) { return (c == (T)'_') || LLStringOps::isAlnum(c); } - - -#ifdef _DEBUG - LL_COMMON_API static void testHarness(); + ///////////////////////////////////////////////////////////////////////////////////////// + // Static Utility functions that operate on std::strings + + static const string_type null; + + typedef std::map format_map_t; + /// considers any sequence of delims as a single field separator + LL_COMMON_API static void getTokens(const string_type& instr, + std::vector& tokens, + const string_type& delims); + /// like simple scan overload, but returns scanned vector + static std::vector getTokens(const string_type& instr, + const string_type& delims); + /// add support for keep_delims and quotes (either could be empty string) + static void getTokens(const string_type& instr, + std::vector& tokens, + const string_type& drop_delims, + const string_type& keep_delims, + const string_type& quotes=string_type()); + /// like keep_delims-and-quotes overload, but returns scanned vector + static std::vector getTokens(const string_type& instr, + const string_type& drop_delims, + const string_type& keep_delims, + const string_type& quotes=string_type()); + /// add support for escapes (could be empty string) + static void getTokens(const string_type& instr, + std::vector& tokens, + const string_type& drop_delims, + const string_type& keep_delims, + const string_type& quotes, + const string_type& escapes); + /// like escapes overload, but returns scanned vector + static std::vector getTokens(const string_type& instr, + const string_type& drop_delims, + const string_type& keep_delims, + const string_type& quotes, + const string_type& escapes); + + LL_COMMON_API static void formatNumber(string_type& numStr, string_type decimals); + LL_COMMON_API static bool formatDatetime(string_type& replacement, string_type token, string_type param, S32 secFromEpoch); + LL_COMMON_API static S32 format(string_type& s, const format_map_t& substitutions); + LL_COMMON_API static S32 format(string_type& s, const LLSD& substitutions); + LL_COMMON_API static bool simpleReplacement(string_type& replacement, string_type token, const format_map_t& substitutions); + LL_COMMON_API static bool simpleReplacement(string_type& replacement, string_type token, const LLSD& substitutions); + LL_COMMON_API static void setLocale (std::string inLocale); + LL_COMMON_API static std::string getLocale (void); + + static bool isValidIndex(const string_type& string, size_type i) + { + return !string.empty() && (0 <= i) && (i <= string.size()); + } + + static bool contains(const string_type& string, T c, size_type i=0) + { + return string.find(c, i) != string_type::npos; + } + + static void trimHead(string_type& string); + static void trimTail(string_type& string); + static void trim(string_type& string) { trimHead(string); trimTail(string); } + static void truncate(string_type& string, size_type count); + + static void toUpper(string_type& string); + static void toLower(string_type& string); + + // True if this is the head of s. + static BOOL isHead( const string_type& string, const T* s ); + + /** + * @brief Returns true if string starts with substr + * + * If etither string or substr are empty, this method returns false. + */ + static bool startsWith( + const string_type& string, + const string_type& substr); + + /** + * @brief Returns true if string ends in substr + * + * If etither string or substr are empty, this method returns false. + */ + static bool endsWith( + const string_type& string, + const string_type& substr); + + /** + * get environment string value with proper Unicode handling + * (key is always UTF-8) + * detect absence by return value == dflt + */ + static string_type getenv(const std::string& key, const string_type& dflt=""); + /** + * get optional environment string value with proper Unicode handling + * (key is always UTF-8) + * detect absence by (! return value) + */ + static boost::optional getoptenv(const std::string& key); + + static void addCRLF(string_type& string); + static void removeCRLF(string_type& string); + static void removeWindowsCR(string_type& string); + + static void replaceTabsWithSpaces( string_type& string, size_type spaces_per_tab ); + static void replaceNonstandardASCII( string_type& string, T replacement ); + static void replaceChar( string_type& string, T target, T replacement ); + static void replaceString( string_type& string, string_type target, string_type replacement ); + static string_type capitalize(const string_type& str); + static void capitalize(string_type& str); + + static BOOL containsNonprintable(const string_type& string); + static void stripNonprintable(string_type& string); + + /** + * Double-quote an argument string if needed, unless it's already + * double-quoted. Decide whether it's needed based on the presence of any + * character in @a triggers (default space or double-quote). If we quote + * it, escape any embedded double-quote with the @a escape string (default + * backslash). + * + * Passing triggers="" means always quote, unless it's already double-quoted. + */ + static string_type quote(const string_type& str, + const string_type& triggers=" \"", + const string_type& escape="\\"); + + /** + * @brief Unsafe way to make ascii characters. You should probably + * only call this when interacting with the host operating system. + * The 1 byte std::string does not work correctly. + * The 2 and 4 byte std::string probably work, so LLWStringUtil::_makeASCII + * should work. + */ + static void _makeASCII(string_type& string); + + // Conversion to other data types + static BOOL convertToBOOL(const string_type& string, BOOL& value); + static BOOL convertToU8(const string_type& string, U8& value); + static BOOL convertToS8(const string_type& string, S8& value); + static BOOL convertToS16(const string_type& string, S16& value); + static BOOL convertToU16(const string_type& string, U16& value); + static BOOL convertToU32(const string_type& string, U32& value); + static BOOL convertToS32(const string_type& string, S32& value); + static BOOL convertToF32(const string_type& string, F32& value); + static BOOL convertToF64(const string_type& string, F64& value); + + ///////////////////////////////////////////////////////////////////////////////////////// + // Utility functions for working with char*'s and strings + + // Like strcmp but also handles empty strings. Uses + // current locale. + static S32 compareStrings(const T* lhs, const T* rhs); + static S32 compareStrings(const string_type& lhs, const string_type& rhs); + + // case insensitive version of above. Uses current locale on + // Win32, and falls back to a non-locale aware comparison on + // Linux. + static S32 compareInsensitive(const T* lhs, const T* rhs); + static S32 compareInsensitive(const string_type& lhs, const string_type& rhs); + + // Case sensitive comparison with good handling of numbers. Does not use current locale. + // a.k.a. strdictcmp() + static S32 compareDict(const string_type& a, const string_type& b); + + // Case *in*sensitive comparison with good handling of numbers. Does not use current locale. + // a.k.a. strdictcmp() + static S32 compareDictInsensitive(const string_type& a, const string_type& b); + + // Puts compareDict() in a form appropriate for LL container classes to use for sorting. + static BOOL precedesDict( const string_type& a, const string_type& b ); + + // A replacement for strncpy. + // If the dst buffer is dst_size bytes long or more, ensures that dst is null terminated and holds + // up to dst_size-1 characters of src. + static void copy(T* dst, const T* src, size_type dst_size); + + // Copies src into dst at a given offset. + static void copyInto(string_type& dst, const string_type& src, size_type offset); + + static bool isPartOfWord(T c) { return (c == (T)'_') || LLStringOps::isAlnum(c); } + + +#ifdef _DEBUG + LL_COMMON_API static void testHarness(); #endif private: - LL_COMMON_API static size_type getSubstitution(const string_type& instr, size_type& start, std::vector& tokens); + LL_COMMON_API static size_type getSubstitution(const string_type& instr, size_type& start, std::vector& tokens); }; template const std::basic_string LLStringUtilBase::null; @@ -453,18 +453,18 @@ typedef std::basic_string LLWString; class LLStringExplicit : public std::string { public: - explicit LLStringExplicit(const char* s) : std::string(s) {} - LLStringExplicit(const std::string& s) : std::string(s) {} - LLStringExplicit(const std::string& s, size_type pos, size_type n = std::string::npos) : std::string(s, pos, n) {} + explicit LLStringExplicit(const char* s) : std::string(s) {} + LLStringExplicit(const std::string& s) : std::string(s) {} + LLStringExplicit(const std::string& s, size_type pos, size_type n = std::string::npos) : std::string(s, pos, n) {} }; struct LLDictionaryLess { public: - bool operator()(const std::string& a, const std::string& b) const - { - return (LLStringUtil::precedesDict(a, b) ? true : false); - } + bool operator()(const std::string& a, const std::string& b) const + { + return (LLStringUtil::precedesDict(a, b) ? true : false); + } }; @@ -481,10 +481,10 @@ public: * @return a copy of in string minus the trailing count bytes. */ inline std::string chop_tail_copy( - const std::string& in, - std::string::size_type count) + const std::string& in, + std::string::size_type count) { - return std::string(in, 0, in.length() - count); + return std::string(in, 0, in.length() - count); } /** @@ -677,10 +677,10 @@ ll_convert_forms(ll_convert_u16_alias, std::string, llutf16string, utf16str_to_u inline std::string wstring_to_utf8str(const llutf16string &utf16str) { return utf16str_to_utf8str(utf16str);} // Length of this UTF32 string in bytes when transformed to UTF8 -LL_COMMON_API S32 wstring_utf8_length(const LLWString& wstr); +LL_COMMON_API S32 wstring_utf8_length(const LLWString& wstr); // Length in bytes of this wide char in a UTF8 string -LL_COMMON_API S32 wchar_utf8_length(const llwchar wc); +LL_COMMON_API S32 wchar_utf8_length(const llwchar wc); LL_COMMON_API std::string wchar_utf8_preview(const llwchar wc); @@ -697,7 +697,7 @@ LL_COMMON_API S32 wstring_wstring_length_from_utf16_length(const LLWString & wst /** * @brief Properly truncate a utf8 string to a maximum byte count. - * + * * The returned string may be less than max_len if the truncation * happens in the middle of a glyph. If max_len is longer than the * string passed in, the return value == utf8str. @@ -710,8 +710,8 @@ LL_COMMON_API std::string utf8str_truncate(const std::string& utf8str, const S32 LL_COMMON_API std::string utf8str_trim(const std::string& utf8str); LL_COMMON_API S32 utf8str_compare_insensitive( - const std::string& lhs, - const std::string& rhs); + const std::string& lhs, + const std::string& rhs); /** * @brief Properly truncate a utf8 string to a maximum character count. @@ -732,14 +732,14 @@ LL_COMMON_API std::string utf8str_symbol_truncate(const std::string& utf8str, co * @param replace_char The wchar which is written on replace */ LL_COMMON_API std::string utf8str_substChar( - const std::string& utf8str, - const llwchar target_char, - const llwchar replace_char); + const std::string& utf8str, + const llwchar target_char, + const llwchar replace_char); LL_COMMON_API std::string utf8str_makeASCII(const std::string& utf8str); // Hack - used for evil notecards. -LL_COMMON_API std::string mbcsstring_makeASCII(const std::string& str); +LL_COMMON_API std::string mbcsstring_makeASCII(const std::string& str); LL_COMMON_API std::string utf8str_removeCRLF(const std::string& utf8str); @@ -845,52 +845,52 @@ LL_COMMON_API boost::optional llstring_getoptenv(const std::string */ namespace LLStringFn { - /** - * @brief Replace all non-printable characters with replacement in - * string. - * NOTE - this will zap non-ascii - * - * @param [in,out] string the to modify. out value is the string - * with zero non-printable characters. - * @param The replacement character. use LL_UNKNOWN_CHAR if unsure. - */ - LL_COMMON_API void replace_nonprintable_in_ascii( - std::basic_string& string, - char replacement); - - - /** - * @brief Replace all non-printable characters and pipe characters - * with replacement in a string. - * NOTE - this will zap non-ascii - * - * @param [in,out] the string to modify. out value is the string - * with zero non-printable characters and zero pipe characters. - * @param The replacement character. use LL_UNKNOWN_CHAR if unsure. - */ - LL_COMMON_API void replace_nonprintable_and_pipe_in_ascii(std::basic_string& str, - char replacement); - - - /** - * @brief Remove all characters that are not allowed in XML 1.0. - * Returns a copy of the string with those characters removed. - * Works with US ASCII and UTF-8 encoded strings. JC - */ - LL_COMMON_API std::string strip_invalid_xml(const std::string& input); - - - /** - * @brief Replace all control characters (0 <= c < 0x20) with replacement in - * string. This is safe for utf-8 - * - * @param [in,out] string the to modify. out value is the string - * with zero non-printable characters. - * @param The replacement character. use LL_UNKNOWN_CHAR if unsure. - */ - LL_COMMON_API void replace_ascii_controlchars( - std::basic_string& string, - char replacement); + /** + * @brief Replace all non-printable characters with replacement in + * string. + * NOTE - this will zap non-ascii + * + * @param [in,out] string the to modify. out value is the string + * with zero non-printable characters. + * @param The replacement character. use LL_UNKNOWN_CHAR if unsure. + */ + LL_COMMON_API void replace_nonprintable_in_ascii( + std::basic_string& string, + char replacement); + + + /** + * @brief Replace all non-printable characters and pipe characters + * with replacement in a string. + * NOTE - this will zap non-ascii + * + * @param [in,out] the string to modify. out value is the string + * with zero non-printable characters and zero pipe characters. + * @param The replacement character. use LL_UNKNOWN_CHAR if unsure. + */ + LL_COMMON_API void replace_nonprintable_and_pipe_in_ascii(std::basic_string& str, + char replacement); + + + /** + * @brief Remove all characters that are not allowed in XML 1.0. + * Returns a copy of the string with those characters removed. + * Works with US ASCII and UTF-8 encoded strings. JC + */ + LL_COMMON_API std::string strip_invalid_xml(const std::string& input); + + + /** + * @brief Replace all control characters (0 <= c < 0x20) with replacement in + * string. This is safe for utf-8 + * + * @param [in,out] string the to modify. out value is the string + * with zero non-printable characters. + * @param The replacement character. use LL_UNKNOWN_CHAR if unsure. + */ + LL_COMMON_API void replace_ascii_controlchars( + std::basic_string& string, + char replacement); } //////////////////////////////////////////////////////////// @@ -905,36 +905,36 @@ template std::vector::string_type> LLStringUtilBase::getTokens(const string_type& instr, const string_type& delims) { - std::vector tokens; - getTokens(instr, tokens, delims); - return tokens; + std::vector tokens; + getTokens(instr, tokens, delims); + return tokens; } // static template std::vector::string_type> LLStringUtilBase::getTokens(const string_type& instr, - const string_type& drop_delims, - const string_type& keep_delims, - const string_type& quotes) + const string_type& drop_delims, + const string_type& keep_delims, + const string_type& quotes) { - std::vector tokens; - getTokens(instr, tokens, drop_delims, keep_delims, quotes); - return tokens; + std::vector tokens; + getTokens(instr, tokens, drop_delims, keep_delims, quotes); + return tokens; } // static template std::vector::string_type> LLStringUtilBase::getTokens(const string_type& instr, - const string_type& drop_delims, - const string_type& keep_delims, - const string_type& quotes, - const string_type& escapes) -{ - std::vector tokens; - getTokens(instr, tokens, drop_delims, keep_delims, quotes, escapes); - return tokens; + const string_type& drop_delims, + const string_type& keep_delims, + const string_type& quotes, + const string_type& escapes) +{ + std::vector tokens; + getTokens(instr, tokens, drop_delims, keep_delims, quotes, escapes); + return tokens; } namespace LLStringUtilBaseImpl @@ -950,62 +950,62 @@ namespace LLStringUtilBaseImpl template struct InString { - typedef std::basic_string string_type; - typedef typename string_type::const_iterator const_iterator; - - InString(const_iterator b, const_iterator e): - mIter(b), - mEnd(e) - {} - virtual ~InString() {} - - bool done() const { return mIter == mEnd; } - /// Is the current character (*mIter) escaped? This implementation can - /// answer trivially because it doesn't support escapes. - virtual bool escaped() const { return false; } - /// Obtain the current character and advance @c mIter. - virtual T next() { return *mIter++; } - /// Does the current character match specified character? - virtual bool is(T ch) const { return (! done()) && *mIter == ch; } - /// Is the current character any one of the specified characters? - virtual bool oneof(const string_type& delims) const - { - return (! done()) && LLStringUtilBase::contains(delims, *mIter); - } - - /** - * Scan forward from @from until either @a delim or end. This is primarily - * useful for processing quoted substrings. - * - * If we do see @a delim, append everything from @from until (excluding) - * @a delim to @a into, advance @c mIter to skip @a delim, and return @c - * true. - * - * If we do not see @a delim, do not alter @a into or @c mIter and return - * @c false. Do not pass GO, do not collect $200. - * - * @note The @c false case described above implements normal getTokens() - * treatment of an unmatched open quote: treat the quote character as if - * escaped, that is, simply collect it as part of the current token. Other - * plausible behaviors directly affect the way getTokens() deals with an - * unmatched quote: e.g. throwing an exception to treat it as an error, or - * assuming a close quote beyond end of string (in which case return @c - * true). - */ - virtual bool collect_until(string_type& into, const_iterator from, T delim) - { - const_iterator found = std::find(from, mEnd, delim); - // If we didn't find delim, change nothing, just tell caller. - if (found == mEnd) - return false; - // Found delim! Append everything between from and found. - into.append(from, found); - // advance past delim in input - mIter = found + 1; - return true; - } - - const_iterator mIter, mEnd; + typedef std::basic_string string_type; + typedef typename string_type::const_iterator const_iterator; + + InString(const_iterator b, const_iterator e): + mIter(b), + mEnd(e) + {} + virtual ~InString() {} + + bool done() const { return mIter == mEnd; } + /// Is the current character (*mIter) escaped? This implementation can + /// answer trivially because it doesn't support escapes. + virtual bool escaped() const { return false; } + /// Obtain the current character and advance @c mIter. + virtual T next() { return *mIter++; } + /// Does the current character match specified character? + virtual bool is(T ch) const { return (! done()) && *mIter == ch; } + /// Is the current character any one of the specified characters? + virtual bool oneof(const string_type& delims) const + { + return (! done()) && LLStringUtilBase::contains(delims, *mIter); + } + + /** + * Scan forward from @from until either @a delim or end. This is primarily + * useful for processing quoted substrings. + * + * If we do see @a delim, append everything from @from until (excluding) + * @a delim to @a into, advance @c mIter to skip @a delim, and return @c + * true. + * + * If we do not see @a delim, do not alter @a into or @c mIter and return + * @c false. Do not pass GO, do not collect $200. + * + * @note The @c false case described above implements normal getTokens() + * treatment of an unmatched open quote: treat the quote character as if + * escaped, that is, simply collect it as part of the current token. Other + * plausible behaviors directly affect the way getTokens() deals with an + * unmatched quote: e.g. throwing an exception to treat it as an error, or + * assuming a close quote beyond end of string (in which case return @c + * true). + */ + virtual bool collect_until(string_type& into, const_iterator from, T delim) + { + const_iterator found = std::find(from, mEnd, delim); + // If we didn't find delim, change nothing, just tell caller. + if (found == mEnd) + return false; + // Found delim! Append everything between from and found. + into.append(from, found); + // advance past delim in input + mIter = found + 1; + return true; + } + + const_iterator mIter, mEnd; }; /// InString subclass that handles escape characters @@ -1013,177 +1013,177 @@ template class InEscString: public InString { public: - typedef InString super; - typedef typename super::string_type string_type; - typedef typename super::const_iterator const_iterator; - using super::done; - using super::mIter; - using super::mEnd; - - InEscString(const_iterator b, const_iterator e, const string_type& escapes): - super(b, e), - mEscapes(escapes) - { - // Even though we've already initialized 'mIter' via our base-class - // constructor, set it again to check for initial escape char. - setiter(b); - } - - /// This implementation uses the answer cached by setiter(). - virtual bool escaped() const { return mIsEsc; } - virtual T next() - { - // If we're looking at the escape character of an escape sequence, - // skip that character. This is the one time we can modify 'mIter' - // without using setiter: for this one case we DO NOT CARE if the - // escaped character is itself an escape. - if (mIsEsc) - ++mIter; - // If we were looking at an escape character, this is the escaped - // character; otherwise it's just the next character. - T result(*mIter); - // Advance mIter, checking for escape sequence. - setiter(mIter + 1); - return result; - } - - virtual bool is(T ch) const - { - // Like base-class is(), except that an escaped character matches - // nothing. - return (! done()) && (! mIsEsc) && *mIter == ch; - } - - virtual bool oneof(const string_type& delims) const - { - // Like base-class oneof(), except that an escaped character matches - // nothing. - return (! done()) && (! mIsEsc) && LLStringUtilBase::contains(delims, *mIter); - } - - virtual bool collect_until(string_type& into, const_iterator from, T delim) - { - // Deal with escapes in the characters we collect; that is, an escaped - // character must become just that character without the preceding - // escape. Collect characters in a separate string rather than - // directly appending to 'into' in case we do not find delim, in which - // case we're supposed to leave 'into' unmodified. - string_type collected; - // For scanning purposes, we're going to work directly with 'mIter'. - // Save its current value in case we fail to see delim. - const_iterator save_iter(mIter); - // Okay, set 'mIter', checking for escape. - setiter(from); - while (! done()) - { - // If we see an unescaped delim, stop and report success. - if ((! mIsEsc) && *mIter == delim) - { - // Append collected chars to 'into'. - into.append(collected); - // Don't forget to advance 'mIter' past delim. - setiter(mIter + 1); - return true; - } - // We're not at end, and either we're not looking at delim or it's - // escaped. Collect this character and keep going. - collected.push_back(next()); - } - // Here we hit 'mEnd' without ever seeing delim. Restore mIter and tell - // caller. - setiter(save_iter); - return false; - } + typedef InString super; + typedef typename super::string_type string_type; + typedef typename super::const_iterator const_iterator; + using super::done; + using super::mIter; + using super::mEnd; + + InEscString(const_iterator b, const_iterator e, const string_type& escapes): + super(b, e), + mEscapes(escapes) + { + // Even though we've already initialized 'mIter' via our base-class + // constructor, set it again to check for initial escape char. + setiter(b); + } + + /// This implementation uses the answer cached by setiter(). + virtual bool escaped() const { return mIsEsc; } + virtual T next() + { + // If we're looking at the escape character of an escape sequence, + // skip that character. This is the one time we can modify 'mIter' + // without using setiter: for this one case we DO NOT CARE if the + // escaped character is itself an escape. + if (mIsEsc) + ++mIter; + // If we were looking at an escape character, this is the escaped + // character; otherwise it's just the next character. + T result(*mIter); + // Advance mIter, checking for escape sequence. + setiter(mIter + 1); + return result; + } + + virtual bool is(T ch) const + { + // Like base-class is(), except that an escaped character matches + // nothing. + return (! done()) && (! mIsEsc) && *mIter == ch; + } + + virtual bool oneof(const string_type& delims) const + { + // Like base-class oneof(), except that an escaped character matches + // nothing. + return (! done()) && (! mIsEsc) && LLStringUtilBase::contains(delims, *mIter); + } + + virtual bool collect_until(string_type& into, const_iterator from, T delim) + { + // Deal with escapes in the characters we collect; that is, an escaped + // character must become just that character without the preceding + // escape. Collect characters in a separate string rather than + // directly appending to 'into' in case we do not find delim, in which + // case we're supposed to leave 'into' unmodified. + string_type collected; + // For scanning purposes, we're going to work directly with 'mIter'. + // Save its current value in case we fail to see delim. + const_iterator save_iter(mIter); + // Okay, set 'mIter', checking for escape. + setiter(from); + while (! done()) + { + // If we see an unescaped delim, stop and report success. + if ((! mIsEsc) && *mIter == delim) + { + // Append collected chars to 'into'. + into.append(collected); + // Don't forget to advance 'mIter' past delim. + setiter(mIter + 1); + return true; + } + // We're not at end, and either we're not looking at delim or it's + // escaped. Collect this character and keep going. + collected.push_back(next()); + } + // Here we hit 'mEnd' without ever seeing delim. Restore mIter and tell + // caller. + setiter(save_iter); + return false; + } private: - void setiter(const_iterator i) - { - mIter = i; - - // Every time we change 'mIter', set 'mIsEsc' to be able to repetitively - // answer escaped() without having to rescan 'mEscapes'. mIsEsc caches - // contains(mEscapes, *mIter). - - // We're looking at an escaped char if we're not already at end (that - // is, *mIter is even meaningful); if *mIter is in fact one of the - // specified escape characters; and if there's one more character - // following it. That is, if an escape character is the very last - // character of the input string, it loses its special meaning. - mIsEsc = (! done()) && - LLStringUtilBase::contains(mEscapes, *mIter) && - (mIter+1) != mEnd; - } - - const string_type mEscapes; - bool mIsEsc; + void setiter(const_iterator i) + { + mIter = i; + + // Every time we change 'mIter', set 'mIsEsc' to be able to repetitively + // answer escaped() without having to rescan 'mEscapes'. mIsEsc caches + // contains(mEscapes, *mIter). + + // We're looking at an escaped char if we're not already at end (that + // is, *mIter is even meaningful); if *mIter is in fact one of the + // specified escape characters; and if there's one more character + // following it. That is, if an escape character is the very last + // character of the input string, it loses its special meaning. + mIsEsc = (! done()) && + LLStringUtilBase::contains(mEscapes, *mIter) && + (mIter+1) != mEnd; + } + + const string_type mEscapes; + bool mIsEsc; }; /// getTokens() implementation based on InString concept template void getTokens(INSTRING& instr, std::vector& tokens, - const string_type& drop_delims, const string_type& keep_delims, - const string_type& quotes) -{ - // There are times when we want to match either drop_delims or - // keep_delims. Concatenate them up front to speed things up. - string_type all_delims(drop_delims + keep_delims); - // no tokens yet - tokens.clear(); - - // try for another token - while (! instr.done()) - { - // scan past any drop_delims - while (instr.oneof(drop_delims)) - { - // skip this drop_delim - instr.next(); - // but if that was the end of the string, done - if (instr.done()) - return; - } - // found the start of another token: make a slot for it - tokens.push_back(string_type()); - if (instr.oneof(keep_delims)) - { - // *iter is a keep_delim, a token of exactly 1 character. Append - // that character to the new token and proceed. - tokens.back().push_back(instr.next()); - continue; - } - // Here we have a non-delimiter token, which might consist of a mix of - // quoted and unquoted parts. Use bash rules for quoting: you can - // embed a quoted substring in the midst of an unquoted token (e.g. - // ~/"sub dir"/myfile.txt); you can ram two quoted substrings together - // to make a single token (e.g. 'He said, "'"Don't."'"'). We diverge - // from bash in that bash considers an unmatched quote an error. Our - // param signature doesn't allow for errors, so just pretend it's not - // a quote and embed it. - // At this level, keep scanning until we hit the next delimiter of - // either type (drop_delims or keep_delims). - while (! instr.oneof(all_delims)) - { - // If we're looking at an open quote, search forward for - // a close quote, collecting characters along the way. - if (instr.oneof(quotes) && - instr.collect_until(tokens.back(), instr.mIter+1, *instr.mIter)) - { - // collect_until is cleverly designed to do exactly what we - // need here. No further action needed if it returns true. - } - else - { - // Either *iter isn't a quote, or there's no matching close - // quote: in other words, just an ordinary char. Append it to - // current token. - tokens.back().push_back(instr.next()); - } - // having scanned that segment of this token, if we've reached the - // end of the string, we're done - if (instr.done()) - return; - } - } + const string_type& drop_delims, const string_type& keep_delims, + const string_type& quotes) +{ + // There are times when we want to match either drop_delims or + // keep_delims. Concatenate them up front to speed things up. + string_type all_delims(drop_delims + keep_delims); + // no tokens yet + tokens.clear(); + + // try for another token + while (! instr.done()) + { + // scan past any drop_delims + while (instr.oneof(drop_delims)) + { + // skip this drop_delim + instr.next(); + // but if that was the end of the string, done + if (instr.done()) + return; + } + // found the start of another token: make a slot for it + tokens.push_back(string_type()); + if (instr.oneof(keep_delims)) + { + // *iter is a keep_delim, a token of exactly 1 character. Append + // that character to the new token and proceed. + tokens.back().push_back(instr.next()); + continue; + } + // Here we have a non-delimiter token, which might consist of a mix of + // quoted and unquoted parts. Use bash rules for quoting: you can + // embed a quoted substring in the midst of an unquoted token (e.g. + // ~/"sub dir"/myfile.txt); you can ram two quoted substrings together + // to make a single token (e.g. 'He said, "'"Don't."'"'). We diverge + // from bash in that bash considers an unmatched quote an error. Our + // param signature doesn't allow for errors, so just pretend it's not + // a quote and embed it. + // At this level, keep scanning until we hit the next delimiter of + // either type (drop_delims or keep_delims). + while (! instr.oneof(all_delims)) + { + // If we're looking at an open quote, search forward for + // a close quote, collecting characters along the way. + if (instr.oneof(quotes) && + instr.collect_until(tokens.back(), instr.mIter+1, *instr.mIter)) + { + // collect_until is cleverly designed to do exactly what we + // need here. No further action needed if it returns true. + } + else + { + // Either *iter isn't a quote, or there's no matching close + // quote: in other words, just an ordinary char. Append it to + // current token. + tokens.back().push_back(instr.next()); + } + // having scanned that segment of this token, if we've reached the + // end of the string, we're done + if (instr.done()) + return; + } + } } } // namespace LLStringUtilBaseImpl @@ -1191,256 +1191,256 @@ void getTokens(INSTRING& instr, std::vector& tokens, // static template void LLStringUtilBase::getTokens(const string_type& string, std::vector& tokens, - const string_type& drop_delims, const string_type& keep_delims, - const string_type& quotes) + const string_type& drop_delims, const string_type& keep_delims, + const string_type& quotes) { - // Because this overload doesn't support escapes, use simple InString to - // manage input range. - LLStringUtilBaseImpl::InString instring(string.begin(), string.end()); - LLStringUtilBaseImpl::getTokens(instring, tokens, drop_delims, keep_delims, quotes); + // Because this overload doesn't support escapes, use simple InString to + // manage input range. + LLStringUtilBaseImpl::InString instring(string.begin(), string.end()); + LLStringUtilBaseImpl::getTokens(instring, tokens, drop_delims, keep_delims, quotes); } // static template void LLStringUtilBase::getTokens(const string_type& string, std::vector& tokens, - const string_type& drop_delims, const string_type& keep_delims, - const string_type& quotes, const string_type& escapes) -{ - // This overload must deal with escapes. Delegate that to InEscString - // (unless there ARE no escapes). - std::unique_ptr< LLStringUtilBaseImpl::InString > instrp; - if (escapes.empty()) - instrp.reset(new LLStringUtilBaseImpl::InString(string.begin(), string.end())); - else - instrp.reset(new LLStringUtilBaseImpl::InEscString(string.begin(), string.end(), escapes)); - LLStringUtilBaseImpl::getTokens(*instrp, tokens, drop_delims, keep_delims, quotes); + const string_type& drop_delims, const string_type& keep_delims, + const string_type& quotes, const string_type& escapes) +{ + // This overload must deal with escapes. Delegate that to InEscString + // (unless there ARE no escapes). + std::unique_ptr< LLStringUtilBaseImpl::InString > instrp; + if (escapes.empty()) + instrp.reset(new LLStringUtilBaseImpl::InString(string.begin(), string.end())); + else + instrp.reset(new LLStringUtilBaseImpl::InEscString(string.begin(), string.end(), escapes)); + LLStringUtilBaseImpl::getTokens(*instrp, tokens, drop_delims, keep_delims, quotes); } // static -template +template S32 LLStringUtilBase::compareStrings(const T* lhs, const T* rhs) -{ - S32 result; - if( lhs == rhs ) - { - result = 0; - } - else - if ( !lhs || !lhs[0] ) - { - result = ((!rhs || !rhs[0]) ? 0 : 1); - } - else - if ( !rhs || !rhs[0]) - { - result = -1; - } - else - { - result = LLStringOps::collate(lhs, rhs); - } - return result; +{ + S32 result; + if( lhs == rhs ) + { + result = 0; + } + else + if ( !lhs || !lhs[0] ) + { + result = ((!rhs || !rhs[0]) ? 0 : 1); + } + else + if ( !rhs || !rhs[0]) + { + result = -1; + } + else + { + result = LLStringOps::collate(lhs, rhs); + } + return result; } -//static -template +//static +template S32 LLStringUtilBase::compareStrings(const string_type& lhs, const string_type& rhs) { - return LLStringOps::collate(lhs.c_str(), rhs.c_str()); + return LLStringOps::collate(lhs.c_str(), rhs.c_str()); } // static -template +template S32 LLStringUtilBase::compareInsensitive(const T* lhs, const T* rhs ) { - S32 result; - if( lhs == rhs ) - { - result = 0; - } - else - if ( !lhs || !lhs[0] ) - { - result = ((!rhs || !rhs[0]) ? 0 : 1); - } - else - if ( !rhs || !rhs[0] ) - { - result = -1; - } - else - { - string_type lhs_string(lhs); - string_type rhs_string(rhs); - LLStringUtilBase::toUpper(lhs_string); - LLStringUtilBase::toUpper(rhs_string); - result = LLStringOps::collate(lhs_string.c_str(), rhs_string.c_str()); - } - return result; + S32 result; + if( lhs == rhs ) + { + result = 0; + } + else + if ( !lhs || !lhs[0] ) + { + result = ((!rhs || !rhs[0]) ? 0 : 1); + } + else + if ( !rhs || !rhs[0] ) + { + result = -1; + } + else + { + string_type lhs_string(lhs); + string_type rhs_string(rhs); + LLStringUtilBase::toUpper(lhs_string); + LLStringUtilBase::toUpper(rhs_string); + result = LLStringOps::collate(lhs_string.c_str(), rhs_string.c_str()); + } + return result; } -//static -template +//static +template S32 LLStringUtilBase::compareInsensitive(const string_type& lhs, const string_type& rhs) { - string_type lhs_string(lhs); - string_type rhs_string(rhs); - LLStringUtilBase::toUpper(lhs_string); - LLStringUtilBase::toUpper(rhs_string); - return LLStringOps::collate(lhs_string.c_str(), rhs_string.c_str()); + string_type lhs_string(lhs); + string_type rhs_string(rhs); + LLStringUtilBase::toUpper(lhs_string); + LLStringUtilBase::toUpper(rhs_string); + return LLStringOps::collate(lhs_string.c_str(), rhs_string.c_str()); } // Case sensitive comparison with good handling of numbers. Does not use current locale. // a.k.a. strdictcmp() -//static +//static template S32 LLStringUtilBase::compareDict(const string_type& astr, const string_type& bstr) { - const T* a = astr.c_str(); - const T* b = bstr.c_str(); - T ca, cb; - S32 ai, bi, cnt = 0; - S32 bias = 0; - - ca = *(a++); - cb = *(b++); - while( ca && cb ){ - if( bias==0 ){ - if( LLStringOps::isUpper(ca) ){ ca = LLStringOps::toLower(ca); bias--; } - if( LLStringOps::isUpper(cb) ){ cb = LLStringOps::toLower(cb); bias++; } - }else{ - if( LLStringOps::isUpper(ca) ){ ca = LLStringOps::toLower(ca); } - if( LLStringOps::isUpper(cb) ){ cb = LLStringOps::toLower(cb); } - } - if( LLStringOps::isDigit(ca) ){ - if( cnt-->0 ){ - if( cb!=ca ) break; - }else{ - if( !LLStringOps::isDigit(cb) ) break; - for(ai=0; LLStringOps::isDigit(a[ai]); ai++); - for(bi=0; LLStringOps::isDigit(b[bi]); bi++); - if( ai0 ){ + if( cb!=ca ) break; + }else{ + if( !LLStringOps::isDigit(cb) ) break; + for(ai=0; LLStringOps::isDigit(a[ai]); ai++); + for(bi=0; LLStringOps::isDigit(b[bi]); bi++); + if( ai S32 LLStringUtilBase::compareDictInsensitive(const string_type& astr, const string_type& bstr) { - const T* a = astr.c_str(); - const T* b = bstr.c_str(); - T ca, cb; - S32 ai, bi, cnt = 0; - - ca = *(a++); - cb = *(b++); - while( ca && cb ){ - if( LLStringOps::isUpper(ca) ){ ca = LLStringOps::toLower(ca); } - if( LLStringOps::isUpper(cb) ){ cb = LLStringOps::toLower(cb); } - if( LLStringOps::isDigit(ca) ){ - if( cnt-->0 ){ - if( cb!=ca ) break; - }else{ - if( !LLStringOps::isDigit(cb) ) break; - for(ai=0; LLStringOps::isDigit(a[ai]); ai++); - for(bi=0; LLStringOps::isDigit(b[bi]); bi++); - if( ai0 ){ + if( cb!=ca ) break; + }else{ + if( !LLStringOps::isDigit(cb) ) break; + for(ai=0; LLStringOps::isDigit(a[ai]); ai++); + for(bi=0; LLStringOps::isDigit(b[bi]); bi++); + if( ai +// static +template BOOL LLStringUtilBase::precedesDict( const string_type& a, const string_type& b ) { - if( a.size() && b.size() ) - { - return (LLStringUtilBase::compareDict(a.c_str(), b.c_str()) < 0); - } - else - { - return (!b.empty()); - } + if( a.size() && b.size() ) + { + return (LLStringUtilBase::compareDict(a.c_str(), b.c_str()) < 0); + } + else + { + return (!b.empty()); + } } //static -template -void LLStringUtilBase::toUpper(string_type& string) -{ - if( !string.empty() ) - { - std::transform( - string.begin(), - string.end(), - string.begin(), - (T(*)(T)) &LLStringOps::toUpper); - } +template +void LLStringUtilBase::toUpper(string_type& string) +{ + if( !string.empty() ) + { + std::transform( + string.begin(), + string.end(), + string.begin(), + (T(*)(T)) &LLStringOps::toUpper); + } } //static -template +template void LLStringUtilBase::toLower(string_type& string) -{ - if( !string.empty() ) - { - std::transform( - string.begin(), - string.end(), - string.begin(), - (T(*)(T)) &LLStringOps::toLower); - } +{ + if( !string.empty() ) + { + std::transform( + string.begin(), + string.end(), + string.begin(), + (T(*)(T)) &LLStringOps::toLower); + } } //static -template +template void LLStringUtilBase::trimHead(string_type& string) -{ - if( !string.empty() ) - { - size_type i = 0; - while( i < string.length() && LLStringOps::isSpace( string[i] ) ) - { - i++; - } - string.erase(0, i); - } +{ + if( !string.empty() ) + { + size_type i = 0; + while( i < string.length() && LLStringOps::isSpace( string[i] ) ) + { + i++; + } + string.erase(0, i); + } } //static -template +template void LLStringUtilBase::trimTail(string_type& string) -{ - if( string.size() ) - { - size_type len = string.length(); - size_type i = len; - while( i > 0 && LLStringOps::isSpace( string[i-1] ) ) - { - i--; - } - - string.erase( i, len - i ); - } +{ + if( string.size() ) + { + size_type len = string.length(); + size_type i = len; + while( i > 0 && LLStringOps::isSpace( string[i-1] ) ) + { + i--; + } + + string.erase( i, len - i ); + } } @@ -1449,67 +1449,67 @@ void LLStringUtilBase::trimTail(string_type& string) template void LLStringUtilBase::addCRLF(string_type& string) { - const T LF = 10; - const T CR = 13; - - // Count the number of line feeds - size_type count = 0; - size_type len = string.size(); - size_type i; - for( i = 0; i < len; i++ ) - { - if( string[i] == LF ) - { - count++; - } - } - - // Insert a carriage return before each line feed - if( count ) - { - size_type size = len + count; - T *t = new T[size]; - size_type j = 0; - for( i = 0; i < len; ++i ) - { - if( string[i] == LF ) - { - t[j] = CR; - ++j; - } - t[j] = string[i]; - ++j; - } - - string.assign(t, size); - delete[] t; - } + const T LF = 10; + const T CR = 13; + + // Count the number of line feeds + size_type count = 0; + size_type len = string.size(); + size_type i; + for( i = 0; i < len; i++ ) + { + if( string[i] == LF ) + { + count++; + } + } + + // Insert a carriage return before each line feed + if( count ) + { + size_type size = len + count; + T *t = new T[size]; + size_type j = 0; + for( i = 0; i < len; ++i ) + { + if( string[i] == LF ) + { + t[j] = CR; + ++j; + } + t[j] = string[i]; + ++j; + } + + string.assign(t, size); + delete[] t; + } } // Remove all carriage returns //static -template +template void LLStringUtilBase::removeCRLF(string_type& string) { - const T CR = 13; - - size_type cr_count = 0; - size_type len = string.size(); - size_type i; - for( i = 0; i < len - cr_count; i++ ) - { - if( string[i+cr_count] == CR ) - { - cr_count++; - } - - string[i] = string[i+cr_count]; - } - string.erase(i, cr_count); + const T CR = 13; + + size_type cr_count = 0; + size_type len = string.size(); + size_type i; + for( i = 0; i < len - cr_count; i++ ) + { + if( string[i+cr_count] == CR ) + { + cr_count++; + } + + string[i] = string[i+cr_count]; + } + string.erase(i, cr_count); } //static -template +template void LLStringUtilBase::removeWindowsCR(string_type& string) { if (string.empty()) @@ -1538,269 +1538,269 @@ void LLStringUtilBase::removeWindowsCR(string_type& string) template void LLStringUtilBase::replaceChar( string_type& string, T target, T replacement ) { - size_type found_pos = 0; - while( (found_pos = string.find(target, found_pos)) != string_type::npos ) - { - string[found_pos] = replacement; - found_pos++; // avoid infinite defeat if target == replacement - } + size_type found_pos = 0; + while( (found_pos = string.find(target, found_pos)) != string_type::npos ) + { + string[found_pos] = replacement; + found_pos++; // avoid infinite defeat if target == replacement + } } //static -template +template void LLStringUtilBase::replaceString( string_type& string, string_type target, string_type replacement ) { - size_type found_pos = 0; - while( (found_pos = string.find(target, found_pos)) != string_type::npos ) - { - string.replace( found_pos, target.length(), replacement ); - found_pos += replacement.length(); // avoid infinite defeat if replacement contains target - } + size_type found_pos = 0; + while( (found_pos = string.find(target, found_pos)) != string_type::npos ) + { + string.replace( found_pos, target.length(), replacement ); + found_pos += replacement.length(); // avoid infinite defeat if replacement contains target + } } //static -template +template void LLStringUtilBase::replaceNonstandardASCII( string_type& string, T replacement ) { - const char LF = 10; - const S8 MIN = 32; -// const S8 MAX = 127; - - size_type len = string.size(); - for( size_type i = 0; i < len; i++ ) - { - // No need to test MAX < mText[i] because we treat mText[i] as a signed char, - // which has a max value of 127. - if( ( S8(string[i]) < MIN ) && (string[i] != LF) ) - { - string[i] = replacement; - } - } + const char LF = 10; + const S8 MIN = 32; +// const S8 MAX = 127; + + size_type len = string.size(); + for( size_type i = 0; i < len; i++ ) + { + // No need to test MAX < mText[i] because we treat mText[i] as a signed char, + // which has a max value of 127. + if( ( S8(string[i]) < MIN ) && (string[i] != LF) ) + { + string[i] = replacement; + } + } } //static -template +template void LLStringUtilBase::replaceTabsWithSpaces( string_type& str, size_type spaces_per_tab ) { - const T TAB = '\t'; - const T SPACE = ' '; - - string_type out_str; - // Replace tabs with spaces - for (size_type i = 0; i < str.length(); i++) - { - if (str[i] == TAB) - { - for (size_type j = 0; j < spaces_per_tab; j++) - out_str += SPACE; - } - else - { - out_str += str[i]; - } - } - str = out_str; + const T TAB = '\t'; + const T SPACE = ' '; + + string_type out_str; + // Replace tabs with spaces + for (size_type i = 0; i < str.length(); i++) + { + if (str[i] == TAB) + { + for (size_type j = 0; j < spaces_per_tab; j++) + out_str += SPACE; + } + else + { + out_str += str[i]; + } + } + str = out_str; } //static template std::basic_string LLStringUtilBase::capitalize(const string_type& str) { - string_type result(str); - capitalize(result); - return result; + string_type result(str); + capitalize(result); + return result; } //static template void LLStringUtilBase::capitalize(string_type& str) { - if (str.size()) - { - auto last = str[0] = toupper(str[0]); - for (U32 i = 1; i < str.size(); ++i) - { - last = (last == ' ' || last == '-' || last == '_') ? str[i] = toupper(str[i]) : str[i]; - } - } + if (str.size()) + { + auto last = str[0] = toupper(str[0]); + for (U32 i = 1; i < str.size(); ++i) + { + last = (last == ' ' || last == '-' || last == '_') ? str[i] = toupper(str[i]) : str[i]; + } + } } //static -template +template BOOL LLStringUtilBase::containsNonprintable(const string_type& string) { - const char MIN = 32; - BOOL rv = FALSE; - for (size_type i = 0; i < string.size(); i++) - { - if(string[i] < MIN) - { - rv = TRUE; - break; - } - } - return rv; + const char MIN = 32; + BOOL rv = FALSE; + for (size_type i = 0; i < string.size(); i++) + { + if(string[i] < MIN) + { + rv = TRUE; + break; + } + } + return rv; } -// *TODO: reimplement in terms of algorithm +// *TODO: reimplement in terms of algorithm //static -template +template void LLStringUtilBase::stripNonprintable(string_type& string) { - const char MIN = 32; - size_type j = 0; - if (string.empty()) - { - return; - } - size_t src_size = string.size(); - char* c_string = new char[src_size + 1]; - if(c_string == NULL) - { - return; - } - copy(c_string, string.c_str(), src_size+1); - char* write_head = &c_string[0]; - for (size_type i = 0; i < src_size; i++) - { - char* read_head = &string[i]; - write_head = &c_string[j]; - if(!(*read_head < MIN)) - { - *write_head = *read_head; - ++j; - } - } - c_string[j]= '\0'; - string = c_string; - delete []c_string; + const char MIN = 32; + size_type j = 0; + if (string.empty()) + { + return; + } + size_t src_size = string.size(); + char* c_string = new char[src_size + 1]; + if(c_string == NULL) + { + return; + } + copy(c_string, string.c_str(), src_size+1); + char* write_head = &c_string[0]; + for (size_type i = 0; i < src_size; i++) + { + char* read_head = &string[i]; + write_head = &c_string[j]; + if(!(*read_head < MIN)) + { + *write_head = *read_head; + ++j; + } + } + c_string[j]= '\0'; + string = c_string; + delete []c_string; } -// *TODO: reimplement in terms of algorithm +// *TODO: reimplement in terms of algorithm template std::basic_string LLStringUtilBase::quote(const string_type& str, - const string_type& triggers, - const string_type& escape) -{ - size_type len(str.length()); - // If the string is already quoted, assume user knows what s/he's doing. - if (len >= 2 && str[0] == '"' && str[len-1] == '"') - { - return str; - } - - // Not already quoted: do we need to? triggers.empty() is a special case - // meaning "always quote." - if ((! triggers.empty()) && str.find_first_of(triggers) == string_type::npos) - { - // no trigger characters, don't bother quoting - return str; - } - - // For whatever reason, we must quote this string. - string_type result; - result.push_back('"'); - for (typename string_type::const_iterator ci(str.begin()), cend(str.end()); ci != cend; ++ci) - { - if (*ci == '"') - { - result.append(escape); - } - result.push_back(*ci); - } - result.push_back('"'); - return result; + const string_type& triggers, + const string_type& escape) +{ + size_type len(str.length()); + // If the string is already quoted, assume user knows what s/he's doing. + if (len >= 2 && str[0] == '"' && str[len-1] == '"') + { + return str; + } + + // Not already quoted: do we need to? triggers.empty() is a special case + // meaning "always quote." + if ((! triggers.empty()) && str.find_first_of(triggers) == string_type::npos) + { + // no trigger characters, don't bother quoting + return str; + } + + // For whatever reason, we must quote this string. + string_type result; + result.push_back('"'); + for (typename string_type::const_iterator ci(str.begin()), cend(str.end()); ci != cend; ++ci) + { + if (*ci == '"') + { + result.append(escape); + } + result.push_back(*ci); + } + result.push_back('"'); + return result; } -template +template void LLStringUtilBase::_makeASCII(string_type& string) { - // Replace non-ASCII chars with LL_UNKNOWN_CHAR - for (size_type i = 0; i < string.length(); i++) - { - if (string[i] > 0x7f) - { - string[i] = LL_UNKNOWN_CHAR; - } - } + // Replace non-ASCII chars with LL_UNKNOWN_CHAR + for (size_type i = 0; i < string.length(); i++) + { + if (string[i] > 0x7f) + { + string[i] = LL_UNKNOWN_CHAR; + } + } } // static -template +template void LLStringUtilBase::copy( T* dst, const T* src, size_type dst_size ) { - if( dst_size > 0 ) - { - size_type min_len = 0; - if( src ) - { - min_len = llmin( dst_size - 1, strlen( src ) ); /* Flawfinder: ignore */ - memcpy(dst, src, min_len * sizeof(T)); /* Flawfinder: ignore */ - } - dst[min_len] = '\0'; - } + if( dst_size > 0 ) + { + size_type min_len = 0; + if( src ) + { + min_len = llmin( dst_size - 1, strlen( src ) ); /* Flawfinder: ignore */ + memcpy(dst, src, min_len * sizeof(T)); /* Flawfinder: ignore */ + } + dst[min_len] = '\0'; + } } // static -template +template void LLStringUtilBase::copyInto(string_type& dst, const string_type& src, size_type offset) { - if ( offset == dst.length() ) - { - // special case - append to end of string and avoid expensive - // (when strings are large) string manipulations - dst += src; - } - else - { - string_type tail = dst.substr(offset); - - dst = dst.substr(0, offset); - dst += src; - dst += tail; - }; + if ( offset == dst.length() ) + { + // special case - append to end of string and avoid expensive + // (when strings are large) string manipulations + dst += src; + } + else + { + string_type tail = dst.substr(offset); + + dst = dst.substr(0, offset); + dst += src; + dst += tail; + }; } // True if this is the head of s. //static -template -BOOL LLStringUtilBase::isHead( const string_type& string, const T* s ) -{ - if( string.empty() ) - { - // Early exit - return FALSE; - } - else - { - return (strncmp( s, string.c_str(), string.size() ) == 0); - } +template +BOOL LLStringUtilBase::isHead( const string_type& string, const T* s ) +{ + if( string.empty() ) + { + // Early exit + return FALSE; + } + else + { + return (strncmp( s, string.c_str(), string.size() ) == 0); + } } // static -template +template bool LLStringUtilBase::startsWith( - const string_type& string, - const string_type& substr) + const string_type& string, + const string_type& substr) { - if(string.empty() || (substr.empty())) return false; - if (substr.length() > string.length()) return false; - if (0 == string.compare(0, substr.length(), substr)) return true; - return false; + if(string.empty() || (substr.empty())) return false; + if (substr.length() > string.length()) return false; + if (0 == string.compare(0, substr.length(), substr)) return true; + return false; } // static -template +template bool LLStringUtilBase::endsWith( - const string_type& string, - const string_type& substr) -{ - if(string.empty() || (substr.empty())) return false; - size_t sub_len = substr.length(); - size_t str_len = string.length(); - if (sub_len > str_len) return false; - if (0 == string.compare(str_len - sub_len, sub_len, substr)) return true; - return false; + const string_type& string, + const string_type& substr) +{ + if(string.empty() || (substr.empty())) return false; + size_t sub_len = substr.length(); + size_t str_len = string.length(); + if (sub_len > str_len) return false; + if (0 == string.compare(str_len - sub_len, sub_len, substr)) return true; + return false; } // static @@ -1835,187 +1835,187 @@ auto LLStringUtilBase::getenv(const std::string& key, const string_type& dflt } } -template +template BOOL LLStringUtilBase::convertToBOOL(const string_type& string, BOOL& value) { - if( string.empty() ) - { - return FALSE; - } - - string_type temp( string ); - trim(temp); - if( - (temp == "1") || - (temp == "T") || - (temp == "t") || - (temp == "TRUE") || - (temp == "true") || - (temp == "True") ) - { - value = TRUE; - return TRUE; - } - else - if( - (temp == "0") || - (temp == "F") || - (temp == "f") || - (temp == "FALSE") || - (temp == "false") || - (temp == "False") ) - { - value = FALSE; - return TRUE; - } - - return FALSE; + if( string.empty() ) + { + return FALSE; + } + + string_type temp( string ); + trim(temp); + if( + (temp == "1") || + (temp == "T") || + (temp == "t") || + (temp == "TRUE") || + (temp == "true") || + (temp == "True") ) + { + value = TRUE; + return TRUE; + } + else + if( + (temp == "0") || + (temp == "F") || + (temp == "f") || + (temp == "FALSE") || + (temp == "false") || + (temp == "False") ) + { + value = FALSE; + return TRUE; + } + + return FALSE; } -template -BOOL LLStringUtilBase::convertToU8(const string_type& string, U8& value) -{ - S32 value32 = 0; - BOOL success = convertToS32(string, value32); - if( success && (U8_MIN <= value32) && (value32 <= U8_MAX) ) - { - value = (U8) value32; - return TRUE; - } - return FALSE; +template +BOOL LLStringUtilBase::convertToU8(const string_type& string, U8& value) +{ + S32 value32 = 0; + BOOL success = convertToS32(string, value32); + if( success && (U8_MIN <= value32) && (value32 <= U8_MAX) ) + { + value = (U8) value32; + return TRUE; + } + return FALSE; } -template -BOOL LLStringUtilBase::convertToS8(const string_type& string, S8& value) -{ - S32 value32 = 0; - BOOL success = convertToS32(string, value32); - if( success && (S8_MIN <= value32) && (value32 <= S8_MAX) ) - { - value = (S8) value32; - return TRUE; - } - return FALSE; +template +BOOL LLStringUtilBase::convertToS8(const string_type& string, S8& value) +{ + S32 value32 = 0; + BOOL success = convertToS32(string, value32); + if( success && (S8_MIN <= value32) && (value32 <= S8_MAX) ) + { + value = (S8) value32; + return TRUE; + } + return FALSE; } -template -BOOL LLStringUtilBase::convertToS16(const string_type& string, S16& value) -{ - S32 value32 = 0; - BOOL success = convertToS32(string, value32); - if( success && (S16_MIN <= value32) && (value32 <= S16_MAX) ) - { - value = (S16) value32; - return TRUE; - } - return FALSE; +template +BOOL LLStringUtilBase::convertToS16(const string_type& string, S16& value) +{ + S32 value32 = 0; + BOOL success = convertToS32(string, value32); + if( success && (S16_MIN <= value32) && (value32 <= S16_MAX) ) + { + value = (S16) value32; + return TRUE; + } + return FALSE; } -template -BOOL LLStringUtilBase::convertToU16(const string_type& string, U16& value) -{ - S32 value32 = 0; - BOOL success = convertToS32(string, value32); - if( success && (U16_MIN <= value32) && (value32 <= U16_MAX) ) - { - value = (U16) value32; - return TRUE; - } - return FALSE; +template +BOOL LLStringUtilBase::convertToU16(const string_type& string, U16& value) +{ + S32 value32 = 0; + BOOL success = convertToS32(string, value32); + if( success && (U16_MIN <= value32) && (value32 <= U16_MAX) ) + { + value = (U16) value32; + return TRUE; + } + return FALSE; } -template -BOOL LLStringUtilBase::convertToU32(const string_type& string, U32& value) -{ - if( string.empty() ) - { - return FALSE; - } - - string_type temp( string ); - trim(temp); - U32 v; - std::basic_istringstream i_stream((string_type)temp); - if(i_stream >> v) - { - value = v; - return TRUE; - } - return FALSE; +template +BOOL LLStringUtilBase::convertToU32(const string_type& string, U32& value) +{ + if( string.empty() ) + { + return FALSE; + } + + string_type temp( string ); + trim(temp); + U32 v; + std::basic_istringstream i_stream((string_type)temp); + if(i_stream >> v) + { + value = v; + return TRUE; + } + return FALSE; } -template -BOOL LLStringUtilBase::convertToS32(const string_type& string, S32& value) -{ - if( string.empty() ) - { - return FALSE; - } - - string_type temp( string ); - trim(temp); - S32 v; - std::basic_istringstream i_stream((string_type)temp); - if(i_stream >> v) - { - //TODO: figure out overflow and underflow reporting here - //if((LONG_MAX == v) || (LONG_MIN == v)) - //{ - // // Underflow or overflow - // return FALSE; - //} - - value = v; - return TRUE; - } - return FALSE; +template +BOOL LLStringUtilBase::convertToS32(const string_type& string, S32& value) +{ + if( string.empty() ) + { + return FALSE; + } + + string_type temp( string ); + trim(temp); + S32 v; + std::basic_istringstream i_stream((string_type)temp); + if(i_stream >> v) + { + //TODO: figure out overflow and underflow reporting here + //if((LONG_MAX == v) || (LONG_MIN == v)) + //{ + // // Underflow or overflow + // return FALSE; + //} + + value = v; + return TRUE; + } + return FALSE; } -template -BOOL LLStringUtilBase::convertToF32(const string_type& string, F32& value) -{ - F64 value64 = 0.0; - BOOL success = convertToF64(string, value64); - if( success && (-F32_MAX <= value64) && (value64 <= F32_MAX) ) - { - value = (F32) value64; - return TRUE; - } - return FALSE; +template +BOOL LLStringUtilBase::convertToF32(const string_type& string, F32& value) +{ + F64 value64 = 0.0; + BOOL success = convertToF64(string, value64); + if( success && (-F32_MAX <= value64) && (value64 <= F32_MAX) ) + { + value = (F32) value64; + return TRUE; + } + return FALSE; } -template +template BOOL LLStringUtilBase::convertToF64(const string_type& string, F64& value) { - if( string.empty() ) - { - return FALSE; - } - - string_type temp( string ); - trim(temp); - F64 v; - std::basic_istringstream i_stream((string_type)temp); - if(i_stream >> v) - { - //TODO: figure out overflow and underflow reporting here - //if( ((-HUGE_VAL == v) || (HUGE_VAL == v))) ) - //{ - // // Underflow or overflow - // return FALSE; - //} - - value = v; - return TRUE; - } - return FALSE; + if( string.empty() ) + { + return FALSE; + } + + string_type temp( string ); + trim(temp); + F64 v; + std::basic_istringstream i_stream((string_type)temp); + if(i_stream >> v) + { + //TODO: figure out overflow and underflow reporting here + //if( ((-HUGE_VAL == v) || (HUGE_VAL == v))) ) + //{ + // // Underflow or overflow + // return FALSE; + //} + + value = v; + return TRUE; + } + return FALSE; } -template +template void LLStringUtilBase::truncate(string_type& string, size_type count) { - size_type cur_size = string.size(); - string.resize(count < cur_size ? count : cur_size); + size_type cur_size = string.size(); + string.resize(count < cur_size ? count : cur_size); } // The good thing about *declaration* macros, vs. usage macros, is that now diff --git a/indra/llcommon/llstringtable.cpp b/indra/llcommon/llstringtable.cpp index 92a5e777a6..d28e1e2219 100644 --- a/indra/llcommon/llstringtable.cpp +++ b/indra/llcommon/llstringtable.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llstringtable.cpp * @brief The LLStringTable class provides a _fast_ method for finding * unique copies of strings. @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -35,101 +35,101 @@ LLStringTable gStringTable(32768); LLStringTableEntry::LLStringTableEntry(const char *str) : mString(NULL), mCount(1) { - // Copy string - U32 length = (U32)strlen(str) + 1; /*Flawfinder: ignore*/ - length = llmin(length, MAX_STRINGS_LENGTH); - mString = new char[length]; - strncpy(mString, str, length); /*Flawfinder: ignore*/ - mString[length - 1] = 0; + // Copy string + U32 length = (U32)strlen(str) + 1; /*Flawfinder: ignore*/ + length = llmin(length, MAX_STRINGS_LENGTH); + mString = new char[length]; + strncpy(mString, str, length); /*Flawfinder: ignore*/ + mString[length - 1] = 0; } LLStringTableEntry::~LLStringTableEntry() { - delete [] mString; - mCount = 0; + delete [] mString; + mCount = 0; } LLStringTable::LLStringTable(int tablesize) : mUniqueEntries(0) { - S32 i; - if (!tablesize) - tablesize = 4096; // some arbitrary default - // Make sure tablesize is power of 2 - for (i = 31; i>0; i--) - { - if (tablesize & (1<= (3<<(i-1))) - tablesize = (1<<(i+1)); - else - tablesize = (1<0; i--) + { + if (tablesize & (1<= (3<<(i-1))) + tablesize = (1<<(i+1)); + else + tablesize = (1<>24); - retval = retval & (~x); - str++; - } + while (*str) + { + retval = (retval<<4) + *str; + U32 x = (retval & 0xf0000000); + if (x) retval = retval ^ (x>>24); + retval = retval & (~x); + str++; + } #endif - return (retval & (max_entries-1)); // max_entries is gauranteed to be power of 2 + return (retval & (max_entries-1)); // max_entries is gauranteed to be power of 2 } char* LLStringTable::checkString(const std::string& str) { - return checkString(str.c_str()); + return checkString(str.c_str()); } char* LLStringTable::checkString(const char *str) @@ -137,11 +137,11 @@ char* LLStringTable::checkString(const char *str) LLStringTableEntry* entry = checkStringEntry(str); if (entry) { - return entry->mString; + return entry->mString; } else { - return NULL; + return NULL; } } @@ -152,51 +152,51 @@ LLStringTableEntry* LLStringTable::checkStringEntry(const std::string& str) LLStringTableEntry* LLStringTable::checkStringEntry(const char *str) { - if (str) - { - char *ret_val; - U32 hash_value = hash_my_string(str, mMaxEntries); + if (str) + { + char *ret_val; + U32 hash_value = hash_my_string(str, mMaxEntries); #if STRING_TABLE_HASH_MAP - LLStringTableEntry *entry; + LLStringTableEntry *entry; #if 1 // Microsoft - string_hash_t::iterator lower = mStringHash.lower_bound(hash_value); - string_hash_t::iterator upper = mStringHash.upper_bound(hash_value); + string_hash_t::iterator lower = mStringHash.lower_bound(hash_value); + string_hash_t::iterator upper = mStringHash.upper_bound(hash_value); #else // stlport - std::pair P = mStringHash.equal_range(hash_value); - string_hash_t::iterator lower = P.first; - string_hash_t::iterator upper = P.second; + std::pair P = mStringHash.equal_range(hash_value); + string_hash_t::iterator lower = P.first; + string_hash_t::iterator upper = P.second; #endif - for (string_hash_t::iterator iter = lower; iter != upper; iter++) - { - entry = iter->second; - ret_val = entry->mString; - if (!strncmp(ret_val, str, MAX_STRINGS_LENGTH)) - { - return entry; - } - } + for (string_hash_t::iterator iter = lower; iter != upper; iter++) + { + entry = iter->second; + ret_val = entry->mString; + if (!strncmp(ret_val, str, MAX_STRINGS_LENGTH)) + { + return entry; + } + } #else - string_list_t *strlist = mStringList[hash_value]; - if (strlist) - { - for (LLStringTableEntry* entry : *strlist) - { - ret_val = entry->mString; - if (!strncmp(ret_val, str, MAX_STRINGS_LENGTH)) - { - return entry; - } - } - } + string_list_t *strlist = mStringList[hash_value]; + if (strlist) + { + for (LLStringTableEntry* entry : *strlist) + { + ret_val = entry->mString; + if (!strncmp(ret_val, str, MAX_STRINGS_LENGTH)) + { + return entry; + } + } + } #endif - } - return NULL; + } + return NULL; } char* LLStringTable::addString(const std::string& str) { - //RN: safe to use temporary c_str since string is copied - return addString(str.c_str()); + //RN: safe to use temporary c_str since string is copied + return addString(str.c_str()); } char* LLStringTable::addString(const char *str) @@ -205,11 +205,11 @@ char* LLStringTable::addString(const char *str) LLStringTableEntry* entry = addStringEntry(str); if (entry) { - return entry->mString; + return entry->mString; } else { - return NULL; + return NULL; } } @@ -220,132 +220,132 @@ LLStringTableEntry* LLStringTable::addStringEntry(const std::string& str) LLStringTableEntry* LLStringTable::addStringEntry(const char *str) { - if (str) - { - char *ret_val = NULL; - U32 hash_value = hash_my_string(str, mMaxEntries); + if (str) + { + char *ret_val = NULL; + U32 hash_value = hash_my_string(str, mMaxEntries); #if STRING_TABLE_HASH_MAP - LLStringTableEntry *entry; + LLStringTableEntry *entry; #if 1 // Microsoft - string_hash_t::iterator lower = mStringHash.lower_bound(hash_value); - string_hash_t::iterator upper = mStringHash.upper_bound(hash_value); + string_hash_t::iterator lower = mStringHash.lower_bound(hash_value); + string_hash_t::iterator upper = mStringHash.upper_bound(hash_value); #else // stlport - std::pair P = mStringHash.equal_range(hash_value); - string_hash_t::iterator lower = P.first; - string_hash_t::iterator upper = P.second; + std::pair P = mStringHash.equal_range(hash_value); + string_hash_t::iterator lower = P.first; + string_hash_t::iterator upper = P.second; #endif - for (string_hash_t::iterator iter = lower; iter != upper; iter++) - { - entry = iter->second; - ret_val = entry->mString; - if (!strncmp(ret_val, str, MAX_STRINGS_LENGTH)) - { - entry->incCount(); - return entry; - } - } + for (string_hash_t::iterator iter = lower; iter != upper; iter++) + { + entry = iter->second; + ret_val = entry->mString; + if (!strncmp(ret_val, str, MAX_STRINGS_LENGTH)) + { + entry->incCount(); + return entry; + } + } - // not found, so add! - LLStringTableEntry* newentry = new LLStringTableEntry(str); - ret_val = newentry->mString; - mStringHash.insert(string_hash_t::value_type(hash_value, newentry)); + // not found, so add! + LLStringTableEntry* newentry = new LLStringTableEntry(str); + ret_val = newentry->mString; + mStringHash.insert(string_hash_t::value_type(hash_value, newentry)); #else - string_list_t *strlist = mStringList[hash_value]; + string_list_t *strlist = mStringList[hash_value]; - if (strlist) - { - for (LLStringTableEntry* entry : *strlist) - { - ret_val = entry->mString; - if (!strncmp(ret_val, str, MAX_STRINGS_LENGTH)) - { - entry->incCount(); - return entry; - } - } - } - else - { - mStringList[hash_value] = new string_list_t; - strlist = mStringList[hash_value]; - } + if (strlist) + { + for (LLStringTableEntry* entry : *strlist) + { + ret_val = entry->mString; + if (!strncmp(ret_val, str, MAX_STRINGS_LENGTH)) + { + entry->incCount(); + return entry; + } + } + } + else + { + mStringList[hash_value] = new string_list_t; + strlist = mStringList[hash_value]; + } - // not found, so add! - LLStringTableEntry *newentry = new LLStringTableEntry(str); - //ret_val = newentry->mString; - strlist->push_front(newentry); + // not found, so add! + LLStringTableEntry *newentry = new LLStringTableEntry(str); + //ret_val = newentry->mString; + strlist->push_front(newentry); #endif - mUniqueEntries++; - return newentry; - } - else - { - return NULL; - } + mUniqueEntries++; + return newentry; + } + else + { + return NULL; + } } void LLStringTable::removeString(const char *str) { - if (str) - { - char *ret_val; - U32 hash_value = hash_my_string(str, mMaxEntries); + if (str) + { + char *ret_val; + U32 hash_value = hash_my_string(str, mMaxEntries); #if STRING_TABLE_HASH_MAP - { - LLStringTableEntry *entry; + { + LLStringTableEntry *entry; #if 1 // Microsoft - string_hash_t::iterator lower = mStringHash.lower_bound(hash_value); - string_hash_t::iterator upper = mStringHash.upper_bound(hash_value); + string_hash_t::iterator lower = mStringHash.lower_bound(hash_value); + string_hash_t::iterator upper = mStringHash.upper_bound(hash_value); #else // stlport - std::pair P = mStringHash.equal_range(hash_value); - string_hash_t::iterator lower = P.first; - string_hash_t::iterator upper = P.second; + std::pair P = mStringHash.equal_range(hash_value); + string_hash_t::iterator lower = P.first; + string_hash_t::iterator upper = P.second; #endif - for (string_hash_t::iterator iter = lower; iter != upper; iter++) - { - entry = iter->second; - ret_val = entry->mString; - if (!strncmp(ret_val, str, MAX_STRINGS_LENGTH)) - { - if (!entry->decCount()) - { - mUniqueEntries--; - if (mUniqueEntries < 0) - { - LL_ERRS() << "LLStringTable:removeString trying to remove too many strings!" << LL_ENDL; - } - delete iter->second; - mStringHash.erase(iter); - } - return; - } - } - } + for (string_hash_t::iterator iter = lower; iter != upper; iter++) + { + entry = iter->second; + ret_val = entry->mString; + if (!strncmp(ret_val, str, MAX_STRINGS_LENGTH)) + { + if (!entry->decCount()) + { + mUniqueEntries--; + if (mUniqueEntries < 0) + { + LL_ERRS() << "LLStringTable:removeString trying to remove too many strings!" << LL_ENDL; + } + delete iter->second; + mStringHash.erase(iter); + } + return; + } + } + } #else - string_list_t *strlist = mStringList[hash_value]; + string_list_t *strlist = mStringList[hash_value]; - if (strlist) - { - for (LLStringTableEntry* entry : *strlist) - { - ret_val = entry->mString; - if (!strncmp(ret_val, str, MAX_STRINGS_LENGTH)) - { - if (!entry->decCount()) - { - mUniqueEntries--; - if (mUniqueEntries < 0) - { - LL_ERRS() << "LLStringTable:removeString trying to remove too many strings!" << LL_ENDL; - } - strlist->remove(entry); - delete entry; - } - return; - } - } - } + if (strlist) + { + for (LLStringTableEntry* entry : *strlist) + { + ret_val = entry->mString; + if (!strncmp(ret_val, str, MAX_STRINGS_LENGTH)) + { + if (!entry->decCount()) + { + mUniqueEntries--; + if (mUniqueEntries < 0) + { + LL_ERRS() << "LLStringTable:removeString trying to remove too many strings!" << LL_ENDL; + } + strlist->remove(entry); + delete entry; + } + return; + } + } + } #endif - } + } } diff --git a/indra/llcommon/llstringtable.h b/indra/llcommon/llstringtable.h index 0a292c8bac..e41701ce9c 100644 --- a/indra/llcommon/llstringtable.h +++ b/indra/llcommon/llstringtable.h @@ -1,4 +1,4 @@ -/** +/** * @file llstringtable.h * @brief The LLStringTable class provides a _fast_ method for finding * unique copies of strings. @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -47,48 +47,48 @@ const U32 MAX_STRINGS_LENGTH = 256; class LL_COMMON_API LLStringTableEntry { public: - LLStringTableEntry(const char *str); - ~LLStringTableEntry(); + LLStringTableEntry(const char *str); + ~LLStringTableEntry(); - void incCount() { mCount++; } - BOOL decCount() { return --mCount; } + void incCount() { mCount++; } + BOOL decCount() { return --mCount; } - char *mString; - S32 mCount; + char *mString; + S32 mCount; }; class LL_COMMON_API LLStringTable { public: - LLStringTable(int tablesize); - ~LLStringTable(); - - char *checkString(const char *str); - char *checkString(const std::string& str); - LLStringTableEntry *checkStringEntry(const char *str); - LLStringTableEntry *checkStringEntry(const std::string& str); - - char *addString(const char *str); - char *addString(const std::string& str); - LLStringTableEntry *addStringEntry(const char *str); - LLStringTableEntry *addStringEntry(const std::string& str); - void removeString(const char *str); - - S32 mMaxEntries; - S32 mUniqueEntries; - + LLStringTable(int tablesize); + ~LLStringTable(); + + char *checkString(const char *str); + char *checkString(const std::string& str); + LLStringTableEntry *checkStringEntry(const char *str); + LLStringTableEntry *checkStringEntry(const std::string& str); + + char *addString(const char *str); + char *addString(const std::string& str); + LLStringTableEntry *addStringEntry(const char *str); + LLStringTableEntry *addStringEntry(const std::string& str); + void removeString(const char *str); + + S32 mMaxEntries; + S32 mUniqueEntries; + #if STRING_TABLE_HASH_MAP #if LL_WINDOWS - typedef std::hash_multimap string_hash_t; + typedef std::hash_multimap string_hash_t; #else - typedef __gnu_cxx::hash_multimap string_hash_t; + typedef __gnu_cxx::hash_multimap string_hash_t; #endif - string_hash_t mStringHash; + string_hash_t mStringHash; #else - typedef std::list string_list_t; - typedef string_list_t * string_list_ptr_t; - string_list_ptr_t *mStringList; -#endif + typedef std::list string_list_t; + typedef string_list_t * string_list_ptr_t; + string_list_ptr_t *mStringList; +#endif }; extern LL_COMMON_API LLStringTable gStringTable; @@ -104,105 +104,105 @@ typedef const std::string* LLStdStringHandle; class LL_COMMON_API LLStdStringTable { public: - LLStdStringTable(S32 tablesize = 0) - { - if (tablesize == 0) - { - tablesize = 256; // default - } - // Make sure tablesize is power of 2 - for (S32 i = 31; i>0; i--) - { - if (tablesize & (1<= (3<<(i-1))) - tablesize = (1<<(i+1)); - else - tablesize = (1<0; i--) + { + if (tablesize & (1<= (3<<(i-1))) + tablesize = (1<<(i+1)); + else + tablesize = (1< > string_set_t; - string_set_t* mStringList; // [mTableSize] + S32 mTableSize; + typedef std::set > string_set_t; + string_set_t* mStringList; // [mTableSize] }; diff --git a/indra/llcommon/llsys.cpp b/indra/llcommon/llsys.cpp index 42400e90af..47868b3fca 100644 --- a/indra/llcommon/llsys.cpp +++ b/indra/llcommon/llsys.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llsys.cpp * @brief Implementation of the basic system query functions. * * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -59,26 +59,26 @@ using namespace llsd; #if LL_WINDOWS -# include "llwin32headerslean.h" +# include "llwin32headerslean.h" # include // GetPerformanceInfo() et al. -# include +# include #elif LL_DARWIN # include "llsys_objc.h" -# include -# include -# include -# include -# include +# include +# include +# include +# include +# include # include -# include -# include -# include -# include +# include +# include +# include +# include #elif LL_LINUX -# include -# include -# include -# include +# include +# include +# include +# include # include const char MEMINFO_FILE[] = "/proc/meminfo"; # include @@ -96,132 +96,132 @@ static const F32 MEM_INFO_THROTTLE = 20; static const F32 MEM_INFO_WINDOW = 10*60; LLOSInfo::LLOSInfo() : - mMajorVer(0), mMinorVer(0), mBuild(0), mOSVersionString("") + mMajorVer(0), mMinorVer(0), mBuild(0), mOSVersionString("") { #if LL_WINDOWS if (IsWindows10OrGreater()) - { - mMajorVer = 10; - mMinorVer = 0; - mOSStringSimple = "Microsoft Windows 10 "; - } - else if (IsWindows8Point1OrGreater()) - { - mMajorVer = 6; - mMinorVer = 3; - if (IsWindowsServer()) - { - mOSStringSimple = "Windows Server 2012 R2 "; - } - else - { - mOSStringSimple = "Microsoft Windows 8.1 "; - } - } - else if (IsWindows8OrGreater()) - { - mMajorVer = 6; - mMinorVer = 2; - if (IsWindowsServer()) - { - mOSStringSimple = "Windows Server 2012 "; - } - else - { - mOSStringSimple = "Microsoft Windows 8 "; - } - } - else if (IsWindows7SP1OrGreater()) - { - mMajorVer = 6; - mMinorVer = 1; - if (IsWindowsServer()) - { - mOSStringSimple = "Windows Server 2008 R2 SP1 "; - } - else - { - mOSStringSimple = "Microsoft Windows 7 SP1 "; - } - } - else if (IsWindows7OrGreater()) - { - mMajorVer = 6; - mMinorVer = 1; - if (IsWindowsServer()) - { - mOSStringSimple = "Windows Server 2008 R2 "; - } - else - { - mOSStringSimple = "Microsoft Windows 7 "; - } - } - else if (IsWindowsVistaSP2OrGreater()) - { - mMajorVer = 6; - mMinorVer = 0; - if (IsWindowsServer()) - { - mOSStringSimple = "Windows Server 2008 SP2 "; - } - else - { - mOSStringSimple = "Microsoft Windows Vista SP2 "; - } - } - else - { - mOSStringSimple = "Unsupported Windows version "; - } - - ///get native system info if available.. - typedef void (WINAPI *PGNSI)(LPSYSTEM_INFO); ///function pointer for loading GetNativeSystemInfo - SYSTEM_INFO si; //System Info object file contains architecture info - PGNSI pGNSI; //pointer object - ZeroMemory(&si, sizeof(SYSTEM_INFO)); //zero out the memory in information - pGNSI = (PGNSI)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "GetNativeSystemInfo"); //load kernel32 get function - if (NULL != pGNSI) //check if it has failed - pGNSI(&si); //success - else - GetSystemInfo(&si); //if it fails get regular system info - //(Warning: If GetSystemInfo it may result in incorrect information in a WOW64 machine, if the kernel fails to load) - - // Try calling GetVersionEx using the OSVERSIONINFOEX structure. - OSVERSIONINFOEX osvi; - ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX)); - osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); - if (GetVersionEx((OSVERSIONINFO *)&osvi)) - { - mBuild = osvi.dwBuildNumber & 0xffff; - } - else - { - // If OSVERSIONINFOEX doesn't work, try OSVERSIONINFO. - osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); - if (GetVersionEx((OSVERSIONINFO *)&osvi)) - { - mBuild = osvi.dwBuildNumber & 0xffff; - } - } - - S32 ubr = 0; // Windows 10 Update Build Revision, can be retrieved from a registry - if (mMajorVer == 10) - { - DWORD cbData(sizeof(DWORD)); - DWORD data(0); - HKEY key; - BOOL ret_code = RegOpenKeyExW(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"), 0, KEY_READ, &key); - if (ERROR_SUCCESS == ret_code) - { - ret_code = RegQueryValueExW(key, L"UBR", 0, NULL, reinterpret_cast(&data), &cbData); - if (ERROR_SUCCESS == ret_code) - { - ubr = data; - } - } + { + mMajorVer = 10; + mMinorVer = 0; + mOSStringSimple = "Microsoft Windows 10 "; + } + else if (IsWindows8Point1OrGreater()) + { + mMajorVer = 6; + mMinorVer = 3; + if (IsWindowsServer()) + { + mOSStringSimple = "Windows Server 2012 R2 "; + } + else + { + mOSStringSimple = "Microsoft Windows 8.1 "; + } + } + else if (IsWindows8OrGreater()) + { + mMajorVer = 6; + mMinorVer = 2; + if (IsWindowsServer()) + { + mOSStringSimple = "Windows Server 2012 "; + } + else + { + mOSStringSimple = "Microsoft Windows 8 "; + } + } + else if (IsWindows7SP1OrGreater()) + { + mMajorVer = 6; + mMinorVer = 1; + if (IsWindowsServer()) + { + mOSStringSimple = "Windows Server 2008 R2 SP1 "; + } + else + { + mOSStringSimple = "Microsoft Windows 7 SP1 "; + } + } + else if (IsWindows7OrGreater()) + { + mMajorVer = 6; + mMinorVer = 1; + if (IsWindowsServer()) + { + mOSStringSimple = "Windows Server 2008 R2 "; + } + else + { + mOSStringSimple = "Microsoft Windows 7 "; + } + } + else if (IsWindowsVistaSP2OrGreater()) + { + mMajorVer = 6; + mMinorVer = 0; + if (IsWindowsServer()) + { + mOSStringSimple = "Windows Server 2008 SP2 "; + } + else + { + mOSStringSimple = "Microsoft Windows Vista SP2 "; + } + } + else + { + mOSStringSimple = "Unsupported Windows version "; + } + + ///get native system info if available.. + typedef void (WINAPI *PGNSI)(LPSYSTEM_INFO); ///function pointer for loading GetNativeSystemInfo + SYSTEM_INFO si; //System Info object file contains architecture info + PGNSI pGNSI; //pointer object + ZeroMemory(&si, sizeof(SYSTEM_INFO)); //zero out the memory in information + pGNSI = (PGNSI)GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "GetNativeSystemInfo"); //load kernel32 get function + if (NULL != pGNSI) //check if it has failed + pGNSI(&si); //success + else + GetSystemInfo(&si); //if it fails get regular system info + //(Warning: If GetSystemInfo it may result in incorrect information in a WOW64 machine, if the kernel fails to load) + + // Try calling GetVersionEx using the OSVERSIONINFOEX structure. + OSVERSIONINFOEX osvi; + ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX)); + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); + if (GetVersionEx((OSVERSIONINFO *)&osvi)) + { + mBuild = osvi.dwBuildNumber & 0xffff; + } + else + { + // If OSVERSIONINFOEX doesn't work, try OSVERSIONINFO. + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + if (GetVersionEx((OSVERSIONINFO *)&osvi)) + { + mBuild = osvi.dwBuildNumber & 0xffff; + } + } + + S32 ubr = 0; // Windows 10 Update Build Revision, can be retrieved from a registry + if (mMajorVer == 10) + { + DWORD cbData(sizeof(DWORD)); + DWORD data(0); + HKEY key; + BOOL ret_code = RegOpenKeyExW(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"), 0, KEY_READ, &key); + if (ERROR_SUCCESS == ret_code) + { + ret_code = RegQueryValueExW(key, L"UBR", 0, NULL, reinterpret_cast(&data), &cbData); + if (ERROR_SUCCESS == ret_code) + { + ubr = data; + } + } if (mBuild >= 22000) { @@ -251,315 +251,315 @@ LLOSInfo::LLOSInfo() : mOSStringSimple += "32-bit "; } - mOSString = mOSStringSimple; - if (mBuild > 0) - { - mOSString += llformat("(Build %d", mBuild); - if (ubr > 0) - { - mOSString += llformat(".%d", ubr); - } - mOSString += ")"; - } + mOSString = mOSStringSimple; + if (mBuild > 0) + { + mOSString += llformat("(Build %d", mBuild); + if (ubr > 0) + { + mOSString += llformat(".%d", ubr); + } + mOSString += ")"; + } - LLStringUtil::trim(mOSStringSimple); - LLStringUtil::trim(mOSString); + LLStringUtil::trim(mOSStringSimple); + LLStringUtil::trim(mOSString); #elif LL_DARWIN - - // Initialize mOSStringSimple to something like: - // "Mac OS X 10.6.7" - { - const char * DARWIN_PRODUCT_NAME = "Mac OS X"; - - int64_t major_version, minor_version, bugfix_version = 0; - - if (LLGetDarwinOSInfo(major_version, minor_version, bugfix_version)) - { - mMajorVer = major_version; - mMinorVer = minor_version; - mBuild = bugfix_version; - - std::stringstream os_version_string; - os_version_string << DARWIN_PRODUCT_NAME << " " << mMajorVer << "." << mMinorVer << "." << mBuild; - - // Put it in the OS string we are compiling - mOSStringSimple.append(os_version_string.str()); - } - else - { - mOSStringSimple.append("Unable to collect OS info"); - } - } - - // Initialize mOSString to something like: - // "Mac OS X 10.6.7 Darwin Kernel Version 10.7.0: Sat Jan 29 15:17:16 PST 2011; root:xnu-1504.9.37~1/RELEASE_I386 i386" - struct utsname un; - if(uname(&un) != -1) - { - mOSString = mOSStringSimple; - mOSString.append(" "); - mOSString.append(un.sysname); - mOSString.append(" "); - mOSString.append(un.release); - mOSString.append(" "); - mOSString.append(un.version); - mOSString.append(" "); - mOSString.append(un.machine); - } - else - { - mOSString = mOSStringSimple; - } - + + // Initialize mOSStringSimple to something like: + // "Mac OS X 10.6.7" + { + const char * DARWIN_PRODUCT_NAME = "Mac OS X"; + + int64_t major_version, minor_version, bugfix_version = 0; + + if (LLGetDarwinOSInfo(major_version, minor_version, bugfix_version)) + { + mMajorVer = major_version; + mMinorVer = minor_version; + mBuild = bugfix_version; + + std::stringstream os_version_string; + os_version_string << DARWIN_PRODUCT_NAME << " " << mMajorVer << "." << mMinorVer << "." << mBuild; + + // Put it in the OS string we are compiling + mOSStringSimple.append(os_version_string.str()); + } + else + { + mOSStringSimple.append("Unable to collect OS info"); + } + } + + // Initialize mOSString to something like: + // "Mac OS X 10.6.7 Darwin Kernel Version 10.7.0: Sat Jan 29 15:17:16 PST 2011; root:xnu-1504.9.37~1/RELEASE_I386 i386" + struct utsname un; + if(uname(&un) != -1) + { + mOSString = mOSStringSimple; + mOSString.append(" "); + mOSString.append(un.sysname); + mOSString.append(" "); + mOSString.append(un.release); + mOSString.append(" "); + mOSString.append(un.version); + mOSString.append(" "); + mOSString.append(un.machine); + } + else + { + mOSString = mOSStringSimple; + } + #elif LL_LINUX - - struct utsname un; - if(uname(&un) != -1) - { - mOSStringSimple.append(un.sysname); - mOSStringSimple.append(" "); - mOSStringSimple.append(un.release); - - mOSString = mOSStringSimple; - mOSString.append(" "); - mOSString.append(un.version); - mOSString.append(" "); - mOSString.append(un.machine); - - // Simplify 'Simple' - std::string ostype = mOSStringSimple.substr(0, mOSStringSimple.find_first_of(" ", 0)); - if (ostype == "Linux") - { - // Only care about major and minor Linux versions, truncate at second '.' - std::string::size_type idx1 = mOSStringSimple.find_first_of(".", 0); - std::string::size_type idx2 = (idx1 != std::string::npos) ? mOSStringSimple.find_first_of(".", idx1+1) : std::string::npos; - std::string simple = mOSStringSimple.substr(0, idx2); - if (simple.length() > 0) - mOSStringSimple = simple; - } - } - else - { - mOSStringSimple.append("Unable to collect OS info"); - mOSString = mOSStringSimple; - } - - const char OS_VERSION_MATCH_EXPRESSION[] = "([0-9]+)\\.([0-9]+)(\\.([0-9]+))?"; - boost::regex os_version_parse(OS_VERSION_MATCH_EXPRESSION); - boost::smatch matched; - - std::string glibc_version(gnu_get_libc_version()); - if ( ll_regex_match(glibc_version, matched, os_version_parse) ) - { - LL_INFOS("AppInit") << "Using glibc version '" << glibc_version << "' as OS version" << LL_ENDL; - - std::string version_value; - - if ( matched[1].matched ) // Major version - { - version_value.assign(matched[1].first, matched[1].second); - if (sscanf(version_value.c_str(), "%d", &mMajorVer) != 1) - { - LL_WARNS("AppInit") << "failed to parse major version '" << version_value << "' as a number" << LL_ENDL; - } - } - else - { - LL_ERRS("AppInit") - << "OS version regex '" << OS_VERSION_MATCH_EXPRESSION - << "' returned true, but major version [1] did not match" - << LL_ENDL; - } - - if ( matched[2].matched ) // Minor version - { - version_value.assign(matched[2].first, matched[2].second); - if (sscanf(version_value.c_str(), "%d", &mMinorVer) != 1) - { - LL_ERRS("AppInit") << "failed to parse minor version '" << version_value << "' as a number" << LL_ENDL; - } - } - else - { - LL_ERRS("AppInit") - << "OS version regex '" << OS_VERSION_MATCH_EXPRESSION - << "' returned true, but minor version [1] did not match" - << LL_ENDL; - } - - if ( matched[4].matched ) // Build version (optional) - note that [3] includes the '.' - { - version_value.assign(matched[4].first, matched[4].second); - if (sscanf(version_value.c_str(), "%d", &mBuild) != 1) - { - LL_ERRS("AppInit") << "failed to parse build version '" << version_value << "' as a number" << LL_ENDL; - } - } - else - { - LL_INFOS("AppInit") - << "OS build version not provided; using zero" - << LL_ENDL; - } - } - else - { - LL_WARNS("AppInit") << "glibc version '" << glibc_version << "' cannot be parsed to three numbers; using all zeros" << LL_ENDL; - } + + struct utsname un; + if(uname(&un) != -1) + { + mOSStringSimple.append(un.sysname); + mOSStringSimple.append(" "); + mOSStringSimple.append(un.release); + + mOSString = mOSStringSimple; + mOSString.append(" "); + mOSString.append(un.version); + mOSString.append(" "); + mOSString.append(un.machine); + + // Simplify 'Simple' + std::string ostype = mOSStringSimple.substr(0, mOSStringSimple.find_first_of(" ", 0)); + if (ostype == "Linux") + { + // Only care about major and minor Linux versions, truncate at second '.' + std::string::size_type idx1 = mOSStringSimple.find_first_of(".", 0); + std::string::size_type idx2 = (idx1 != std::string::npos) ? mOSStringSimple.find_first_of(".", idx1+1) : std::string::npos; + std::string simple = mOSStringSimple.substr(0, idx2); + if (simple.length() > 0) + mOSStringSimple = simple; + } + } + else + { + mOSStringSimple.append("Unable to collect OS info"); + mOSString = mOSStringSimple; + } + + const char OS_VERSION_MATCH_EXPRESSION[] = "([0-9]+)\\.([0-9]+)(\\.([0-9]+))?"; + boost::regex os_version_parse(OS_VERSION_MATCH_EXPRESSION); + boost::smatch matched; + + std::string glibc_version(gnu_get_libc_version()); + if ( ll_regex_match(glibc_version, matched, os_version_parse) ) + { + LL_INFOS("AppInit") << "Using glibc version '" << glibc_version << "' as OS version" << LL_ENDL; + + std::string version_value; + + if ( matched[1].matched ) // Major version + { + version_value.assign(matched[1].first, matched[1].second); + if (sscanf(version_value.c_str(), "%d", &mMajorVer) != 1) + { + LL_WARNS("AppInit") << "failed to parse major version '" << version_value << "' as a number" << LL_ENDL; + } + } + else + { + LL_ERRS("AppInit") + << "OS version regex '" << OS_VERSION_MATCH_EXPRESSION + << "' returned true, but major version [1] did not match" + << LL_ENDL; + } + + if ( matched[2].matched ) // Minor version + { + version_value.assign(matched[2].first, matched[2].second); + if (sscanf(version_value.c_str(), "%d", &mMinorVer) != 1) + { + LL_ERRS("AppInit") << "failed to parse minor version '" << version_value << "' as a number" << LL_ENDL; + } + } + else + { + LL_ERRS("AppInit") + << "OS version regex '" << OS_VERSION_MATCH_EXPRESSION + << "' returned true, but minor version [1] did not match" + << LL_ENDL; + } + + if ( matched[4].matched ) // Build version (optional) - note that [3] includes the '.' + { + version_value.assign(matched[4].first, matched[4].second); + if (sscanf(version_value.c_str(), "%d", &mBuild) != 1) + { + LL_ERRS("AppInit") << "failed to parse build version '" << version_value << "' as a number" << LL_ENDL; + } + } + else + { + LL_INFOS("AppInit") + << "OS build version not provided; using zero" + << LL_ENDL; + } + } + else + { + LL_WARNS("AppInit") << "glibc version '" << glibc_version << "' cannot be parsed to three numbers; using all zeros" << LL_ENDL; + } #else - - struct utsname un; - if(uname(&un) != -1) - { - mOSStringSimple.append(un.sysname); - mOSStringSimple.append(" "); - mOSStringSimple.append(un.release); - - mOSString = mOSStringSimple; - mOSString.append(" "); - mOSString.append(un.version); - mOSString.append(" "); - mOSString.append(un.machine); - - // Simplify 'Simple' - std::string ostype = mOSStringSimple.substr(0, mOSStringSimple.find_first_of(" ", 0)); - if (ostype == "Linux") - { - // Only care about major and minor Linux versions, truncate at second '.' - std::string::size_type idx1 = mOSStringSimple.find_first_of(".", 0); - std::string::size_type idx2 = (idx1 != std::string::npos) ? mOSStringSimple.find_first_of(".", idx1+1) : std::string::npos; - std::string simple = mOSStringSimple.substr(0, idx2); - if (simple.length() > 0) - mOSStringSimple = simple; - } - } - else - { - mOSStringSimple.append("Unable to collect OS info"); - mOSString = mOSStringSimple; - } + + struct utsname un; + if(uname(&un) != -1) + { + mOSStringSimple.append(un.sysname); + mOSStringSimple.append(" "); + mOSStringSimple.append(un.release); + + mOSString = mOSStringSimple; + mOSString.append(" "); + mOSString.append(un.version); + mOSString.append(" "); + mOSString.append(un.machine); + + // Simplify 'Simple' + std::string ostype = mOSStringSimple.substr(0, mOSStringSimple.find_first_of(" ", 0)); + if (ostype == "Linux") + { + // Only care about major and minor Linux versions, truncate at second '.' + std::string::size_type idx1 = mOSStringSimple.find_first_of(".", 0); + std::string::size_type idx2 = (idx1 != std::string::npos) ? mOSStringSimple.find_first_of(".", idx1+1) : std::string::npos; + std::string simple = mOSStringSimple.substr(0, idx2); + if (simple.length() > 0) + mOSStringSimple = simple; + } + } + else + { + mOSStringSimple.append("Unable to collect OS info"); + mOSString = mOSStringSimple; + } #endif - std::stringstream dotted_version_string; - dotted_version_string << mMajorVer << "." << mMinorVer << "." << mBuild; - mOSVersionString.append(dotted_version_string.str()); + std::stringstream dotted_version_string; + dotted_version_string << mMajorVer << "." << mMinorVer << "." << mBuild; + mOSVersionString.append(dotted_version_string.str()); - mOSBitness = is64Bit() ? 64 : 32; - LL_INFOS("LLOSInfo") << "OS bitness: " << mOSBitness << LL_ENDL; + mOSBitness = is64Bit() ? 64 : 32; + LL_INFOS("LLOSInfo") << "OS bitness: " << mOSBitness << LL_ENDL; } #ifndef LL_WINDOWS // static long LLOSInfo::getMaxOpenFiles() { - const long OPEN_MAX_GUESS = 256; + const long OPEN_MAX_GUESS = 256; -#ifdef OPEN_MAX - static long open_max = OPEN_MAX; +#ifdef OPEN_MAX + static long open_max = OPEN_MAX; #else - static long open_max = 0; + static long open_max = 0; #endif - if (0 == open_max) - { - // First time through. - errno = 0; - if ( (open_max = sysconf(_SC_OPEN_MAX)) < 0) - { - if (0 == errno) - { - // Indeterminate. - open_max = OPEN_MAX_GUESS; - } - else - { - LL_ERRS() << "LLOSInfo::getMaxOpenFiles: sysconf error for _SC_OPEN_MAX" << LL_ENDL; - } - } - } - return open_max; + if (0 == open_max) + { + // First time through. + errno = 0; + if ( (open_max = sysconf(_SC_OPEN_MAX)) < 0) + { + if (0 == errno) + { + // Indeterminate. + open_max = OPEN_MAX_GUESS; + } + else + { + LL_ERRS() << "LLOSInfo::getMaxOpenFiles: sysconf error for _SC_OPEN_MAX" << LL_ENDL; + } + } + } + return open_max; } #endif void LLOSInfo::stream(std::ostream& s) const { - s << mOSString; + s << mOSString; } const std::string& LLOSInfo::getOSString() const { - return mOSString; + return mOSString; } const std::string& LLOSInfo::getOSStringSimple() const { - return mOSStringSimple; + return mOSStringSimple; } const std::string& LLOSInfo::getOSVersionString() const { - return mOSVersionString; + return mOSVersionString; } const S32 LLOSInfo::getOSBitness() const { - return mOSBitness; + return mOSBitness; } //static U32 LLOSInfo::getProcessVirtualSizeKB() { - U32 virtual_size = 0; + U32 virtual_size = 0; #if LL_LINUX -# define STATUS_SIZE 2048 - LLFILE* status_filep = LLFile::fopen("/proc/self/status", "rb"); - if (status_filep) - { - S32 numRead = 0; - char buff[STATUS_SIZE]; /* Flawfinder: ignore */ - - size_t nbytes = fread(buff, 1, STATUS_SIZE-1, status_filep); - buff[nbytes] = '\0'; - - // All these guys return numbers in KB - char *memp = strstr(buff, "VmSize:"); - if (memp) - { - numRead += sscanf(memp, "%*s %u", &virtual_size); - } - fclose(status_filep); - } +# define STATUS_SIZE 2048 + LLFILE* status_filep = LLFile::fopen("/proc/self/status", "rb"); + if (status_filep) + { + S32 numRead = 0; + char buff[STATUS_SIZE]; /* Flawfinder: ignore */ + + size_t nbytes = fread(buff, 1, STATUS_SIZE-1, status_filep); + buff[nbytes] = '\0'; + + // All these guys return numbers in KB + char *memp = strstr(buff, "VmSize:"); + if (memp) + { + numRead += sscanf(memp, "%*s %u", &virtual_size); + } + fclose(status_filep); + } #endif - return virtual_size; + return virtual_size; } //static U32 LLOSInfo::getProcessResidentSizeKB() { - U32 resident_size = 0; + U32 resident_size = 0; #if LL_LINUX - LLFILE* status_filep = LLFile::fopen("/proc/self/status", "rb"); - if (status_filep != NULL) - { - S32 numRead = 0; - char buff[STATUS_SIZE]; /* Flawfinder: ignore */ - - size_t nbytes = fread(buff, 1, STATUS_SIZE-1, status_filep); - buff[nbytes] = '\0'; - - // All these guys return numbers in KB - char *memp = strstr(buff, "VmRSS:"); - if (memp) - { - numRead += sscanf(memp, "%*s %u", &resident_size); - } - fclose(status_filep); - } + LLFILE* status_filep = LLFile::fopen("/proc/self/status", "rb"); + if (status_filep != NULL) + { + S32 numRead = 0; + char buff[STATUS_SIZE]; /* Flawfinder: ignore */ + + size_t nbytes = fread(buff, 1, STATUS_SIZE-1, status_filep); + buff[nbytes] = '\0'; + + // All these guys return numbers in KB + char *memp = strstr(buff, "VmRSS:"); + if (memp) + { + numRead += sscanf(memp, "%*s %u", &resident_size); + } + fclose(status_filep); + } #endif - return resident_size; + return resident_size; } //static @@ -577,34 +577,34 @@ bool LLOSInfo::is64Bit() #endif #else // ! LL_WINDOWS // we only build a 64-bit mac viewer and currently we don't build for linux at all - return true; + return true; #endif } LLCPUInfo::LLCPUInfo() { - std::ostringstream out; - LLProcessorInfo proc; - // proc.WriteInfoTextFile("procInfo.txt"); - mHasSSE = proc.hasSSE(); - mHasSSE2 = proc.hasSSE2(); + std::ostringstream out; + LLProcessorInfo proc; + // proc.WriteInfoTextFile("procInfo.txt"); + mHasSSE = proc.hasSSE(); + mHasSSE2 = proc.hasSSE2(); mHasSSE3 = proc.hasSSE3(); mHasSSE3S = proc.hasSSE3S(); mHasSSE41 = proc.hasSSE41(); mHasSSE42 = proc.hasSSE42(); mHasSSE4a = proc.hasSSE4a(); - mHasAltivec = proc.hasAltivec(); - mCPUMHz = (F64)proc.getCPUFrequency(); - mFamily = proc.getCPUFamilyName(); - mCPUString = "Unknown"; - - out << proc.getCPUBrandName(); - if (200 < mCPUMHz && mCPUMHz < 10000) // *NOTE: cpu speed is often way wrong, do a sanity check - { - out << " (" << mCPUMHz << " MHz)"; - } - mCPUString = out.str(); - LLStringUtil::trim(mCPUString); + mHasAltivec = proc.hasAltivec(); + mCPUMHz = (F64)proc.getCPUFrequency(); + mFamily = proc.getCPUFamilyName(); + mCPUString = "Unknown"; + + out << proc.getCPUBrandName(); + if (200 < mCPUMHz && mCPUMHz < 10000) // *NOTE: cpu speed is often way wrong, do a sanity check + { + out << " (" << mCPUMHz << " MHz)"; + } + mCPUString = out.str(); + LLStringUtil::trim(mCPUString); if (mHasSSE) { @@ -638,17 +638,17 @@ LLCPUInfo::LLCPUInfo() bool LLCPUInfo::hasAltivec() const { - return mHasAltivec; + return mHasAltivec; } bool LLCPUInfo::hasSSE() const { - return mHasSSE; + return mHasSSE; } bool LLCPUInfo::hasSSE2() const { - return mHasSSE2; + return mHasSSE2; } bool LLCPUInfo::hasSSE3() const @@ -678,12 +678,12 @@ bool LLCPUInfo::hasSSE4a() const F64 LLCPUInfo::getMHz() const { - return mCPUMHz; + return mCPUMHz; } std::string LLCPUInfo::getCPUString() const { - return mCPUString; + return mCPUString; } const LLSD& LLCPUInfo::getSSEVersions() const @@ -693,21 +693,21 @@ const LLSD& LLCPUInfo::getSSEVersions() const void LLCPUInfo::stream(std::ostream& s) const { - // gather machine information. - s << LLProcessorInfo().getCPUFeatureDescription(); + // gather machine information. + s << LLProcessorInfo().getCPUFeatureDescription(); - // These are interesting as they reflect our internal view of the - // CPU's attributes regardless of platform - s << "->mHasSSE: " << (U32)mHasSSE << std::endl; - s << "->mHasSSE2: " << (U32)mHasSSE2 << std::endl; + // These are interesting as they reflect our internal view of the + // CPU's attributes regardless of platform + s << "->mHasSSE: " << (U32)mHasSSE << std::endl; + s << "->mHasSSE2: " << (U32)mHasSSE2 << std::endl; s << "->mHasSSE3: " << (U32)mHasSSE3 << std::endl; s << "->mHasSSE3S: " << (U32)mHasSSE3S << std::endl; s << "->mHasSSE41: " << (U32)mHasSSE41 << std::endl; s << "->mHasSSE42: " << (U32)mHasSSE42 << std::endl; s << "->mHasSSE4a: " << (U32)mHasSSE4a << std::endl; - s << "->mHasAltivec: " << (U32)mHasAltivec << std::endl; - s << "->mCPUMHz: " << mCPUMHz << std::endl; - s << "->mCPUString: " << mCPUString << std::endl; + s << "->mHasAltivec: " << (U32)mHasAltivec << std::endl; + s << "->mCPUMHz: " << mCPUMHz << std::endl; + s << "->mCPUString: " << mCPUString << std::endl; } // Helper class for LLMemoryInfo: accumulate stats in the form we store for @@ -715,58 +715,58 @@ void LLCPUInfo::stream(std::ostream& s) const class Stats { public: - Stats(): - mStats(LLSD::emptyMap()) - {} - - // Store every integer type as LLSD::Integer. - template - void add(const LLSD::String& name, const T& value, - typename boost::enable_if >::type* = 0) - { - mStats[name] = LLSD::Integer(value); - } - - // Store every floating-point type as LLSD::Real. - template - void add(const LLSD::String& name, const T& value, - typename boost::enable_if >::type* = 0) - { - mStats[name] = LLSD::Real(value); - } - - // Hope that LLSD::Date values are sufficiently unambiguous. - void add(const LLSD::String& name, const LLSD::Date& value) - { - mStats[name] = value; - } - - LLSD get() const { return mStats; } + Stats(): + mStats(LLSD::emptyMap()) + {} + + // Store every integer type as LLSD::Integer. + template + void add(const LLSD::String& name, const T& value, + typename boost::enable_if >::type* = 0) + { + mStats[name] = LLSD::Integer(value); + } + + // Store every floating-point type as LLSD::Real. + template + void add(const LLSD::String& name, const T& value, + typename boost::enable_if >::type* = 0) + { + mStats[name] = LLSD::Real(value); + } + + // Hope that LLSD::Date values are sufficiently unambiguous. + void add(const LLSD::String& name, const LLSD::Date& value) + { + mStats[name] = value; + } + + LLSD get() const { return mStats; } private: - LLSD mStats; + LLSD mStats; }; LLMemoryInfo::LLMemoryInfo() { - refresh(); + refresh(); } #if LL_WINDOWS static U32Kilobytes LLMemoryAdjustKBResult(U32Kilobytes inKB) { - // Moved this here from llfloaterabout.cpp - - //! \bug - // For some reason, the reported amount of memory is always wrong. - // The original adjustment assumes it's always off by one meg, however - // errors of as much as 2520 KB have been observed in the value - // returned from the GetMemoryStatusEx function. Here we keep the - // original adjustment from llfoaterabout.cpp until this can be - // fixed somehow. - inKB += U32Megabytes(1); - - return inKB; + // Moved this here from llfloaterabout.cpp + + //! \bug + // For some reason, the reported amount of memory is always wrong. + // The original adjustment assumes it's always off by one meg, however + // errors of as much as 2520 KB have been observed in the value + // returned from the GetMemoryStatusEx function. Here we keep the + // original adjustment from llfoaterabout.cpp until this can be + // fixed somehow. + inKB += U32Megabytes(1); + + return inKB; } #endif @@ -788,18 +788,18 @@ U32Kilobytes LLMemoryInfo::getHardwareMemSize() U32Kilobytes LLMemoryInfo::getPhysicalMemoryKB() const { #if LL_WINDOWS - return LLMemoryAdjustKBResult(U32Kilobytes(mStatsMap["Total Physical KB"].asInteger())); + return LLMemoryAdjustKBResult(U32Kilobytes(mStatsMap["Total Physical KB"].asInteger())); #elif LL_DARWIN return getHardwareMemSize(); #elif LL_LINUX - U64 phys = 0; - phys = (U64)(getpagesize()) * (U64)(get_phys_pages()); - return U64Bytes(phys); + U64 phys = 0; + phys = (U64)(getpagesize()) * (U64)(get_phys_pages()); + return U64Bytes(phys); #else - return 0; + return 0; #endif } @@ -808,373 +808,373 @@ U32Kilobytes LLMemoryInfo::getPhysicalMemoryKB() const void LLMemoryInfo::getAvailableMemoryKB(U32Kilobytes& avail_physical_mem_kb, U32Kilobytes& avail_virtual_mem_kb) { #if LL_WINDOWS - // Sigh, this shouldn't be a static method, then we wouldn't have to - // reload this data separately from refresh() - LLSD statsMap(loadStatsMap()); + // Sigh, this shouldn't be a static method, then we wouldn't have to + // reload this data separately from refresh() + LLSD statsMap(loadStatsMap()); - avail_physical_mem_kb = (U32Kilobytes)statsMap["Avail Physical KB"].asInteger(); - avail_virtual_mem_kb = (U32Kilobytes)statsMap["Avail Virtual KB"].asInteger(); + avail_physical_mem_kb = (U32Kilobytes)statsMap["Avail Physical KB"].asInteger(); + avail_virtual_mem_kb = (U32Kilobytes)statsMap["Avail Virtual KB"].asInteger(); #elif LL_DARWIN - // mStatsMap is derived from vm_stat, look for (e.g.) "kb free": - // $ vm_stat - // Mach Virtual Memory Statistics: (page size of 4096 bytes) - // Pages free: 462078. - // Pages active: 142010. - // Pages inactive: 220007. - // Pages wired down: 159552. - // "Translation faults": 220825184. - // Pages copy-on-write: 2104153. - // Pages zero filled: 167034876. - // Pages reactivated: 65153. - // Pageins: 2097212. - // Pageouts: 41759. - // Object cache: 841598 hits of 7629869 lookups (11% hit rate) - avail_physical_mem_kb = (U32Kilobytes)-1 ; - avail_virtual_mem_kb = (U32Kilobytes)-1 ; + // mStatsMap is derived from vm_stat, look for (e.g.) "kb free": + // $ vm_stat + // Mach Virtual Memory Statistics: (page size of 4096 bytes) + // Pages free: 462078. + // Pages active: 142010. + // Pages inactive: 220007. + // Pages wired down: 159552. + // "Translation faults": 220825184. + // Pages copy-on-write: 2104153. + // Pages zero filled: 167034876. + // Pages reactivated: 65153. + // Pageins: 2097212. + // Pageouts: 41759. + // Object cache: 841598 hits of 7629869 lookups (11% hit rate) + avail_physical_mem_kb = (U32Kilobytes)-1 ; + avail_virtual_mem_kb = (U32Kilobytes)-1 ; #elif LL_LINUX - // mStatsMap is derived from MEMINFO_FILE: - // $ cat /proc/meminfo - // MemTotal: 4108424 kB - // MemFree: 1244064 kB - // Buffers: 85164 kB - // Cached: 1990264 kB - // SwapCached: 0 kB - // Active: 1176648 kB - // Inactive: 1427532 kB - // Active(anon): 529152 kB - // Inactive(anon): 15924 kB - // Active(file): 647496 kB - // Inactive(file): 1411608 kB - // Unevictable: 16 kB - // Mlocked: 16 kB - // HighTotal: 3266316 kB - // HighFree: 721308 kB - // LowTotal: 842108 kB - // LowFree: 522756 kB - // SwapTotal: 6384632 kB - // SwapFree: 6384632 kB - // Dirty: 28 kB - // Writeback: 0 kB - // AnonPages: 528820 kB - // Mapped: 89472 kB - // Shmem: 16324 kB - // Slab: 159624 kB - // SReclaimable: 145168 kB - // SUnreclaim: 14456 kB - // KernelStack: 2560 kB - // PageTables: 5560 kB - // NFS_Unstable: 0 kB - // Bounce: 0 kB - // WritebackTmp: 0 kB - // CommitLimit: 8438844 kB - // Committed_AS: 1271596 kB - // VmallocTotal: 122880 kB - // VmallocUsed: 65252 kB - // VmallocChunk: 52356 kB - // HardwareCorrupted: 0 kB - // HugePages_Total: 0 - // HugePages_Free: 0 - // HugePages_Rsvd: 0 - // HugePages_Surp: 0 - // Hugepagesize: 2048 kB - // DirectMap4k: 434168 kB - // DirectMap2M: 477184 kB - // (could also run 'free', but easier to read a file than run a program) - avail_physical_mem_kb = (U32Kilobytes)-1 ; - avail_virtual_mem_kb = (U32Kilobytes)-1 ; + // mStatsMap is derived from MEMINFO_FILE: + // $ cat /proc/meminfo + // MemTotal: 4108424 kB + // MemFree: 1244064 kB + // Buffers: 85164 kB + // Cached: 1990264 kB + // SwapCached: 0 kB + // Active: 1176648 kB + // Inactive: 1427532 kB + // Active(anon): 529152 kB + // Inactive(anon): 15924 kB + // Active(file): 647496 kB + // Inactive(file): 1411608 kB + // Unevictable: 16 kB + // Mlocked: 16 kB + // HighTotal: 3266316 kB + // HighFree: 721308 kB + // LowTotal: 842108 kB + // LowFree: 522756 kB + // SwapTotal: 6384632 kB + // SwapFree: 6384632 kB + // Dirty: 28 kB + // Writeback: 0 kB + // AnonPages: 528820 kB + // Mapped: 89472 kB + // Shmem: 16324 kB + // Slab: 159624 kB + // SReclaimable: 145168 kB + // SUnreclaim: 14456 kB + // KernelStack: 2560 kB + // PageTables: 5560 kB + // NFS_Unstable: 0 kB + // Bounce: 0 kB + // WritebackTmp: 0 kB + // CommitLimit: 8438844 kB + // Committed_AS: 1271596 kB + // VmallocTotal: 122880 kB + // VmallocUsed: 65252 kB + // VmallocChunk: 52356 kB + // HardwareCorrupted: 0 kB + // HugePages_Total: 0 + // HugePages_Free: 0 + // HugePages_Rsvd: 0 + // HugePages_Surp: 0 + // Hugepagesize: 2048 kB + // DirectMap4k: 434168 kB + // DirectMap2M: 477184 kB + // (could also run 'free', but easier to read a file than run a program) + avail_physical_mem_kb = (U32Kilobytes)-1 ; + avail_virtual_mem_kb = (U32Kilobytes)-1 ; #else - //do not know how to collect available memory info for other systems. - //leave it blank here for now. + //do not know how to collect available memory info for other systems. + //leave it blank here for now. - avail_physical_mem_kb = (U32Kilobytes)-1 ; - avail_virtual_mem_kb = (U32Kilobytes)-1 ; + avail_physical_mem_kb = (U32Kilobytes)-1 ; + avail_virtual_mem_kb = (U32Kilobytes)-1 ; #endif } void LLMemoryInfo::stream(std::ostream& s) const { - // We want these memory stats to be easy to grep from the log, along with - // the timestamp. So preface each line with the timestamp and a - // distinctive marker. Without that, we'd have to search the log for the - // introducer line, then read subsequent lines, etc... - std::string pfx(LLError::utcTime() + " "); - - // Max key length - size_t key_width(0); - for (const auto& [key, value] : inMap(mStatsMap)) - { - size_t len(key.length()); - if (len > key_width) - { - key_width = len; - } - } - - // Now stream stats - for (const auto& [key, value] : inMap(mStatsMap)) - { - s << pfx << std::setw(narrow(key_width+1)) << (key + ':') << ' '; - if (value.isInteger()) - s << std::setw(12) << value.asInteger(); - else if (value.isReal()) - s << std::fixed << std::setprecision(1) << value.asReal(); - else if (value.isDate()) - value.asDate().toStream(s); - else - s << value; // just use default LLSD formatting - s << std::endl; - } + // We want these memory stats to be easy to grep from the log, along with + // the timestamp. So preface each line with the timestamp and a + // distinctive marker. Without that, we'd have to search the log for the + // introducer line, then read subsequent lines, etc... + std::string pfx(LLError::utcTime() + " "); + + // Max key length + size_t key_width(0); + for (const auto& [key, value] : inMap(mStatsMap)) + { + size_t len(key.length()); + if (len > key_width) + { + key_width = len; + } + } + + // Now stream stats + for (const auto& [key, value] : inMap(mStatsMap)) + { + s << pfx << std::setw(narrow(key_width+1)) << (key + ':') << ' '; + if (value.isInteger()) + s << std::setw(12) << value.asInteger(); + else if (value.isReal()) + s << std::fixed << std::setprecision(1) << value.asReal(); + else if (value.isDate()) + value.asDate().toStream(s); + else + s << value; // just use default LLSD formatting + s << std::endl; + } } LLSD LLMemoryInfo::getStatsMap() const { - return mStatsMap; + return mStatsMap; } LLMemoryInfo& LLMemoryInfo::refresh() { - LL_PROFILE_ZONE_SCOPED - mStatsMap = loadStatsMap(); + LL_PROFILE_ZONE_SCOPED + mStatsMap = loadStatsMap(); - LL_DEBUGS("LLMemoryInfo") << "Populated mStatsMap:\n"; - LLSDSerialize::toPrettyXML(mStatsMap, LL_CONT); - LL_ENDL; + LL_DEBUGS("LLMemoryInfo") << "Populated mStatsMap:\n"; + LLSDSerialize::toPrettyXML(mStatsMap, LL_CONT); + LL_ENDL; - return *this; + return *this; } LLSD LLMemoryInfo::loadStatsMap() { LL_PROFILE_ZONE_SCOPED; - // This implementation is derived from stream() code (as of 2011-06-29). - Stats stats; + // This implementation is derived from stream() code (as of 2011-06-29). + Stats stats; - // associate timestamp for analysis over time - stats.add("timestamp", LLDate::now()); + // associate timestamp for analysis over time + stats.add("timestamp", LLDate::now()); #if LL_WINDOWS - MEMORYSTATUSEX state; - state.dwLength = sizeof(state); - GlobalMemoryStatusEx(&state); - - DWORDLONG div = 1024; - - stats.add("Percent Memory use", state.dwMemoryLoad/div); - stats.add("Total Physical KB", state.ullTotalPhys/div); - stats.add("Avail Physical KB", state.ullAvailPhys/div); - stats.add("Total page KB", state.ullTotalPageFile/div); - stats.add("Avail page KB", state.ullAvailPageFile/div); - stats.add("Total Virtual KB", state.ullTotalVirtual/div); - stats.add("Avail Virtual KB", state.ullAvailVirtual/div); - - // SL-12122 - Call to GetPerformanceInfo() was removed here. Took - // on order of 10 ms, causing unacceptable frame time spike every - // second, and results were never used. If this is needed in the - // future, must find a way to avoid frame time impact (e.g. move - // to another thread, call much less often). - - PROCESS_MEMORY_COUNTERS_EX pmem; - pmem.cb = sizeof(pmem); - // GetProcessMemoryInfo() is documented to accept either - // PROCESS_MEMORY_COUNTERS* or PROCESS_MEMORY_COUNTERS_EX*, presumably - // using the redundant size info to distinguish. But its prototype - // specifically accepts PROCESS_MEMORY_COUNTERS*, and since this is a - // classic-C API, PROCESS_MEMORY_COUNTERS_EX isn't a subclass. Cast the - // pointer. - GetProcessMemoryInfo(GetCurrentProcess(), PPROCESS_MEMORY_COUNTERS(&pmem), sizeof(pmem)); - - stats.add("Page Fault Count", pmem.PageFaultCount); - stats.add("PeakWorkingSetSize KB", pmem.PeakWorkingSetSize/div); - stats.add("WorkingSetSize KB", pmem.WorkingSetSize/div); - stats.add("QutaPeakPagedPoolUsage KB", pmem.QuotaPeakPagedPoolUsage/div); - stats.add("QuotaPagedPoolUsage KB", pmem.QuotaPagedPoolUsage/div); - stats.add("QuotaPeakNonPagedPoolUsage KB", pmem.QuotaPeakNonPagedPoolUsage/div); - stats.add("QuotaNonPagedPoolUsage KB", pmem.QuotaNonPagedPoolUsage/div); - stats.add("PagefileUsage KB", pmem.PagefileUsage/div); - stats.add("PeakPagefileUsage KB", pmem.PeakPagefileUsage/div); - stats.add("PrivateUsage KB", pmem.PrivateUsage/div); + MEMORYSTATUSEX state; + state.dwLength = sizeof(state); + GlobalMemoryStatusEx(&state); + + DWORDLONG div = 1024; + + stats.add("Percent Memory use", state.dwMemoryLoad/div); + stats.add("Total Physical KB", state.ullTotalPhys/div); + stats.add("Avail Physical KB", state.ullAvailPhys/div); + stats.add("Total page KB", state.ullTotalPageFile/div); + stats.add("Avail page KB", state.ullAvailPageFile/div); + stats.add("Total Virtual KB", state.ullTotalVirtual/div); + stats.add("Avail Virtual KB", state.ullAvailVirtual/div); + + // SL-12122 - Call to GetPerformanceInfo() was removed here. Took + // on order of 10 ms, causing unacceptable frame time spike every + // second, and results were never used. If this is needed in the + // future, must find a way to avoid frame time impact (e.g. move + // to another thread, call much less often). + + PROCESS_MEMORY_COUNTERS_EX pmem; + pmem.cb = sizeof(pmem); + // GetProcessMemoryInfo() is documented to accept either + // PROCESS_MEMORY_COUNTERS* or PROCESS_MEMORY_COUNTERS_EX*, presumably + // using the redundant size info to distinguish. But its prototype + // specifically accepts PROCESS_MEMORY_COUNTERS*, and since this is a + // classic-C API, PROCESS_MEMORY_COUNTERS_EX isn't a subclass. Cast the + // pointer. + GetProcessMemoryInfo(GetCurrentProcess(), PPROCESS_MEMORY_COUNTERS(&pmem), sizeof(pmem)); + + stats.add("Page Fault Count", pmem.PageFaultCount); + stats.add("PeakWorkingSetSize KB", pmem.PeakWorkingSetSize/div); + stats.add("WorkingSetSize KB", pmem.WorkingSetSize/div); + stats.add("QutaPeakPagedPoolUsage KB", pmem.QuotaPeakPagedPoolUsage/div); + stats.add("QuotaPagedPoolUsage KB", pmem.QuotaPagedPoolUsage/div); + stats.add("QuotaPeakNonPagedPoolUsage KB", pmem.QuotaPeakNonPagedPoolUsage/div); + stats.add("QuotaNonPagedPoolUsage KB", pmem.QuotaNonPagedPoolUsage/div); + stats.add("PagefileUsage KB", pmem.PagefileUsage/div); + stats.add("PeakPagefileUsage KB", pmem.PeakPagefileUsage/div); + stats.add("PrivateUsage KB", pmem.PrivateUsage/div); #elif LL_DARWIN - const vm_size_t pagekb(vm_page_size / 1024); - - // - // Collect the vm_stat's - // - - { - vm_statistics64_data_t vmstat; - mach_msg_type_number_t vmstatCount = HOST_VM_INFO64_COUNT; - - if (host_statistics64(mach_host_self(), HOST_VM_INFO64, (host_info64_t) &vmstat, &vmstatCount) != KERN_SUCCESS) - { - LL_WARNS("LLMemoryInfo") << "Unable to collect memory information" << LL_ENDL; - } - else - { - stats.add("Pages free KB", pagekb * vmstat.free_count); - stats.add("Pages active KB", pagekb * vmstat.active_count); - stats.add("Pages inactive KB", pagekb * vmstat.inactive_count); - stats.add("Pages wired KB", pagekb * vmstat.wire_count); - - stats.add("Pages zero fill", vmstat.zero_fill_count); - stats.add("Page reactivations", vmstat.reactivations); - stats.add("Page-ins", vmstat.pageins); - stats.add("Page-outs", vmstat.pageouts); - - stats.add("Faults", vmstat.faults); - stats.add("Faults copy-on-write", vmstat.cow_faults); - - stats.add("Cache lookups", vmstat.lookups); - stats.add("Cache hits", vmstat.hits); - - stats.add("Page purgeable count", vmstat.purgeable_count); - stats.add("Page purges", vmstat.purges); - - stats.add("Page speculative reads", vmstat.speculative_count); - } - } - - // - // Collect the misc task info - // - - { - task_events_info_data_t taskinfo; - unsigned taskinfoSize = sizeof(taskinfo); - - if (task_info(mach_task_self(), TASK_EVENTS_INFO, (task_info_t) &taskinfo, &taskinfoSize) != KERN_SUCCESS) - { - LL_WARNS("LLMemoryInfo") << "Unable to collect task information" << LL_ENDL; - } - else - { - stats.add("Task page-ins", taskinfo.pageins); - stats.add("Task copy-on-write faults", taskinfo.cow_faults); - stats.add("Task messages sent", taskinfo.messages_sent); - stats.add("Task messages received", taskinfo.messages_received); - stats.add("Task mach system call count", taskinfo.syscalls_mach); - stats.add("Task unix system call count", taskinfo.syscalls_unix); - stats.add("Task context switch count", taskinfo.csw); - } - } - - // - // Collect the basic task info - // - - { - mach_task_basic_info_data_t taskinfo; - mach_msg_type_number_t task_count = MACH_TASK_BASIC_INFO_COUNT; - if (task_info(mach_task_self(), MACH_TASK_BASIC_INFO, (task_info_t) &taskinfo, &task_count) != KERN_SUCCESS) - { - LL_WARNS("LLMemoryInfo") << "Unable to collect task information" << LL_ENDL; - } - else - { - stats.add("Basic virtual memory KB", taskinfo.virtual_size / 1024); - stats.add("Basic resident memory KB", taskinfo.resident_size / 1024); - stats.add("Basic max resident memory KB", taskinfo.resident_size_max / 1024); - stats.add("Basic new thread policy", taskinfo.policy); - stats.add("Basic suspend count", taskinfo.suspend_count); - } - } + const vm_size_t pagekb(vm_page_size / 1024); + + // + // Collect the vm_stat's + // + + { + vm_statistics64_data_t vmstat; + mach_msg_type_number_t vmstatCount = HOST_VM_INFO64_COUNT; + + if (host_statistics64(mach_host_self(), HOST_VM_INFO64, (host_info64_t) &vmstat, &vmstatCount) != KERN_SUCCESS) + { + LL_WARNS("LLMemoryInfo") << "Unable to collect memory information" << LL_ENDL; + } + else + { + stats.add("Pages free KB", pagekb * vmstat.free_count); + stats.add("Pages active KB", pagekb * vmstat.active_count); + stats.add("Pages inactive KB", pagekb * vmstat.inactive_count); + stats.add("Pages wired KB", pagekb * vmstat.wire_count); + + stats.add("Pages zero fill", vmstat.zero_fill_count); + stats.add("Page reactivations", vmstat.reactivations); + stats.add("Page-ins", vmstat.pageins); + stats.add("Page-outs", vmstat.pageouts); + + stats.add("Faults", vmstat.faults); + stats.add("Faults copy-on-write", vmstat.cow_faults); + + stats.add("Cache lookups", vmstat.lookups); + stats.add("Cache hits", vmstat.hits); + + stats.add("Page purgeable count", vmstat.purgeable_count); + stats.add("Page purges", vmstat.purges); + + stats.add("Page speculative reads", vmstat.speculative_count); + } + } + + // + // Collect the misc task info + // + + { + task_events_info_data_t taskinfo; + unsigned taskinfoSize = sizeof(taskinfo); + + if (task_info(mach_task_self(), TASK_EVENTS_INFO, (task_info_t) &taskinfo, &taskinfoSize) != KERN_SUCCESS) + { + LL_WARNS("LLMemoryInfo") << "Unable to collect task information" << LL_ENDL; + } + else + { + stats.add("Task page-ins", taskinfo.pageins); + stats.add("Task copy-on-write faults", taskinfo.cow_faults); + stats.add("Task messages sent", taskinfo.messages_sent); + stats.add("Task messages received", taskinfo.messages_received); + stats.add("Task mach system call count", taskinfo.syscalls_mach); + stats.add("Task unix system call count", taskinfo.syscalls_unix); + stats.add("Task context switch count", taskinfo.csw); + } + } + + // + // Collect the basic task info + // + + { + mach_task_basic_info_data_t taskinfo; + mach_msg_type_number_t task_count = MACH_TASK_BASIC_INFO_COUNT; + if (task_info(mach_task_self(), MACH_TASK_BASIC_INFO, (task_info_t) &taskinfo, &task_count) != KERN_SUCCESS) + { + LL_WARNS("LLMemoryInfo") << "Unable to collect task information" << LL_ENDL; + } + else + { + stats.add("Basic virtual memory KB", taskinfo.virtual_size / 1024); + stats.add("Basic resident memory KB", taskinfo.resident_size / 1024); + stats.add("Basic max resident memory KB", taskinfo.resident_size_max / 1024); + stats.add("Basic new thread policy", taskinfo.policy); + stats.add("Basic suspend count", taskinfo.suspend_count); + } + } #elif LL_LINUX - std::ifstream meminfo(MEMINFO_FILE); - if (meminfo.is_open()) - { - // MemTotal: 4108424 kB - // MemFree: 1244064 kB - // Buffers: 85164 kB - // Cached: 1990264 kB - // SwapCached: 0 kB - // Active: 1176648 kB - // Inactive: 1427532 kB - // ... - // VmallocTotal: 122880 kB - // VmallocUsed: 65252 kB - // VmallocChunk: 52356 kB - // HardwareCorrupted: 0 kB - // HugePages_Total: 0 - // HugePages_Free: 0 - // HugePages_Rsvd: 0 - // HugePages_Surp: 0 - // Hugepagesize: 2048 kB - // DirectMap4k: 434168 kB - // DirectMap2M: 477184 kB - - // Intentionally don't pass the boost::no_except flag. This - // boost::regex object is constructed with a string literal, so it - // should be valid every time. If it becomes invalid, we WANT an - // exception, hopefully even before the dev checks in. - boost::regex stat_rx("(.+): +([0-9]+)( kB)?"); - boost::smatch matched; - - std::string line; - while (std::getline(meminfo, line)) - { - LL_DEBUGS("LLMemoryInfo") << line << LL_ENDL; - if (ll_regex_match(line, matched, stat_rx)) - { - // e.g. "MemTotal: 4108424 kB" - LLSD::String key(matched[1].first, matched[1].second); - LLSD::String value_str(matched[2].first, matched[2].second); - LLSD::Integer value(0); - try - { - value = boost::lexical_cast(value_str); - } - catch (const boost::bad_lexical_cast&) - { - LL_WARNS("LLMemoryInfo") << "couldn't parse '" << value_str - << "' in " << MEMINFO_FILE << " line: " - << line << LL_ENDL; - continue; - } - // Store this statistic. - stats.add(key, value); - } - else - { - LL_WARNS("LLMemoryInfo") << "unrecognized " << MEMINFO_FILE << " line: " - << line << LL_ENDL; - } - } - } - else - { - LL_WARNS("LLMemoryInfo") << "Unable to collect memory information" << LL_ENDL; - } + std::ifstream meminfo(MEMINFO_FILE); + if (meminfo.is_open()) + { + // MemTotal: 4108424 kB + // MemFree: 1244064 kB + // Buffers: 85164 kB + // Cached: 1990264 kB + // SwapCached: 0 kB + // Active: 1176648 kB + // Inactive: 1427532 kB + // ... + // VmallocTotal: 122880 kB + // VmallocUsed: 65252 kB + // VmallocChunk: 52356 kB + // HardwareCorrupted: 0 kB + // HugePages_Total: 0 + // HugePages_Free: 0 + // HugePages_Rsvd: 0 + // HugePages_Surp: 0 + // Hugepagesize: 2048 kB + // DirectMap4k: 434168 kB + // DirectMap2M: 477184 kB + + // Intentionally don't pass the boost::no_except flag. This + // boost::regex object is constructed with a string literal, so it + // should be valid every time. If it becomes invalid, we WANT an + // exception, hopefully even before the dev checks in. + boost::regex stat_rx("(.+): +([0-9]+)( kB)?"); + boost::smatch matched; + + std::string line; + while (std::getline(meminfo, line)) + { + LL_DEBUGS("LLMemoryInfo") << line << LL_ENDL; + if (ll_regex_match(line, matched, stat_rx)) + { + // e.g. "MemTotal: 4108424 kB" + LLSD::String key(matched[1].first, matched[1].second); + LLSD::String value_str(matched[2].first, matched[2].second); + LLSD::Integer value(0); + try + { + value = boost::lexical_cast(value_str); + } + catch (const boost::bad_lexical_cast&) + { + LL_WARNS("LLMemoryInfo") << "couldn't parse '" << value_str + << "' in " << MEMINFO_FILE << " line: " + << line << LL_ENDL; + continue; + } + // Store this statistic. + stats.add(key, value); + } + else + { + LL_WARNS("LLMemoryInfo") << "unrecognized " << MEMINFO_FILE << " line: " + << line << LL_ENDL; + } + } + } + else + { + LL_WARNS("LLMemoryInfo") << "Unable to collect memory information" << LL_ENDL; + } #else - LL_WARNS("LLMemoryInfo") << "Unknown system; unable to collect memory information" << LL_ENDL; + LL_WARNS("LLMemoryInfo") << "Unknown system; unable to collect memory information" << LL_ENDL; #endif - return stats.get(); + return stats.get(); } std::ostream& operator<<(std::ostream& s, const LLOSInfo& info) { - info.stream(s); - return s; + info.stream(s); + return s; } std::ostream& operator<<(std::ostream& s, const LLCPUInfo& info) { - info.stream(s); - return s; + info.stream(s); + return s; } std::ostream& operator<<(std::ostream& s, const LLMemoryInfo& info) { - info.stream(s); - return s; + info.stream(s); + return s; } class FrameWatcher @@ -1286,13 +1286,13 @@ public: << " seconds "; } - auto precision = LL_CONT.precision(); + auto precision = LL_CONT.precision(); LL_CONT << std::fixed << std::setprecision(1) << framerate << '\n' << LLMemoryInfo(); - LL_CONT.precision(precision); - LL_CONT << LL_ENDL; + LL_CONT.precision(precision); + LL_CONT << LL_ENDL; return false; } @@ -1321,53 +1321,53 @@ static FrameWatcher sFrameWatcher; BOOL gunzip_file(const std::string& srcfile, const std::string& dstfile) { - std::string tmpfile; - const S32 UNCOMPRESS_BUFFER_SIZE = 32768; - BOOL retval = FALSE; - gzFile src = NULL; - U8 buffer[UNCOMPRESS_BUFFER_SIZE]; - LLFILE *dst = NULL; - S32 bytes = 0; - tmpfile = dstfile + ".t"; + std::string tmpfile; + const S32 UNCOMPRESS_BUFFER_SIZE = 32768; + BOOL retval = FALSE; + gzFile src = NULL; + U8 buffer[UNCOMPRESS_BUFFER_SIZE]; + LLFILE *dst = NULL; + S32 bytes = 0; + tmpfile = dstfile + ".t"; #ifdef LL_WINDOWS llutf16string utf16filename = utf8str_to_utf16str(srcfile); src = gzopen_w(utf16filename.c_str(), "rb"); #else src = gzopen(srcfile.c_str(), "rb"); #endif - if (! src) goto err; - dst = LLFile::fopen(tmpfile, "wb"); /* Flawfinder: ignore */ - if (! dst) goto err; - do - { - bytes = gzread(src, buffer, UNCOMPRESS_BUFFER_SIZE); - size_t nwrit = fwrite(buffer, sizeof(U8), bytes, dst); - if (nwrit < (size_t) bytes) - { - LL_WARNS() << "Short write on " << tmpfile << ": Wrote " << nwrit << " of " << bytes << " bytes." << LL_ENDL; - goto err; - } - } while(gzeof(src) == 0); - fclose(dst); - dst = NULL; - if (LLFile::rename(tmpfile, dstfile) == -1) goto err; /* Flawfinder: ignore */ - retval = TRUE; + if (! src) goto err; + dst = LLFile::fopen(tmpfile, "wb"); /* Flawfinder: ignore */ + if (! dst) goto err; + do + { + bytes = gzread(src, buffer, UNCOMPRESS_BUFFER_SIZE); + size_t nwrit = fwrite(buffer, sizeof(U8), bytes, dst); + if (nwrit < (size_t) bytes) + { + LL_WARNS() << "Short write on " << tmpfile << ": Wrote " << nwrit << " of " << bytes << " bytes." << LL_ENDL; + goto err; + } + } while(gzeof(src) == 0); + fclose(dst); + dst = NULL; + if (LLFile::rename(tmpfile, dstfile) == -1) goto err; /* Flawfinder: ignore */ + retval = TRUE; err: - if (src != NULL) gzclose(src); - if (dst != NULL) fclose(dst); - return retval; + if (src != NULL) gzclose(src); + if (dst != NULL) fclose(dst); + return retval; } BOOL gzip_file(const std::string& srcfile, const std::string& dstfile) { - const S32 COMPRESS_BUFFER_SIZE = 32768; - std::string tmpfile; - BOOL retval = FALSE; - U8 buffer[COMPRESS_BUFFER_SIZE]; - gzFile dst = NULL; - LLFILE *src = NULL; - S32 bytes = 0; - tmpfile = dstfile + ".t"; + const S32 COMPRESS_BUFFER_SIZE = 32768; + std::string tmpfile; + BOOL retval = FALSE; + U8 buffer[COMPRESS_BUFFER_SIZE]; + gzFile dst = NULL; + LLFILE *src = NULL; + S32 bytes = 0; + tmpfile = dstfile + ".t"; #ifdef LL_WINDOWS llutf16string utf16filename = utf8str_to_utf16str(tmpfile); @@ -1376,35 +1376,35 @@ BOOL gzip_file(const std::string& srcfile, const std::string& dstfile) dst = gzopen(tmpfile.c_str(), "wb"); #endif - if (! dst) goto err; - src = LLFile::fopen(srcfile, "rb"); /* Flawfinder: ignore */ - if (! src) goto err; - - while ((bytes = (S32)fread(buffer, sizeof(U8), COMPRESS_BUFFER_SIZE, src)) > 0) - { - if (gzwrite(dst, buffer, bytes) <= 0) - { - LL_WARNS() << "gzwrite failed: " << gzerror(dst, NULL) << LL_ENDL; - goto err; - } - } - - if (ferror(src)) - { - LL_WARNS() << "Error reading " << srcfile << LL_ENDL; - goto err; - } - - gzclose(dst); - dst = NULL; + if (! dst) goto err; + src = LLFile::fopen(srcfile, "rb"); /* Flawfinder: ignore */ + if (! src) goto err; + + while ((bytes = (S32)fread(buffer, sizeof(U8), COMPRESS_BUFFER_SIZE, src)) > 0) + { + if (gzwrite(dst, buffer, bytes) <= 0) + { + LL_WARNS() << "gzwrite failed: " << gzerror(dst, NULL) << LL_ENDL; + goto err; + } + } + + if (ferror(src)) + { + LL_WARNS() << "Error reading " << srcfile << LL_ENDL; + goto err; + } + + gzclose(dst); + dst = NULL; #if LL_WINDOWS - // Rename in windows needs the dstfile to not exist. - LLFile::remove(dstfile); + // Rename in windows needs the dstfile to not exist. + LLFile::remove(dstfile); #endif - if (LLFile::rename(tmpfile, dstfile) == -1) goto err; /* Flawfinder: ignore */ - retval = TRUE; + if (LLFile::rename(tmpfile, dstfile) == -1) goto err; /* Flawfinder: ignore */ + retval = TRUE; err: - if (src != NULL) fclose(src); - if (dst != NULL) gzclose(dst); - return retval; + if (src != NULL) fclose(src); + if (dst != NULL) gzclose(dst); + return retval; } diff --git a/indra/llcommon/llsys.h b/indra/llcommon/llsys.h index 08d4abffa2..5c87ce6bf2 100644 --- a/indra/llcommon/llsys.h +++ b/indra/llcommon/llsys.h @@ -1,25 +1,25 @@ -/** +/** * @file llsys.h * @brief System information debugging classes. * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -43,120 +43,120 @@ class LL_COMMON_API LLOSInfo : public LLSingleton { - LLSINGLETON(LLOSInfo); + LLSINGLETON(LLOSInfo); public: - void stream(std::ostream& s) const; + void stream(std::ostream& s) const; + + const std::string& getOSString() const; + const std::string& getOSStringSimple() const; - const std::string& getOSString() const; - const std::string& getOSStringSimple() const; + const std::string& getOSVersionString() const; - const std::string& getOSVersionString() const; + const S32 getOSBitness() const; - const S32 getOSBitness() const; - - S32 mMajorVer; - S32 mMinorVer; - S32 mBuild; + S32 mMajorVer; + S32 mMinorVer; + S32 mBuild; #ifndef LL_WINDOWS - static long getMaxOpenFiles(); + static long getMaxOpenFiles(); #endif - static bool is64Bit(); + static bool is64Bit(); - static U32 getProcessVirtualSizeKB(); - static U32 getProcessResidentSizeKB(); + static U32 getProcessVirtualSizeKB(); + static U32 getProcessResidentSizeKB(); private: - std::string mOSString; - std::string mOSStringSimple; - std::string mOSVersionString; - S32 mOSBitness; + std::string mOSString; + std::string mOSStringSimple; + std::string mOSVersionString; + S32 mOSBitness; }; class LL_COMMON_API LLCPUInfo { public: - LLCPUInfo(); - void stream(std::ostream& s) const; + LLCPUInfo(); + void stream(std::ostream& s) const; - std::string getCPUString() const; - const LLSD& getSSEVersions() const; + std::string getCPUString() const; + const LLSD& getSSEVersions() const; - bool hasAltivec() const; - bool hasSSE() const; - bool hasSSE2() const; + bool hasAltivec() const; + bool hasSSE() const; + bool hasSSE2() const; bool hasSSE3() const; bool hasSSE3S() const; bool hasSSE41() const; bool hasSSE42() const; bool hasSSE4a() const; - F64 getMHz() const; + F64 getMHz() const; - // Family is "AMD Duron" or "Intel Pentium Pro" - const std::string& getFamily() const { return mFamily; } + // Family is "AMD Duron" or "Intel Pentium Pro" + const std::string& getFamily() const { return mFamily; } private: - bool mHasSSE; - bool mHasSSE2; + bool mHasSSE; + bool mHasSSE2; bool mHasSSE3; bool mHasSSE3S; bool mHasSSE41; bool mHasSSE42; bool mHasSSE4a; - bool mHasAltivec; - F64 mCPUMHz; - std::string mFamily; - std::string mCPUString; + bool mHasAltivec; + F64 mCPUMHz; + std::string mFamily; + std::string mCPUString; LLSD mSSEVersions; }; //============================================================================= // -// CLASS LLMemoryInfo +// CLASS LLMemoryInfo class LL_COMMON_API LLMemoryInfo -/*! @brief Class to query the memory subsystem +/*! @brief Class to query the memory subsystem + + @details + Here's how you use an LLMemoryInfo: - @details - Here's how you use an LLMemoryInfo: - - LLMemoryInfo info; -
LL_INFOS() << info << LL_ENDL; + LLMemoryInfo info; +
LL_INFOS() << info << LL_ENDL; */ { public: - LLMemoryInfo(); ///< Default constructor - void stream(std::ostream& s) const; ///< output text info to s + LLMemoryInfo(); ///< Default constructor + void stream(std::ostream& s) const; ///< output text info to s - U32Kilobytes getPhysicalMemoryKB() const; + U32Kilobytes getPhysicalMemoryKB() const; #if LL_DARWIN static U32Kilobytes getHardwareMemSize(); // Because some Mac linkers won't let us reference extern gSysMemory from a different lib. #endif - //get the available memory infomation in KiloBytes. - static void getAvailableMemoryKB(U32Kilobytes& avail_physical_mem_kb, U32Kilobytes& avail_virtual_mem_kb); + //get the available memory infomation in KiloBytes. + static void getAvailableMemoryKB(U32Kilobytes& avail_physical_mem_kb, U32Kilobytes& avail_virtual_mem_kb); - // Retrieve a map of memory statistics. The keys of the map are platform- - // dependent. The values are in kilobytes to try to avoid integer overflow. - LLSD getStatsMap() const; + // Retrieve a map of memory statistics. The keys of the map are platform- + // dependent. The values are in kilobytes to try to avoid integer overflow. + LLSD getStatsMap() const; - // Re-fetch memory data (as reported by stream() and getStatsMap()) from the - // system. Normally this is fetched at construction time. Return (*this) - // to permit usage of the form: - // @code - // LLMemoryInfo info; - // ... - // info.refresh().getStatsMap(); - // @endcode - LLMemoryInfo& refresh(); + // Re-fetch memory data (as reported by stream() and getStatsMap()) from the + // system. Normally this is fetched at construction time. Return (*this) + // to permit usage of the form: + // @code + // LLMemoryInfo info; + // ... + // info.refresh().getStatsMap(); + // @endcode + LLMemoryInfo& refresh(); private: - // set mStatsMap - static LLSD loadStatsMap(); + // set mStatsMap + static LLSD loadStatsMap(); - // Memory stats for getStatsMap(). - LLSD mStatsMap; + // Memory stats for getStatsMap(). + LLSD mStatsMap; }; diff --git a/indra/llcommon/lltempredirect.cpp b/indra/llcommon/lltempredirect.cpp index ec194c1d29..ee7923e8ca 100644 --- a/indra/llcommon/lltempredirect.cpp +++ b/indra/llcommon/lltempredirect.cpp @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2019-10-31 * @brief Implementation for lltempredirect. - * + * * $LicenseInfo:firstyear=2019&license=viewerlgpl$ * Copyright (c) 2019, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/lltempredirect.h b/indra/llcommon/lltempredirect.h index 33e05dc06b..0ab3575d30 100644 --- a/indra/llcommon/lltempredirect.h +++ b/indra/llcommon/lltempredirect.h @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2019-10-31 * @brief RAII low-level file-descriptor redirection - * + * * $LicenseInfo:firstyear=2019&license=viewerlgpl$ * Copyright (c) 2019, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp index cd4975d9d3..e6b0c03371 100644 --- a/indra/llcommon/llthread.cpp +++ b/indra/llcommon/llthread.cpp @@ -1,24 +1,24 @@ -/** +/** * @file llthread.cpp * * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010-2013, 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$ */ @@ -91,7 +91,7 @@ void set_thread_name( DWORD dwThreadID, const char* threadName) // break; // } // } -// +// //---------------------------------------------------------------------------- namespace { @@ -155,7 +155,7 @@ void LLThread::threadRun() mRecorder = new LLTrace::ThreadRecorder(*LLTrace::get_master_thread_recorder()); // Run the user supplied function - do + do { try { @@ -258,7 +258,7 @@ void LLThread::shutdown() // This thread just wouldn't stop, even though we gave it time //LL_WARNS() << "LLThread::~LLThread() exiting thread before clean exit!" << LL_ENDL; // Put a stake in its heart. (A very hostile method to force a thread to quit) -#if LL_WINDOWS +#if LL_WINDOWS TerminateThread(mNativeHandle, 0); #else pthread_cancel(mNativeHandle); @@ -291,7 +291,7 @@ void LLThread::shutdown() void LLThread::start() { llassert(isStopped()); - + // Set thread state to running mStatus = RUNNING; @@ -319,7 +319,7 @@ void LLThread::pause() { // this will cause the thread to stop execution as soon as checkPause() is called mPaused = 1; // Does not need to be atomic since this is only set/unset from the main thread - } + } } void LLThread::unpause() @@ -355,7 +355,7 @@ void LLThread::checkPause() mDataLock->lock(); // mRunCondition is locked when the thread wakes up } - + mDataLock->unlock(); } @@ -441,7 +441,7 @@ void LLThreadSafeRefCount::cleanupThreadSafeRefCount() delete sMutex; sMutex = NULL; } - + //---------------------------------------------------------------------------- @@ -456,10 +456,10 @@ LLThreadSafeRefCount::LLThreadSafeRefCount(const LLThreadSafeRefCount& src) } LLThreadSafeRefCount::~LLThreadSafeRefCount() -{ +{ if (mRef != 0) { - LL_ERRS() << "deleting referenced object mRef = " << mRef << LL_ENDL; + LL_ERRS() << "deleting referenced object mRef = " << mRef << LL_ENDL; } } diff --git a/indra/llcommon/llthread.h b/indra/llcommon/llthread.h index 9f1c589fcd..e21e6265ea 100644 --- a/indra/llcommon/llthread.h +++ b/indra/llcommon/llthread.h @@ -1,25 +1,25 @@ -/** +/** * @file llthread.h * @brief Base classes for thread, mutex and condition handling. * * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010-2013, 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$ */ @@ -55,21 +55,21 @@ public: LLThread(const std::string& name, apr_pool_t *poolp = NULL); virtual ~LLThread(); // Warning! You almost NEVER want to destroy a thread unless it's in the STOPPED state. virtual void shutdown(); // stops the thread - + bool isQuitting() const { return (QUITTING == mStatus); } bool isStopped() const { return (STOPPED == mStatus) || (CRASHED == mStatus); } - bool isCrashed() const { return (CRASHED == mStatus); } - + bool isCrashed() const { return (CRASHED == mStatus); } + static id_t currentID(); // Return ID of current thread static void yield(); // Static because it can be called by the main thread, which doesn't have an LLThread data structure. - + public: // PAUSE / RESUME functionality. See source code for important usage notes. // Called from MAIN THREAD. void pause(); void unpause(); bool isPaused() { return isStopped() || mPaused == TRUE; } - + // Cause the thread to wake up and check its condition void wake(); @@ -90,11 +90,11 @@ public: // internal state used by LLMutex. You must call this once early // in the running thread to prevent collisions with the main thread. static void registerThreadID(); - + private: bool mPaused; std::thread::native_handle_type mNativeHandle; // for termination in case of issues - + // static function passed to APR thread creation routine void threadRun(); @@ -111,21 +111,21 @@ protected: //a local apr_pool for APRFile operations in this thread. If it exists, LLAPRFile::sAPRFilePoolp should not be used. //Note: this pool is used by APRFile ONLY, do NOT use it for any other purposes. // otherwise it will cause severe memory leaking!!! --bao - LLVolatileAPRPool *mLocalAPRFilePoolp ; + LLVolatileAPRPool *mLocalAPRFilePoolp ; void setQuitting(); - + // virtual function overridden by subclass -- this will be called when the thread runs - virtual void run(void) = 0; - + virtual void run(void) = 0; + // virtual predicate function -- returns true if the thread should wake up, false if it should sleep. virtual bool runCondition(void); // Lock/Unlock Run Condition -- use around modification of any variable used in runCondition() void lockData(); void unlockData(); - - // This is the predicate that decides whether the thread should sleep. + + // This is the predicate that decides whether the thread should sleep. // It should only be called with mDataLock locked, since the virtual runCondition() function may need to access // data structures that are thread-unsafe. bool shouldSleep(void) { return (mStatus == RUNNING) && (isPaused() || (!runCondition())); } diff --git a/indra/llcommon/llthreadlocalstorage.h b/indra/llcommon/llthreadlocalstorage.h index bdd28ec865..151d8a666b 100644 --- a/indra/llcommon/llthreadlocalstorage.h +++ b/indra/llcommon/llthreadlocalstorage.h @@ -1,4 +1,4 @@ -/** +/** * @file llthreadlocalstorage.h * @author Richard * @brief Class wrappers for thread local storage @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -34,18 +34,18 @@ template class LLThreadLocalSingletonPointer { public: - LL_FORCE_INLINE static DERIVED_TYPE* getInstance() - { - return sInstance; - } + LL_FORCE_INLINE static DERIVED_TYPE* getInstance() + { + return sInstance; + } - static void setInstance(DERIVED_TYPE* instance) - { - sInstance = instance; - } + static void setInstance(DERIVED_TYPE* instance) + { + sInstance = instance; + } private: - static thread_local DERIVED_TYPE* sInstance; + static thread_local DERIVED_TYPE* sInstance; }; template diff --git a/indra/llcommon/llthreadsafequeue.cpp b/indra/llcommon/llthreadsafequeue.cpp index bde36999ba..03baca2f0a 100644 --- a/indra/llcommon/llthreadsafequeue.cpp +++ b/indra/llcommon/llthreadsafequeue.cpp @@ -1,24 +1,24 @@ -/** +/** * @file llthread.cpp * * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcommon/llthreadsafequeue.h b/indra/llcommon/llthreadsafequeue.h index f396a71e6f..034e3f7897 100644 --- a/indra/llcommon/llthreadsafequeue.h +++ b/indra/llcommon/llthreadsafequeue.h @@ -1,25 +1,25 @@ -/** +/** * @file llthreadsafequeue.h * @brief Queue protected with mutexes for cross-thread use * * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -44,14 +44,14 @@ // A general queue exception. // class LL_COMMON_API LLThreadSafeQueueError: - public LLException + public LLException { public: - LLThreadSafeQueueError(std::string const & message): - LLException(message) - { - ; // No op. - } + LLThreadSafeQueueError(std::string const & message): + LLException(message) + { + ; // No op. + } }; @@ -59,14 +59,14 @@ public: // An exception raised when blocking operations are interrupted. // class LL_COMMON_API LLThreadSafeQueueInterrupt: - public LLThreadSafeQueueError + public LLThreadSafeQueueError { public: - LLThreadSafeQueueInterrupt(void): - LLThreadSafeQueueError("queue operation interrupted") - { - ; // No op. - } + LLThreadSafeQueueInterrupt(void): + LLThreadSafeQueueError("queue operation interrupted") + { + ; // No op. + } }; /** @@ -78,138 +78,138 @@ template> class LLThreadSafeQueue { public: - typedef ElementT value_type; - - // Limiting the number of pending items prevents unbounded growth of the - // underlying queue. - LLThreadSafeQueue(size_t capacity = 1024); - virtual ~LLThreadSafeQueue() {} - - // Add an element to the queue (will block if the queue has reached - // capacity). - // - // This call will raise an interrupt error if the queue is closed while - // the caller is blocked. - template - void push(T&& element); - // legacy name - void pushFront(ElementT const & element) { return push(element); } - - // Add an element to the queue (will block if the queue has reached - // capacity). Return false if the queue is closed before push is possible. - template - bool pushIfOpen(T&& element); - - // Try to add an element to the queue without blocking. Returns - // true only if the element was actually added. - template - bool tryPush(T&& element); - // legacy name - bool tryPushFront(ElementT const & element) { return tryPush(element); } - - // Try to add an element to the queue, blocking if full but with timeout - // after specified duration. Returns true if the element was added. - // There are potentially two different timeouts involved: how long to try - // to lock the mutex, versus how long to wait for the queue to stop being - // full. Careful settings for each timeout might be orders of magnitude - // apart. However, this method conflates them. - template - bool tryPushFor(const std::chrono::duration& timeout, - T&& element); - // legacy name - template - bool tryPushFrontFor(const std::chrono::duration& timeout, - ElementT const & element) { return tryPushFor(timeout, element); } - - // Try to add an element to the queue, blocking if full but with - // timeout at specified time_point. Returns true if the element was added. - template - bool tryPushUntil(const std::chrono::time_point& until, - T&& element); - // no legacy name because this is a newer method - - // Pop the element at the head of the queue (will block if the queue is - // empty). - // - // This call will raise an interrupt error if the queue is closed while - // the caller is blocked. - ElementT pop(void); - // legacy name - ElementT popBack(void) { return pop(); } - - // Pop an element from the head of the queue if there is one available. - // Returns true only if an element was popped. - bool tryPop(ElementT & element); - // legacy name - bool tryPopBack(ElementT & element) { return tryPop(element); } - - // Pop the element at the head of the queue, blocking if empty, with - // timeout after specified duration. Returns true if an element was popped. - template - bool tryPopFor(const std::chrono::duration& timeout, ElementT& element); - // no legacy name because this is a newer method - - // Pop the element at the head of the queue, blocking if empty, with - // timeout at specified time_point. Returns true if an element was popped. - template - bool tryPopUntil(const std::chrono::time_point& until, - ElementT& element); - // no legacy name because this is a newer method - - // Returns the size of the queue. - size_t size(); + typedef ElementT value_type; + + // Limiting the number of pending items prevents unbounded growth of the + // underlying queue. + LLThreadSafeQueue(size_t capacity = 1024); + virtual ~LLThreadSafeQueue() {} + + // Add an element to the queue (will block if the queue has reached + // capacity). + // + // This call will raise an interrupt error if the queue is closed while + // the caller is blocked. + template + void push(T&& element); + // legacy name + void pushFront(ElementT const & element) { return push(element); } + + // Add an element to the queue (will block if the queue has reached + // capacity). Return false if the queue is closed before push is possible. + template + bool pushIfOpen(T&& element); + + // Try to add an element to the queue without blocking. Returns + // true only if the element was actually added. + template + bool tryPush(T&& element); + // legacy name + bool tryPushFront(ElementT const & element) { return tryPush(element); } + + // Try to add an element to the queue, blocking if full but with timeout + // after specified duration. Returns true if the element was added. + // There are potentially two different timeouts involved: how long to try + // to lock the mutex, versus how long to wait for the queue to stop being + // full. Careful settings for each timeout might be orders of magnitude + // apart. However, this method conflates them. + template + bool tryPushFor(const std::chrono::duration& timeout, + T&& element); + // legacy name + template + bool tryPushFrontFor(const std::chrono::duration& timeout, + ElementT const & element) { return tryPushFor(timeout, element); } + + // Try to add an element to the queue, blocking if full but with + // timeout at specified time_point. Returns true if the element was added. + template + bool tryPushUntil(const std::chrono::time_point& until, + T&& element); + // no legacy name because this is a newer method + + // Pop the element at the head of the queue (will block if the queue is + // empty). + // + // This call will raise an interrupt error if the queue is closed while + // the caller is blocked. + ElementT pop(void); + // legacy name + ElementT popBack(void) { return pop(); } + + // Pop an element from the head of the queue if there is one available. + // Returns true only if an element was popped. + bool tryPop(ElementT & element); + // legacy name + bool tryPopBack(ElementT & element) { return tryPop(element); } + + // Pop the element at the head of the queue, blocking if empty, with + // timeout after specified duration. Returns true if an element was popped. + template + bool tryPopFor(const std::chrono::duration& timeout, ElementT& element); + // no legacy name because this is a newer method + + // Pop the element at the head of the queue, blocking if empty, with + // timeout at specified time_point. Returns true if an element was popped. + template + bool tryPopUntil(const std::chrono::time_point& until, + ElementT& element); + // no legacy name because this is a newer method + + // Returns the size of the queue. + size_t size(); //Returns the capacity of the queue. U32 capacity() { return mCapacity; } - // closes the queue: - // - every subsequent push() call will throw LLThreadSafeQueueInterrupt - // - every subsequent tryPush() call will return false - // - pop() calls will return normally until the queue is drained, then - // every subsequent pop() will throw LLThreadSafeQueueInterrupt - // - tryPop() calls will return normally until the queue is drained, - // then every subsequent tryPop() call will return false - void close(); + // closes the queue: + // - every subsequent push() call will throw LLThreadSafeQueueInterrupt + // - every subsequent tryPush() call will return false + // - pop() calls will return normally until the queue is drained, then + // every subsequent pop() will throw LLThreadSafeQueueInterrupt + // - tryPop() calls will return normally until the queue is drained, + // then every subsequent tryPop() call will return false + void close(); - // producer end: are we prevented from pushing any additional items? - bool isClosed(); - // consumer end: are we done, is the queue entirely drained? - bool done(); + // producer end: are we prevented from pushing any additional items? + bool isClosed(); + // consumer end: are we done, is the queue entirely drained? + bool done(); protected: - typedef QueueT queue_type; - QueueT mStorage; - size_t mCapacity; - bool mClosed; - - boost::fibers::timed_mutex mLock; - typedef std::unique_lock lock_t; - boost::fibers::condition_variable_any mCapacityCond; - boost::fibers::condition_variable_any mEmptyCond; - - enum pop_result { EMPTY, DONE, WAITING, POPPED }; - // implementation logic, suitable for passing to tryLockUntil() - template - pop_result tryPopUntil_(lock_t& lock, - const std::chrono::time_point& until, - ElementT& element); - // if we're able to lock immediately, do so and run the passed callable, - // which must accept lock_t& and return bool - template - bool tryLock(CALLABLE&& callable); - // if we're able to lock before the passed time_point, do so and run the - // passed callable, which must accept lock_t& and return bool - template - bool tryLockUntil(const std::chrono::time_point& until, - CALLABLE&& callable); - // while lock is locked, really push the passed element, if we can - template - bool push_(lock_t& lock, T&& element); - // while lock is locked, really pop the head element, if we can - pop_result pop_(lock_t& lock, ElementT& element); - // Is the current head element ready to pop? We say yes; subclass can - // override as needed. - virtual bool canPop(const ElementT& head) const { return true; } + typedef QueueT queue_type; + QueueT mStorage; + size_t mCapacity; + bool mClosed; + + boost::fibers::timed_mutex mLock; + typedef std::unique_lock lock_t; + boost::fibers::condition_variable_any mCapacityCond; + boost::fibers::condition_variable_any mEmptyCond; + + enum pop_result { EMPTY, DONE, WAITING, POPPED }; + // implementation logic, suitable for passing to tryLockUntil() + template + pop_result tryPopUntil_(lock_t& lock, + const std::chrono::time_point& until, + ElementT& element); + // if we're able to lock immediately, do so and run the passed callable, + // which must accept lock_t& and return bool + template + bool tryLock(CALLABLE&& callable); + // if we're able to lock before the passed time_point, do so and run the + // passed callable, which must accept lock_t& and return bool + template + bool tryLockUntil(const std::chrono::time_point& until, + CALLABLE&& callable); + // while lock is locked, really push the passed element, if we can + template + bool push_(lock_t& lock, T&& element); + // while lock is locked, really pop the head element, if we can + pop_result pop_(lock_t& lock, ElementT& element); + // Is the current head element ready to pop? We say yes; subclass can + // override as needed. + virtual bool canPop(const ElementT& head) const { return true; } }; /***************************************************************************** @@ -426,7 +426,7 @@ LLThreadSafeQueue::pop_(lock_t& lock, ElementT& element) if (mStorage.empty()) return mClosed? DONE : EMPTY; - // If there's a head element, pass it to canPop() to see if it's ready to pop. + // If there's a head element, pass it to canPop() to see if it's ready to pop. if (! canPop(mStorage.front())) return WAITING; diff --git a/indra/llcommon/lltimer.cpp b/indra/llcommon/lltimer.cpp index 1a99ac2886..6f74bf3fc8 100644 --- a/indra/llcommon/lltimer.cpp +++ b/indra/llcommon/lltimer.cpp @@ -1,25 +1,25 @@ -/** +/** * @file lltimer.cpp - * @brief Cross-platform objects for doing timing + * @brief Cross-platform objects for doing timing * * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -34,12 +34,12 @@ #include #if LL_WINDOWS -# include "llwin32headerslean.h" +# include "llwin32headerslean.h" #elif LL_LINUX || LL_DARWIN # include -# include -#else -# error "architecture not supported" +# include +#else +# error "architecture not supported" #endif // @@ -83,7 +83,7 @@ U32 micro_sleep(U64 us, U32 max_yields) { // max_yields is unused; just fiddle with it to avoid warnings. max_yields = 0; - ms_sleep((U32)(us / 1000)); + ms_sleep((U32)(us / 1000)); return 0; } @@ -118,43 +118,43 @@ void ms_sleep(U32 ms) #elif LL_LINUX || LL_DARWIN static void _sleep_loop(struct timespec& thiswait) { - struct timespec nextwait; - bool sleep_more = false; - - do { - int result = nanosleep(&thiswait, &nextwait); - - // check if sleep was interrupted by a signal; unslept - // remainder was written back into 't' and we just nanosleep - // again. - sleep_more = (result == -1 && EINTR == errno); - - if (sleep_more) - { - if ( nextwait.tv_sec > thiswait.tv_sec || - (nextwait.tv_sec == thiswait.tv_sec && - nextwait.tv_nsec >= thiswait.tv_nsec) ) - { - // if the remaining time isn't actually going - // down then we're being shafted by low clock - // resolution - manually massage the sleep time - // downward. - if (nextwait.tv_nsec > 1000000) { - // lose 1ms - nextwait.tv_nsec -= 1000000; - } else { - if (nextwait.tv_sec == 0) { - // already so close to finished - sleep_more = false; - } else { - // lose up to 1ms - nextwait.tv_nsec = 0; - } - } - } - thiswait = nextwait; - } - } while (sleep_more); + struct timespec nextwait; + bool sleep_more = false; + + do { + int result = nanosleep(&thiswait, &nextwait); + + // check if sleep was interrupted by a signal; unslept + // remainder was written back into 't' and we just nanosleep + // again. + sleep_more = (result == -1 && EINTR == errno); + + if (sleep_more) + { + if ( nextwait.tv_sec > thiswait.tv_sec || + (nextwait.tv_sec == thiswait.tv_sec && + nextwait.tv_nsec >= thiswait.tv_nsec) ) + { + // if the remaining time isn't actually going + // down then we're being shafted by low clock + // resolution - manually massage the sleep time + // downward. + if (nextwait.tv_nsec > 1000000) { + // lose 1ms + nextwait.tv_nsec -= 1000000; + } else { + if (nextwait.tv_sec == 0) { + // already so close to finished + sleep_more = false; + } else { + // lose up to 1ms + nextwait.tv_nsec = 0; + } + } + } + thiswait = nextwait; + } + } while (sleep_more); } U32 micro_sleep(U64 us, U32 max_yields) @@ -193,10 +193,10 @@ U32 micro_sleep(U64 us, U32 max_yields) void ms_sleep(U32 ms) { - long mslong = ms; // tv_nsec is a long - struct timespec thiswait; - thiswait.tv_sec = ms / 1000; - thiswait.tv_nsec = (mslong % 1000) * 1000000l; + long mslong = ms; // tv_nsec is a long + struct timespec thiswait; + thiswait.tv_sec = ms / 1000; + thiswait.tv_nsec = (mslong % 1000) * 1000000l; _sleep_loop(thiswait); } #else @@ -210,25 +210,25 @@ void ms_sleep(U32 ms) #if LL_WINDOWS U64 get_clock_count() { - static bool firstTime = true; - static U64 offset; - // ensures that callers to this function never have to deal with wrap + static bool firstTime = true; + static U64 offset; + // ensures that callers to this function never have to deal with wrap - // QueryPerformanceCounter implementation - LARGE_INTEGER clock_count; - QueryPerformanceCounter(&clock_count); - if (firstTime) { - offset = clock_count.QuadPart; - firstTime = false; - } - return clock_count.QuadPart - offset; + // QueryPerformanceCounter implementation + LARGE_INTEGER clock_count; + QueryPerformanceCounter(&clock_count); + if (firstTime) { + offset = clock_count.QuadPart; + firstTime = false; + } + return clock_count.QuadPart - offset; } F64 calc_clock_frequency() { - __int64 freq; - QueryPerformanceFrequency((LARGE_INTEGER *) &freq); - return (F64)freq; + __int64 freq; + QueryPerformanceFrequency((LARGE_INTEGER *) &freq); + return (F64)freq; } #endif // LL_WINDOWS @@ -237,81 +237,81 @@ F64 calc_clock_frequency() // Both Linux and Mac use gettimeofday for accurate time F64 calc_clock_frequency() { - return 1000000.0; // microseconds, so 1 MHz. + return 1000000.0; // microseconds, so 1 MHz. } U64 get_clock_count() { - // Linux clocks are in microseconds - struct timeval tv; - gettimeofday(&tv, NULL); - return tv.tv_sec*SEC_TO_MICROSEC_U64 + tv.tv_usec; + // Linux clocks are in microseconds + struct timeval tv; + gettimeofday(&tv, NULL); + return tv.tv_sec*SEC_TO_MICROSEC_U64 + tv.tv_usec; } #endif TimerInfo::TimerInfo() -: mClockFrequency(0.0), - mTotalTimeClockCount(0), - mLastTotalTimeClockCount(0) +: mClockFrequency(0.0), + mTotalTimeClockCount(0), + mLastTotalTimeClockCount(0) {} void TimerInfo::update() { - mClockFrequency = calc_clock_frequency(); - mClockFrequencyInv = 1.0/mClockFrequency; - mClocksToMicroseconds = mClockFrequencyInv; + mClockFrequency = calc_clock_frequency(); + mClockFrequencyInv = 1.0/mClockFrequency; + mClocksToMicroseconds = mClockFrequencyInv; } TimerInfo& get_timer_info() { - static TimerInfo sTimerInfo; - return sTimerInfo; + static TimerInfo sTimerInfo; + return sTimerInfo; } /////////////////////////////////////////////////////////////////////////////// -// returns a U64 number that represents the number of +// returns a U64 number that represents the number of // microseconds since the Unix epoch - Jan 1, 1970 U64MicrosecondsImplicit totalTime() { - U64 current_clock_count = get_clock_count(); - if (!get_timer_info().mTotalTimeClockCount || get_timer_info().mClocksToMicroseconds.value() == 0) - { - get_timer_info().update(); - get_timer_info().mTotalTimeClockCount = current_clock_count; + U64 current_clock_count = get_clock_count(); + if (!get_timer_info().mTotalTimeClockCount || get_timer_info().mClocksToMicroseconds.value() == 0) + { + get_timer_info().update(); + get_timer_info().mTotalTimeClockCount = current_clock_count; #if LL_WINDOWS - // Sync us up with local time (even though we PROBABLY don't need to, this is how it was implemented) - // Unix platforms use gettimeofday so they are synced, although this probably isn't a good assumption to - // make in the future. + // Sync us up with local time (even though we PROBABLY don't need to, this is how it was implemented) + // Unix platforms use gettimeofday so they are synced, although this probably isn't a good assumption to + // make in the future. - get_timer_info().mTotalTimeClockCount = (U64)(time(NULL) * get_timer_info().mClockFrequency); + get_timer_info().mTotalTimeClockCount = (U64)(time(NULL) * get_timer_info().mClockFrequency); #endif - // Update the last clock count - get_timer_info().mLastTotalTimeClockCount = current_clock_count; - } - else - { - if (current_clock_count >= get_timer_info().mLastTotalTimeClockCount) - { - // No wrapping, we're all okay. - get_timer_info().mTotalTimeClockCount += current_clock_count - get_timer_info().mLastTotalTimeClockCount; - } - else - { - // We've wrapped. Compensate correctly - get_timer_info().mTotalTimeClockCount += (0xFFFFFFFFFFFFFFFFULL - get_timer_info().mLastTotalTimeClockCount) + current_clock_count; - } - - // Update the last clock count - get_timer_info().mLastTotalTimeClockCount = current_clock_count; - } + // Update the last clock count + get_timer_info().mLastTotalTimeClockCount = current_clock_count; + } + else + { + if (current_clock_count >= get_timer_info().mLastTotalTimeClockCount) + { + // No wrapping, we're all okay. + get_timer_info().mTotalTimeClockCount += current_clock_count - get_timer_info().mLastTotalTimeClockCount; + } + else + { + // We've wrapped. Compensate correctly + get_timer_info().mTotalTimeClockCount += (0xFFFFFFFFFFFFFFFFULL - get_timer_info().mLastTotalTimeClockCount) + current_clock_count; + } + + // Update the last clock count + get_timer_info().mLastTotalTimeClockCount = current_clock_count; + } - // Return the total clock tick count in microseconds. - U64Microseconds time(get_timer_info().mTotalTimeClockCount*get_timer_info().mClocksToMicroseconds); - return time; + // Return the total clock tick count in microseconds. + U64Microseconds time(get_timer_info().mTotalTimeClockCount*get_timer_info().mClocksToMicroseconds); + return time; } @@ -319,13 +319,13 @@ U64MicrosecondsImplicit totalTime() LLTimer::LLTimer() { - if (!get_timer_info().mClockFrequency) - { - get_timer_info().update(); - } + if (!get_timer_info().mClockFrequency) + { + get_timer_info().update(); + } - mStarted = TRUE; - reset(); + mStarted = TRUE; + reset(); } LLTimer::~LLTimer() @@ -334,47 +334,47 @@ LLTimer::~LLTimer() // static void LLTimer::initClass() { - if (!sTimer) sTimer = new LLTimer; + if (!sTimer) sTimer = new LLTimer; } // static void LLTimer::cleanupClass() { - delete sTimer; sTimer = NULL; + delete sTimer; sTimer = NULL; } // static U64MicrosecondsImplicit LLTimer::getTotalTime() { - // simply call into the implementation function. - U64MicrosecondsImplicit total_time = totalTime(); - return total_time; -} + // simply call into the implementation function. + U64MicrosecondsImplicit total_time = totalTime(); + return total_time; +} // static F64SecondsImplicit LLTimer::getTotalSeconds() { - return F64Microseconds(U64_to_F64(getTotalTime())); + return F64Microseconds(U64_to_F64(getTotalTime())); } void LLTimer::reset() { - mLastClockCount = get_clock_count(); - mExpirationTicks = 0; + mLastClockCount = get_clock_count(); + mExpirationTicks = 0; } /////////////////////////////////////////////////////////////////////////////// U64 LLTimer::getCurrentClockCount() { - return get_clock_count(); + return get_clock_count(); } /////////////////////////////////////////////////////////////////////////////// void LLTimer::setLastClockCount(U64 current_count) { - mLastClockCount = current_count; + mLastClockCount = current_count; } /////////////////////////////////////////////////////////////////////////////// @@ -382,152 +382,152 @@ void LLTimer::setLastClockCount(U64 current_count) static U64 getElapsedTimeAndUpdate(U64& lastClockCount) { - U64 current_clock_count = get_clock_count(); - U64 result; + U64 current_clock_count = get_clock_count(); + U64 result; - if (current_clock_count >= lastClockCount) - { - result = current_clock_count - lastClockCount; - } - else - { - // time has gone backward - result = 0; - } + if (current_clock_count >= lastClockCount) + { + result = current_clock_count - lastClockCount; + } + else + { + // time has gone backward + result = 0; + } - lastClockCount = current_clock_count; + lastClockCount = current_clock_count; - return result; + return result; } F64SecondsImplicit LLTimer::getElapsedTimeF64() const { - U64 last = mLastClockCount; - return (F64)getElapsedTimeAndUpdate(last) * get_timer_info().mClockFrequencyInv; + U64 last = mLastClockCount; + return (F64)getElapsedTimeAndUpdate(last) * get_timer_info().mClockFrequencyInv; } F32SecondsImplicit LLTimer::getElapsedTimeF32() const { - return (F32)getElapsedTimeF64(); + return (F32)getElapsedTimeF64(); } F64SecondsImplicit LLTimer::getElapsedTimeAndResetF64() { - return (F64)getElapsedTimeAndUpdate(mLastClockCount) * get_timer_info().mClockFrequencyInv; + return (F64)getElapsedTimeAndUpdate(mLastClockCount) * get_timer_info().mClockFrequencyInv; } F32SecondsImplicit LLTimer::getElapsedTimeAndResetF32() { - return (F32)getElapsedTimeAndResetF64(); + return (F32)getElapsedTimeAndResetF64(); } /////////////////////////////////////////////////////////////////////////////// void LLTimer::setTimerExpirySec(F32SecondsImplicit expiration) { - mExpirationTicks = get_clock_count() - + (U64)((F32)(expiration * get_timer_info().mClockFrequency.value())); + mExpirationTicks = get_clock_count() + + (U64)((F32)(expiration * get_timer_info().mClockFrequency.value())); } F32SecondsImplicit LLTimer::getRemainingTimeF32() const { - U64 cur_ticks = get_clock_count(); - if (cur_ticks > mExpirationTicks) - { - return 0.0f; - } - return F32((mExpirationTicks - cur_ticks) * get_timer_info().mClockFrequencyInv); + U64 cur_ticks = get_clock_count(); + if (cur_ticks > mExpirationTicks) + { + return 0.0f; + } + return F32((mExpirationTicks - cur_ticks) * get_timer_info().mClockFrequencyInv); } BOOL LLTimer::checkExpirationAndReset(F32 expiration) { - U64 cur_ticks = get_clock_count(); - if (cur_ticks < mExpirationTicks) - { - return FALSE; - } + U64 cur_ticks = get_clock_count(); + if (cur_ticks < mExpirationTicks) + { + return FALSE; + } - mExpirationTicks = cur_ticks - + (U64)((F32)(expiration * get_timer_info().mClockFrequency)); - return TRUE; + mExpirationTicks = cur_ticks + + (U64)((F32)(expiration * get_timer_info().mClockFrequency)); + return TRUE; } BOOL LLTimer::hasExpired() const { - return (get_clock_count() >= mExpirationTicks) - ? TRUE : FALSE; + return (get_clock_count() >= mExpirationTicks) + ? TRUE : FALSE; } /////////////////////////////////////////////////////////////////////////////// BOOL LLTimer::knownBadTimer() { - BOOL failed = FALSE; + BOOL failed = FALSE; #if LL_WINDOWS - WCHAR bad_pci_list[][10] = {L"1039:0530", - L"1039:0620", - L"10B9:0533", - L"10B9:1533", - L"1106:0596", - L"1106:0686", - L"1166:004F", - L"1166:0050", - L"8086:7110", - L"\0" - }; - - HKEY hKey = NULL; - LONG nResult = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE,L"SYSTEM\\CurrentControlSet\\Enum\\PCI", 0, - KEY_EXECUTE | KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, &hKey); - - WCHAR name[1024]; - DWORD name_len = 1024; - FILETIME scrap; - - S32 key_num = 0; - WCHAR pci_id[10]; - - wcscpy(pci_id, L"0000:0000"); /*Flawfinder: ignore*/ - - while (nResult == ERROR_SUCCESS) - { - nResult = ::RegEnumKeyEx(hKey, key_num++, name, &name_len, NULL, NULL, NULL, &scrap); - - if (nResult == ERROR_SUCCESS) - { - memcpy(&pci_id[0],&name[4],4); /* Flawfinder: ignore */ - memcpy(&pci_id[5],&name[13],4); /* Flawfinder: ignore */ - - for (S32 check = 0; bad_pci_list[check][0]; check++) - { - if (!wcscmp(pci_id, bad_pci_list[check])) - { -// LL_WARNS() << "unreliable PCI chipset found!! " << pci_id << endl; - failed = TRUE; - break; - } - } -// llinfo << "PCI chipset found: " << pci_id << endl; - name_len = 1024; - } - } + WCHAR bad_pci_list[][10] = {L"1039:0530", + L"1039:0620", + L"10B9:0533", + L"10B9:1533", + L"1106:0596", + L"1106:0686", + L"1166:004F", + L"1166:0050", + L"8086:7110", + L"\0" + }; + + HKEY hKey = NULL; + LONG nResult = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE,L"SYSTEM\\CurrentControlSet\\Enum\\PCI", 0, + KEY_EXECUTE | KEY_QUERY_VALUE | KEY_ENUMERATE_SUB_KEYS, &hKey); + + WCHAR name[1024]; + DWORD name_len = 1024; + FILETIME scrap; + + S32 key_num = 0; + WCHAR pci_id[10]; + + wcscpy(pci_id, L"0000:0000"); /*Flawfinder: ignore*/ + + while (nResult == ERROR_SUCCESS) + { + nResult = ::RegEnumKeyEx(hKey, key_num++, name, &name_len, NULL, NULL, NULL, &scrap); + + if (nResult == ERROR_SUCCESS) + { + memcpy(&pci_id[0],&name[4],4); /* Flawfinder: ignore */ + memcpy(&pci_id[5],&name[13],4); /* Flawfinder: ignore */ + + for (S32 check = 0; bad_pci_list[check][0]; check++) + { + if (!wcscmp(pci_id, bad_pci_list[check])) + { +// LL_WARNS() << "unreliable PCI chipset found!! " << pci_id << endl; + failed = TRUE; + break; + } + } +// llinfo << "PCI chipset found: " << pci_id << endl; + name_len = 1024; + } + } #endif - return(failed); + return(failed); } /////////////////////////////////////////////////////////////////////////////// -// +// // NON-MEMBER FUNCTIONS // /////////////////////////////////////////////////////////////////////////////// time_t time_corrected() { - return time(NULL) + gUTCOffset; + return time(NULL) + gUTCOffset; } @@ -535,75 +535,75 @@ time_t time_corrected() // observing daylight savings time? BOOL is_daylight_savings() { - time_t now = time(NULL); + time_t now = time(NULL); - // Internal buffer to local server time - struct tm* internal_time = localtime(&now); + // Internal buffer to local server time + struct tm* internal_time = localtime(&now); - // tm_isdst > 0 => daylight savings - // tm_isdst = 0 => not daylight savings - // tm_isdst < 0 => can't tell - return (internal_time->tm_isdst > 0); + // tm_isdst > 0 => daylight savings + // tm_isdst = 0 => not daylight savings + // tm_isdst < 0 => can't tell + return (internal_time->tm_isdst > 0); } struct tm* utc_to_pacific_time(time_t utc_time, BOOL pacific_daylight_time) { - S32Hours pacific_offset_hours; - if (pacific_daylight_time) - { - pacific_offset_hours = S32Hours(7); - } - else - { - pacific_offset_hours = S32Hours(8); - } + S32Hours pacific_offset_hours; + if (pacific_daylight_time) + { + pacific_offset_hours = S32Hours(7); + } + else + { + pacific_offset_hours = S32Hours(8); + } + + // We subtract off the PST/PDT offset _before_ getting + // "UTC" time, because this will handle wrapping around + // for 5 AM UTC -> 10 PM PDT of the previous day. + utc_time -= S32SecondsImplicit(pacific_offset_hours); - // We subtract off the PST/PDT offset _before_ getting - // "UTC" time, because this will handle wrapping around - // for 5 AM UTC -> 10 PM PDT of the previous day. - utc_time -= S32SecondsImplicit(pacific_offset_hours); - - // Internal buffer to PST/PDT (see above) - struct tm* internal_time = gmtime(&utc_time); + // Internal buffer to PST/PDT (see above) + struct tm* internal_time = gmtime(&utc_time); - /* - // Don't do this, this won't correctly tell you if daylight savings is active in CA or not. - if (pacific_daylight_time) - { - internal_time->tm_isdst = 1; - } - */ + /* + // Don't do this, this won't correctly tell you if daylight savings is active in CA or not. + if (pacific_daylight_time) + { + internal_time->tm_isdst = 1; + } + */ - return internal_time; + return internal_time; } void microsecondsToTimecodeString(U64MicrosecondsImplicit current_time, std::string& tcstring) { - U64 hours; - U64 minutes; - U64 seconds; - U64 frames; - U64 subframes; + U64 hours; + U64 minutes; + U64 seconds; + U64 frames; + U64 subframes; - hours = current_time / (U64)3600000000ul; - minutes = current_time / (U64)60000000; - minutes %= 60; - seconds = current_time / (U64)1000000; - seconds %= 60; - frames = current_time / (U64)41667; - frames %= 24; - subframes = current_time / (U64)42; - subframes %= 100; + hours = current_time / (U64)3600000000ul; + minutes = current_time / (U64)60000000; + minutes %= 60; + seconds = current_time / (U64)1000000; + seconds %= 60; + frames = current_time / (U64)41667; + frames %= 24; + subframes = current_time / (U64)42; + subframes %= 100; - tcstring = llformat("%3.3d:%2.2d:%2.2d:%2.2d.%2.2d",(int)hours,(int)minutes,(int)seconds,(int)frames,(int)subframes); + tcstring = llformat("%3.3d:%2.2d:%2.2d:%2.2d.%2.2d",(int)hours,(int)minutes,(int)seconds,(int)frames,(int)subframes); } void secondsToTimecodeString(F32SecondsImplicit current_time, std::string& tcstring) { - microsecondsToTimecodeString(current_time, tcstring); + microsecondsToTimecodeString(current_time, tcstring); } diff --git a/indra/llcommon/lltimer.h b/indra/llcommon/lltimer.h index 010f290b24..fe4a3afc7a 100644 --- a/indra/llcommon/lltimer.h +++ b/indra/llcommon/lltimer.h @@ -1,30 +1,30 @@ -/** +/** * @file lltimer.h - * @brief Cross-platform objects for doing timing + * @brief Cross-platform objects for doing timing * * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ -#ifndef LL_TIMER_H +#ifndef LL_TIMER_H #define LL_TIMER_H #if LL_LINUX || LL_DARWIN @@ -39,76 +39,76 @@ // units conversions #include "llunits.h" #ifndef USEC_PER_SEC - const U32 USEC_PER_SEC = 1000000; + const U32 USEC_PER_SEC = 1000000; #endif -const U32 SEC_PER_MIN = 60; -const U32 MIN_PER_HOUR = 60; -const U32 USEC_PER_MIN = USEC_PER_SEC * SEC_PER_MIN; -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; - -class LL_COMMON_API LLTimer +const U32 SEC_PER_MIN = 60; +const U32 MIN_PER_HOUR = 60; +const U32 USEC_PER_MIN = USEC_PER_SEC * SEC_PER_MIN; +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; + +class LL_COMMON_API LLTimer { public: - static LLTimer *sTimer; // global timer - -protected: - U64 mLastClockCount; - U64 mExpirationTicks; - bool mStarted; + static LLTimer *sTimer; // global timer + +protected: + U64 mLastClockCount; + U64 mExpirationTicks; + bool mStarted; public: - LLTimer(); - ~LLTimer(); + LLTimer(); + ~LLTimer(); - static void initClass(); - static void cleanupClass(); + static void initClass(); + static void cleanupClass(); - // Return a high precision number of seconds since the start of - // this application instance. - static F64SecondsImplicit getElapsedSeconds() - { - if (sTimer) - { - return sTimer->getElapsedTimeF64(); - } - else - { - return 0; - } - } + // Return a high precision number of seconds since the start of + // this application instance. + static F64SecondsImplicit getElapsedSeconds() + { + if (sTimer) + { + return sTimer->getElapsedTimeF64(); + } + else + { + return 0; + } + } - // Return a high precision usec since epoch - static U64MicrosecondsImplicit getTotalTime(); + // Return a high precision usec since epoch + static U64MicrosecondsImplicit getTotalTime(); - // Return a high precision seconds since epoch - static F64SecondsImplicit getTotalSeconds(); + // Return a high precision seconds since epoch + static F64SecondsImplicit getTotalSeconds(); - // MANIPULATORS - void start() { reset(); mStarted = TRUE; } - void stop() { mStarted = FALSE; } - void reset(); // Resets the timer - void setLastClockCount(U64 current_count); // Sets the timer so that the next elapsed call will be relative to this time - void setTimerExpirySec(F32SecondsImplicit expiration); - BOOL checkExpirationAndReset(F32 expiration); - BOOL hasExpired() const; - F32SecondsImplicit getElapsedTimeAndResetF32(); // Returns elapsed time in seconds with reset - F64SecondsImplicit getElapsedTimeAndResetF64(); + // MANIPULATORS + void start() { reset(); mStarted = TRUE; } + void stop() { mStarted = FALSE; } + void reset(); // Resets the timer + void setLastClockCount(U64 current_count); // Sets the timer so that the next elapsed call will be relative to this time + void setTimerExpirySec(F32SecondsImplicit expiration); + BOOL checkExpirationAndReset(F32 expiration); + BOOL hasExpired() const; + F32SecondsImplicit getElapsedTimeAndResetF32(); // Returns elapsed time in seconds with reset + F64SecondsImplicit getElapsedTimeAndResetF64(); - F32SecondsImplicit getRemainingTimeF32() const; + F32SecondsImplicit getRemainingTimeF32() const; - static BOOL knownBadTimer(); + static BOOL knownBadTimer(); - // ACCESSORS - F32SecondsImplicit getElapsedTimeF32() const; // Returns elapsed time in seconds - F64SecondsImplicit getElapsedTimeF64() const; // Returns elapsed time in seconds + // ACCESSORS + F32SecondsImplicit getElapsedTimeF32() const; // Returns elapsed time in seconds + F64SecondsImplicit getElapsedTimeF64() const; // Returns elapsed time in seconds - bool getStarted() const { return mStarted; } + bool getStarted() const { return mStarted; } - static U64 getCurrentClockCount(); // Returns the raw clockticks + static U64 getCurrentClockCount(); // Returns the raw clockticks }; // @@ -116,14 +116,14 @@ public: // struct TimerInfo { - TimerInfo(); - void update(); - - F64HertzImplicit mClockFrequency; - F64SecondsImplicit mClockFrequencyInv; - F64MicrosecondsImplicit mClocksToMicroseconds; - U64 mTotalTimeClockCount; - U64 mLastTotalTimeClockCount; + TimerInfo(); + void update(); + + F64HertzImplicit mClockFrequency; + F64SecondsImplicit mClockFrequencyInv; + F64MicrosecondsImplicit mClocksToMicroseconds; + U64 mTotalTimeClockCount; + U64 mLastTotalTimeClockCount; }; TimerInfo& get_timer_info(); @@ -140,30 +140,30 @@ LL_COMMON_API time_t time_corrected(); static inline time_t time_min() { - if (sizeof(time_t) == 4) - { - return (time_t) INT_MIN; - } else { + if (sizeof(time_t) == 4) + { + return (time_t) INT_MIN; + } else { #ifdef LLONG_MIN - return (time_t) LLONG_MIN; + return (time_t) LLONG_MIN; #else - return (time_t) LONG_MIN; + return (time_t) LONG_MIN; #endif - } + } } static inline time_t time_max() { - if (sizeof(time_t) == 4) - { - return (time_t) INT_MAX; - } else { + if (sizeof(time_t) == 4) + { + return (time_t) INT_MAX; + } else { #ifdef LLONG_MAX - return (time_t) LLONG_MAX; + return (time_t) LLONG_MAX; #else - return (time_t) LONG_MAX; + return (time_t) LONG_MAX; #endif - } + } } // Correction factor used by time_corrected() above. @@ -183,6 +183,6 @@ LL_COMMON_API struct tm* utc_to_pacific_time(time_t utc_time, BOOL pacific_dayli LL_COMMON_API void microsecondsToTimecodeString(U64MicrosecondsImplicit current_time, std::string& tcstring); LL_COMMON_API void secondsToTimecodeString(F32SecondsImplicit current_time, std::string& tcstring); -U64MicrosecondsImplicit LL_COMMON_API totalTime(); // Returns current system time in microseconds +U64MicrosecondsImplicit LL_COMMON_API totalTime(); // Returns current system time in microseconds #endif diff --git a/indra/llcommon/lltrace.cpp b/indra/llcommon/lltrace.cpp index 87457ad907..440529b8e8 100644 --- a/indra/llcommon/lltrace.cpp +++ b/indra/llcommon/lltrace.cpp @@ -1,24 +1,24 @@ -/** +/** * @file lltrace.cpp * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2012, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -33,53 +33,53 @@ namespace LLTrace { -StatBase::StatBase( const char* name, const char* description ) -: mName(name), - mDescription(description ? description : "") +StatBase::StatBase( const char* name, const char* description ) +: mName(name), + mDescription(description ? description : "") { #ifndef LL_RELEASE_FOR_DOWNLOAD - if (LLTrace::get_thread_recorder() != NULL) - { - LL_ERRS() << "Attempting to declare trace object after program initialization. Trace objects should be statically initialized." << LL_ENDL; - } + if (LLTrace::get_thread_recorder() != NULL) + { + LL_ERRS() << "Attempting to declare trace object after program initialization. Trace objects should be statically initialized." << LL_ENDL; + } #endif } const char* StatBase::getUnitLabel() const { - return ""; + return ""; } -TimeBlockTreeNode::TimeBlockTreeNode() -: mBlock(NULL), - mParent(NULL), - mNeedsSorting(false), - mCollapsed(true) +TimeBlockTreeNode::TimeBlockTreeNode() +: mBlock(NULL), + mParent(NULL), + mNeedsSorting(false), + mCollapsed(true) {} void TimeBlockTreeNode::setParent( BlockTimerStatHandle* parent ) { LL_PROFILE_ZONE_SCOPED; - llassert_always(parent != mBlock); - llassert_always(parent != NULL); + llassert_always(parent != mBlock); + llassert_always(parent != NULL); - TimeBlockTreeNode* parent_tree_node = get_thread_recorder()->getTimeBlockTreeNode(narrow(parent->getIndex())); - if (!parent_tree_node) return; + TimeBlockTreeNode* parent_tree_node = get_thread_recorder()->getTimeBlockTreeNode(narrow(parent->getIndex())); + if (!parent_tree_node) return; - if (mParent) - { - std::vector& children = mParent->getChildren(); - std::vector::iterator found_it = std::find(children.begin(), children.end(), mBlock); - if (found_it != children.end()) - { - children.erase(found_it); - } - } + if (mParent) + { + std::vector& children = mParent->getChildren(); + std::vector::iterator found_it = std::find(children.begin(), children.end(), mBlock); + if (found_it != children.end()) + { + children.erase(found_it); + } + } - mParent = parent; - mBlock->getCurrentAccumulator().mParent = parent; - parent_tree_node->mChildren.push_back(mBlock); - parent_tree_node->mNeedsSorting = true; + mParent = parent; + mBlock->getCurrentAccumulator().mParent = parent; + parent_tree_node->mChildren.push_back(mBlock); + parent_tree_node->mNeedsSorting = true; } } diff --git a/indra/llcommon/lltrace.h b/indra/llcommon/lltrace.h index 21a5803a76..edb010b0a4 100644 --- a/indra/llcommon/lltrace.h +++ b/indra/llcommon/lltrace.h @@ -1,25 +1,25 @@ -/** +/** * @file lltrace.h * @brief Runtime statistics accumulation. * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2012, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -47,90 +47,90 @@ class Recording; template T storage_value(T val) { return val; } -template +template STORAGE_TYPE storage_value(LLUnit val) { return val.value(); } -template +template STORAGE_TYPE storage_value(LLUnitImplicit val) { return val.value(); } class StatBase { public: - StatBase(const char* name, const char* description); - virtual ~StatBase() {} - virtual const char* getUnitLabel() const; + StatBase(const char* name, const char* description); + virtual ~StatBase() {} + virtual const char* getUnitLabel() const; - const std::string& getName() const { return mName; } - const std::string& getDescription() const { return mDescription; } + const std::string& getName() const { return mName; } + const std::string& getDescription() const { return mDescription; } protected: - std::string mName; - std::string mDescription; + std::string mName; + std::string mDescription; }; template -class StatType -: public StatBase, - public LLInstanceTracker, std::string> +class StatType +: public StatBase, + public LLInstanceTracker, std::string> { public: - typedef LLInstanceTracker, std::string> instance_tracker_t; - StatType(const char* name, const char* description) - : instance_tracker_t(name), - StatBase(name, description), - mAccumulatorIndex(AccumulatorBuffer::getDefaultBuffer()->reserveSlot()) - {} - - LL_FORCE_INLINE ACCUMULATOR& getCurrentAccumulator() const - { - ACCUMULATOR* accumulator_storage = LLThreadLocalSingletonPointer::getInstance(); - return accumulator_storage ? accumulator_storage[mAccumulatorIndex] : (*AccumulatorBuffer::getDefaultBuffer())[mAccumulatorIndex]; - } - - size_t getIndex() const { return mAccumulatorIndex; } - static size_t getNumIndices() { return AccumulatorBuffer::getNumIndices(); } + typedef LLInstanceTracker, std::string> instance_tracker_t; + StatType(const char* name, const char* description) + : instance_tracker_t(name), + StatBase(name, description), + mAccumulatorIndex(AccumulatorBuffer::getDefaultBuffer()->reserveSlot()) + {} + + LL_FORCE_INLINE ACCUMULATOR& getCurrentAccumulator() const + { + ACCUMULATOR* accumulator_storage = LLThreadLocalSingletonPointer::getInstance(); + return accumulator_storage ? accumulator_storage[mAccumulatorIndex] : (*AccumulatorBuffer::getDefaultBuffer())[mAccumulatorIndex]; + } + + size_t getIndex() const { return mAccumulatorIndex; } + static size_t getNumIndices() { return AccumulatorBuffer::getNumIndices(); } protected: - const size_t mAccumulatorIndex; + const size_t mAccumulatorIndex; }; template<> class StatType -: public StatType +: public StatType { public: - StatType(const char* name, const char* description = "") - : StatType(name, description) - {} + StatType(const char* name, const char* description = "") + : StatType(name, description) + {} }; template<> class StatType - : public StatType + : public StatType { public: - StatType(const char* name, const char* description = "") - : StatType(name, description) - {} + StatType(const char* name, const char* description = "") + : StatType(name, description) + {} }; template class EventStatHandle -: public StatType +: public StatType { public: - typedef F64 storage_t; - typedef StatType stat_t; - typedef EventStatHandle self_t; + typedef F64 storage_t; + typedef StatType stat_t; + typedef EventStatHandle self_t; - EventStatHandle(const char* name, const char* description = NULL) - : stat_t(name, description) - {} + EventStatHandle(const char* name, const char* description = NULL) + : stat_t(name, description) + {} - /*virtual*/ const char* getUnitLabel() const { return LLGetUnitLabel::getUnitLabel(); } + /*virtual*/ const char* getUnitLabel() const { return LLGetUnitLabel::getUnitLabel(); } }; @@ -138,58 +138,58 @@ template void record(EventStatHandle& measurement, VALUE_T value) { #if LL_TRACE_ENABLED - T converted_value(value); - measurement.getCurrentAccumulator().record(storage_value(converted_value)); + T converted_value(value); + measurement.getCurrentAccumulator().record(storage_value(converted_value)); #endif } template class SampleStatHandle -: public StatType +: public StatType { public: - typedef F64 storage_t; - typedef StatType stat_t; - typedef SampleStatHandle self_t; + typedef F64 storage_t; + typedef StatType stat_t; + typedef SampleStatHandle self_t; - SampleStatHandle(const char* name, const char* description = NULL) - : stat_t(name, description) - {} + SampleStatHandle(const char* name, const char* description = NULL) + : stat_t(name, description) + {} - /*virtual*/ const char* getUnitLabel() const { return LLGetUnitLabel::getUnitLabel(); } + /*virtual*/ const char* getUnitLabel() const { return LLGetUnitLabel::getUnitLabel(); } }; template void sample(SampleStatHandle& measurement, VALUE_T value) { #if LL_TRACE_ENABLED - T converted_value(value); - measurement.getCurrentAccumulator().sample(storage_value(converted_value)); + T converted_value(value); + measurement.getCurrentAccumulator().sample(storage_value(converted_value)); #endif } template class CountStatHandle -: public StatType +: public StatType { public: - typedef F64 storage_t; - typedef StatType stat_t; - typedef CountStatHandle self_t; + typedef F64 storage_t; + typedef StatType stat_t; + typedef CountStatHandle self_t; - CountStatHandle(const char* name, const char* description = NULL) - : stat_t(name, description) - {} + CountStatHandle(const char* name, const char* description = NULL) + : stat_t(name, description) + {} - /*virtual*/ const char* getUnitLabel() const { return LLGetUnitLabel::getUnitLabel(); } + /*virtual*/ const char* getUnitLabel() const { return LLGetUnitLabel::getUnitLabel(); } }; template void add(CountStatHandle& count, VALUE_T value) { #if LL_TRACE_ENABLED - T converted_value(value); - count.getCurrentAccumulator().add(storage_value(converted_value)); + T converted_value(value); + count.getCurrentAccumulator().add(storage_value(converted_value)); #endif } @@ -198,85 +198,85 @@ void add(CountStatHandle& count, VALUE_T value) template struct MeasureMem { - static size_t measureFootprint(const T& value) - { - return sizeof(T); - } + static size_t measureFootprint(const T& value) + { + return sizeof(T); + } }; template struct MeasureMem { - static size_t measureFootprint(const T& value) - { + static size_t measureFootprint(const T& value) + { LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - return sizeof(T) + value.getMemFootprint(); - } + return sizeof(T) + value.getMemFootprint(); + } }; template struct MeasureMem { - static size_t measureFootprint(const T& value) - { + static size_t measureFootprint(const T& value) + { LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - return U32Bytes(value).value(); - } + return U32Bytes(value).value(); + } }; template struct MeasureMem { - static size_t measureFootprint(const T* value) - { + static size_t measureFootprint(const T* value) + { LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - if (!value) - { - return 0; - } - return MeasureMem::measureFootprint(*value); - } + if (!value) + { + return 0; + } + return MeasureMem::measureFootprint(*value); + } }; template struct MeasureMem, IS_MEM_TRACKABLE, IS_BYTES> { - static size_t measureFootprint(const LLPointer value) - { - if (value.isNull()) - { - return 0; - } - return MeasureMem::measureFootprint(*value); - } + static size_t measureFootprint(const LLPointer value) + { + if (value.isNull()) + { + return 0; + } + return MeasureMem::measureFootprint(*value); + } }; template struct MeasureMem { - static size_t measureFootprint(S32 value) - { - return value; - } + static size_t measureFootprint(S32 value) + { + return value; + } }; template struct MeasureMem { - static size_t measureFootprint(U32 value) - { - return value; - } + static size_t measureFootprint(U32 value) + { + return value; + } }; template struct MeasureMem, IS_MEM_TRACKABLE, IS_BYTES> { - static size_t measureFootprint(const std::basic_string& value) - { + static size_t measureFootprint(const std::basic_string& value) + { LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - return value.capacity() * sizeof(T); - } + return value.capacity() * sizeof(T); + } }; } diff --git a/indra/llcommon/lltraceaccumulators.cpp b/indra/llcommon/lltraceaccumulators.cpp index b5b32cba38..8741087f3a 100644 --- a/indra/llcommon/lltraceaccumulators.cpp +++ b/indra/llcommon/lltraceaccumulators.cpp @@ -38,246 +38,246 @@ namespace LLTrace AccumulatorBufferGroup::AccumulatorBufferGroup() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; } AccumulatorBufferGroup::AccumulatorBufferGroup(const AccumulatorBufferGroup& other) -: mCounts(other.mCounts), - mSamples(other.mSamples), - mEvents(other.mEvents), - mStackTimers(other.mStackTimers) +: mCounts(other.mCounts), + mSamples(other.mSamples), + mEvents(other.mEvents), + mStackTimers(other.mStackTimers) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; } AccumulatorBufferGroup::~AccumulatorBufferGroup() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; } void AccumulatorBufferGroup::handOffTo(AccumulatorBufferGroup& other) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - other.mCounts.reset(&mCounts); - other.mSamples.reset(&mSamples); - other.mEvents.reset(&mEvents); - other.mStackTimers.reset(&mStackTimers); + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + other.mCounts.reset(&mCounts); + other.mSamples.reset(&mSamples); + other.mEvents.reset(&mEvents); + other.mStackTimers.reset(&mStackTimers); } void AccumulatorBufferGroup::makeCurrent() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - mCounts.makeCurrent(); - mSamples.makeCurrent(); - mEvents.makeCurrent(); - mStackTimers.makeCurrent(); - - ThreadRecorder* thread_recorder = get_thread_recorder(); - AccumulatorBuffer& timer_accumulator_buffer = mStackTimers; - // update stacktimer parent pointers - for (size_t i = 0, end_i = mStackTimers.size(); i < end_i; i++) - { - TimeBlockTreeNode* tree_node = thread_recorder->getTimeBlockTreeNode(narrow(i)); - if (tree_node) - { - timer_accumulator_buffer[i].mParent = tree_node->mParent; - } - } + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + mCounts.makeCurrent(); + mSamples.makeCurrent(); + mEvents.makeCurrent(); + mStackTimers.makeCurrent(); + + ThreadRecorder* thread_recorder = get_thread_recorder(); + AccumulatorBuffer& timer_accumulator_buffer = mStackTimers; + // update stacktimer parent pointers + for (size_t i = 0, end_i = mStackTimers.size(); i < end_i; i++) + { + TimeBlockTreeNode* tree_node = thread_recorder->getTimeBlockTreeNode(narrow(i)); + if (tree_node) + { + timer_accumulator_buffer[i].mParent = tree_node->mParent; + } + } } //static void AccumulatorBufferGroup::clearCurrent() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - AccumulatorBuffer::clearCurrent(); - AccumulatorBuffer::clearCurrent(); - AccumulatorBuffer::clearCurrent(); - AccumulatorBuffer::clearCurrent(); + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + AccumulatorBuffer::clearCurrent(); + AccumulatorBuffer::clearCurrent(); + AccumulatorBuffer::clearCurrent(); + AccumulatorBuffer::clearCurrent(); } bool AccumulatorBufferGroup::isCurrent() const { - return mCounts.isCurrent(); + return mCounts.isCurrent(); } void AccumulatorBufferGroup::append( const AccumulatorBufferGroup& other ) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - mCounts.addSamples(other.mCounts, SEQUENTIAL); - mSamples.addSamples(other.mSamples, SEQUENTIAL); - mEvents.addSamples(other.mEvents, SEQUENTIAL); - mStackTimers.addSamples(other.mStackTimers, SEQUENTIAL); + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + mCounts.addSamples(other.mCounts, SEQUENTIAL); + mSamples.addSamples(other.mSamples, SEQUENTIAL); + mEvents.addSamples(other.mEvents, SEQUENTIAL); + mStackTimers.addSamples(other.mStackTimers, SEQUENTIAL); } void AccumulatorBufferGroup::merge( const AccumulatorBufferGroup& other) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - mCounts.addSamples(other.mCounts, NON_SEQUENTIAL); - mSamples.addSamples(other.mSamples, NON_SEQUENTIAL); - mEvents.addSamples(other.mEvents, NON_SEQUENTIAL); - // for now, hold out timers from merge, need to be displayed per thread - //mStackTimers.addSamples(other.mStackTimers, NON_SEQUENTIAL); + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + mCounts.addSamples(other.mCounts, NON_SEQUENTIAL); + mSamples.addSamples(other.mSamples, NON_SEQUENTIAL); + mEvents.addSamples(other.mEvents, NON_SEQUENTIAL); + // for now, hold out timers from merge, need to be displayed per thread + //mStackTimers.addSamples(other.mStackTimers, NON_SEQUENTIAL); } void AccumulatorBufferGroup::reset(AccumulatorBufferGroup* other) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - mCounts.reset(other ? &other->mCounts : NULL); - mSamples.reset(other ? &other->mSamples : NULL); - mEvents.reset(other ? &other->mEvents : NULL); - mStackTimers.reset(other ? &other->mStackTimers : NULL); + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + mCounts.reset(other ? &other->mCounts : NULL); + mSamples.reset(other ? &other->mSamples : NULL); + mEvents.reset(other ? &other->mEvents : NULL); + mStackTimers.reset(other ? &other->mStackTimers : NULL); } void AccumulatorBufferGroup::sync() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - if (isCurrent()) - { - F64SecondsImplicit time_stamp = LLTimer::getTotalSeconds(); - mSamples.sync(time_stamp); - } + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + if (isCurrent()) + { + F64SecondsImplicit time_stamp = LLTimer::getTotalSeconds(); + mSamples.sync(time_stamp); + } } F64 SampleAccumulator::mergeSumsOfSquares(const SampleAccumulator& a, const SampleAccumulator& b) { - const F64 epsilon = 0.0000001; - - if (a.getSamplingTime() > epsilon && b.getSamplingTime() > epsilon) - { - // combine variance (and hence standard deviation) of 2 different sized sample groups using - // the following formula: http://www.mrc-bsu.cam.ac.uk/cochrane/handbook/chapter_7/7_7_3_8_combining_groups.htm - F64 n_1 = a.getSamplingTime(), - n_2 = b.getSamplingTime(); - F64 m_1 = a.getMean(), - m_2 = b.getMean(); - F64 v_1 = a.getSumOfSquares() / a.getSamplingTime(), - v_2 = b.getSumOfSquares() / b.getSamplingTime(); - if (n_1 < epsilon) - { - return b.getSumOfSquares(); - } - else - { - return a.getSamplingTime() - * ((((n_1 - epsilon) * v_1) - + ((n_2 - epsilon) * v_2) - + (((n_1 * n_2) / (n_1 + n_2)) - * ((m_1 * m_1) + (m_2 * m_2) - (2.f * m_1 * m_2)))) - / (n_1 + n_2 - epsilon)); - } - } - - return a.getSumOfSquares(); + const F64 epsilon = 0.0000001; + + if (a.getSamplingTime() > epsilon && b.getSamplingTime() > epsilon) + { + // combine variance (and hence standard deviation) of 2 different sized sample groups using + // the following formula: http://www.mrc-bsu.cam.ac.uk/cochrane/handbook/chapter_7/7_7_3_8_combining_groups.htm + F64 n_1 = a.getSamplingTime(), + n_2 = b.getSamplingTime(); + F64 m_1 = a.getMean(), + m_2 = b.getMean(); + F64 v_1 = a.getSumOfSquares() / a.getSamplingTime(), + v_2 = b.getSumOfSquares() / b.getSamplingTime(); + if (n_1 < epsilon) + { + return b.getSumOfSquares(); + } + else + { + return a.getSamplingTime() + * ((((n_1 - epsilon) * v_1) + + ((n_2 - epsilon) * v_2) + + (((n_1 * n_2) / (n_1 + n_2)) + * ((m_1 * m_1) + (m_2 * m_2) - (2.f * m_1 * m_2)))) + / (n_1 + n_2 - epsilon)); + } + } + + return a.getSumOfSquares(); } void SampleAccumulator::addSamples( const SampleAccumulator& other, EBufferAppendType append_type ) { - if (append_type == NON_SEQUENTIAL) - { - return; - } - - if (!mHasValue) - { - *this = other; - - if (append_type == NON_SEQUENTIAL) - { - // restore own last value state - mLastValue = NaN; - mHasValue = false; - } - } - else if (other.mHasValue) - { - mSum += other.mSum; - - if (other.mMin < mMin) { mMin = other.mMin; } - if (other.mMax > mMax) { mMax = other.mMax; } - - mSumOfSquares = mergeSumsOfSquares(*this, other); - - if (append_type == SEQUENTIAL) - { - mLastValue = other.mLastValue; - mLastSampleTimeStamp = other.mLastSampleTimeStamp; - } - } + if (append_type == NON_SEQUENTIAL) + { + return; + } + + if (!mHasValue) + { + *this = other; + + if (append_type == NON_SEQUENTIAL) + { + // restore own last value state + mLastValue = NaN; + mHasValue = false; + } + } + else if (other.mHasValue) + { + mSum += other.mSum; + + if (other.mMin < mMin) { mMin = other.mMin; } + if (other.mMax > mMax) { mMax = other.mMax; } + + mSumOfSquares = mergeSumsOfSquares(*this, other); + + if (append_type == SEQUENTIAL) + { + mLastValue = other.mLastValue; + mLastSampleTimeStamp = other.mLastSampleTimeStamp; + } + } } void SampleAccumulator::reset( const SampleAccumulator* other ) { - mLastValue = other ? other->mLastValue : NaN; - mHasValue = other ? other->mHasValue : false; - mNumSamples = 0; - mSum = 0; - mMin = mLastValue; - mMax = mLastValue; - mMean = mLastValue; - llassert(!mHasValue || mMean < 0 || mMean >= 0); - mSumOfSquares = 0; - mLastSampleTimeStamp = LLTimer::getTotalSeconds(); - mTotalSamplingTime = 0; + mLastValue = other ? other->mLastValue : NaN; + mHasValue = other ? other->mHasValue : false; + mNumSamples = 0; + mSum = 0; + mMin = mLastValue; + mMax = mLastValue; + mMean = mLastValue; + llassert(!mHasValue || mMean < 0 || mMean >= 0); + mSumOfSquares = 0; + mLastSampleTimeStamp = LLTimer::getTotalSeconds(); + mTotalSamplingTime = 0; } F64 EventAccumulator::mergeSumsOfSquares(const EventAccumulator& a, const EventAccumulator& b) { - if (a.mNumSamples && b.mNumSamples) - { - // combine variance (and hence standard deviation) of 2 different sized sample groups using - // the following formula: http://www.mrc-bsu.cam.ac.uk/cochrane/handbook/chapter_7/7_7_3_8_combining_groups.htm - F64 n_1 = a.mNumSamples, - n_2 = b.mNumSamples; - F64 m_1 = a.mMean, - m_2 = b.mMean; - F64 v_1 = a.mSumOfSquares / a.mNumSamples, - v_2 = b.mSumOfSquares / b.mNumSamples; - return (F64)a.mNumSamples - * ((((n_1 - 1.f) * v_1) - + ((n_2 - 1.f) * v_2) - + (((n_1 * n_2) / (n_1 + n_2)) - * ((m_1 * m_1) + (m_2 * m_2) - (2.f * m_1 * m_2)))) - / (n_1 + n_2 - 1.f)); - } - - return a.mSumOfSquares; + if (a.mNumSamples && b.mNumSamples) + { + // combine variance (and hence standard deviation) of 2 different sized sample groups using + // the following formula: http://www.mrc-bsu.cam.ac.uk/cochrane/handbook/chapter_7/7_7_3_8_combining_groups.htm + F64 n_1 = a.mNumSamples, + n_2 = b.mNumSamples; + F64 m_1 = a.mMean, + m_2 = b.mMean; + F64 v_1 = a.mSumOfSquares / a.mNumSamples, + v_2 = b.mSumOfSquares / b.mNumSamples; + return (F64)a.mNumSamples + * ((((n_1 - 1.f) * v_1) + + ((n_2 - 1.f) * v_2) + + (((n_1 * n_2) / (n_1 + n_2)) + * ((m_1 * m_1) + (m_2 * m_2) - (2.f * m_1 * m_2)))) + / (n_1 + n_2 - 1.f)); + } + + return a.mSumOfSquares; } void EventAccumulator::addSamples( const EventAccumulator& other, EBufferAppendType append_type ) { - if (other.mNumSamples) - { - if (!mNumSamples) - { - *this = other; - } - else - { - mSum += other.mSum; - - // NOTE: both conditions will hold first time through - if (other.mMin < mMin) { mMin = other.mMin; } - if (other.mMax > mMax) { mMax = other.mMax; } - - mSumOfSquares = mergeSumsOfSquares(*this, other); - - F64 weight = (F64)mNumSamples / (F64)(mNumSamples + other.mNumSamples); - mNumSamples += other.mNumSamples; - mMean = mMean * weight + other.mMean * (1.f - weight); - if (append_type == SEQUENTIAL) mLastValue = other.mLastValue; - } - } + if (other.mNumSamples) + { + if (!mNumSamples) + { + *this = other; + } + else + { + mSum += other.mSum; + + // NOTE: both conditions will hold first time through + if (other.mMin < mMin) { mMin = other.mMin; } + if (other.mMax > mMax) { mMax = other.mMax; } + + mSumOfSquares = mergeSumsOfSquares(*this, other); + + F64 weight = (F64)mNumSamples / (F64)(mNumSamples + other.mNumSamples); + mNumSamples += other.mNumSamples; + mMean = mMean * weight + other.mMean * (1.f - weight); + if (append_type == SEQUENTIAL) mLastValue = other.mLastValue; + } + } } void EventAccumulator::reset( const EventAccumulator* other ) { - mNumSamples = 0; - mSum = 0; - mMin = F32(NaN); - mMax = F32(NaN); - mMean = NaN; - mSumOfSquares = 0; - mLastValue = other ? other->mLastValue : NaN; + mNumSamples = 0; + mSum = 0; + mMin = F32(NaN); + mMax = F32(NaN); + mMean = NaN; + mSumOfSquares = 0; + mLastValue = other ? other->mLastValue : NaN; } } diff --git a/indra/llcommon/lltraceaccumulators.h b/indra/llcommon/lltraceaccumulators.h index b9d577be9e..692bbe5acf 100644 --- a/indra/llcommon/lltraceaccumulators.h +++ b/indra/llcommon/lltraceaccumulators.h @@ -39,515 +39,515 @@ namespace LLTrace { - const F64 NaN = std::numeric_limits::quiet_NaN(); - - enum EBufferAppendType - { - SEQUENTIAL, - NON_SEQUENTIAL - }; - - template - class AccumulatorBuffer : public LLRefCount - { - typedef AccumulatorBuffer self_t; - static const S32 DEFAULT_ACCUMULATOR_BUFFER_SIZE = 32; - private: - struct StaticAllocationMarker { }; - - AccumulatorBuffer(StaticAllocationMarker m) - : mStorageSize(0), - mStorage(NULL) - {} - - public: - AccumulatorBuffer() - : mStorageSize(0), - mStorage(NULL) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - const AccumulatorBuffer& other = *getDefaultBuffer(); - resize(sNextStorageSlot); - for (S32 i = 0; i < sNextStorageSlot; i++) - { - mStorage[i] = other.mStorage[i]; - } - } - - ~AccumulatorBuffer() - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - if (isCurrent()) - { - LLThreadLocalSingletonPointer::setInstance(NULL); - } - delete[] mStorage; - } - - LL_FORCE_INLINE ACCUMULATOR& operator[](size_t index) - { - return mStorage[index]; - } - - LL_FORCE_INLINE const ACCUMULATOR& operator[](size_t index) const - { - return mStorage[index]; - } - - - AccumulatorBuffer(const AccumulatorBuffer& other) - : mStorageSize(0), - mStorage(NULL) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - resize(sNextStorageSlot); - for (S32 i = 0; i < sNextStorageSlot; i++) - { - mStorage[i] = other.mStorage[i]; - } - } - - void addSamples(const AccumulatorBuffer& other, EBufferAppendType append_type) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - llassert(mStorageSize >= sNextStorageSlot && other.mStorageSize >= sNextStorageSlot); - for (size_t i = 0; i < sNextStorageSlot; i++) - { - mStorage[i].addSamples(other.mStorage[i], append_type); - } - } - - void copyFrom(const AccumulatorBuffer& other) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - llassert(mStorageSize >= sNextStorageSlot && other.mStorageSize >= sNextStorageSlot); - for (size_t i = 0; i < sNextStorageSlot; i++) - { - mStorage[i] = other.mStorage[i]; - } - } - - void reset(const AccumulatorBuffer* other = NULL) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - llassert(mStorageSize >= sNextStorageSlot); - for (size_t i = 0; i < sNextStorageSlot; i++) - { - mStorage[i].reset(other ? &other->mStorage[i] : NULL); - } - } - - void sync(F64SecondsImplicit time_stamp) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - llassert(mStorageSize >= sNextStorageSlot); - for (size_t i = 0; i < sNextStorageSlot; i++) - { - mStorage[i].sync(time_stamp); - } - } - - void makeCurrent() - { - LLThreadLocalSingletonPointer::setInstance(mStorage); - } - - bool isCurrent() const - { - return LLThreadLocalSingletonPointer::getInstance() == mStorage; - } - - static void clearCurrent() - { - LLThreadLocalSingletonPointer::setInstance(NULL); - } - - // NOTE: this is not thread-safe. We assume that slots are reserved in the main thread before any child threads are spawned - size_t reserveSlot() - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - size_t next_slot = sNextStorageSlot++; - if (next_slot >= mStorageSize) - { - // don't perform doubling, as this should only happen during startup - // want to keep a tight bounds as we will have a lot of these buffers - resize(mStorageSize + mStorageSize / 2); - } - llassert(mStorage && next_slot < mStorageSize); - return next_slot; - } - - void resize(size_t new_size) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - if (new_size <= mStorageSize) return; - - ACCUMULATOR* old_storage = mStorage; - mStorage = new ACCUMULATOR[new_size]; - if (old_storage) - { - for (S32 i = 0; i < mStorageSize; i++) - { - mStorage[i] = old_storage[i]; - } - } - mStorageSize = new_size; - delete[] old_storage; - - self_t* default_buffer = getDefaultBuffer(); - if (this != default_buffer - && new_size > default_buffer->size()) - { - //NB: this is not thread safe, but we assume that all resizing occurs during static initialization - default_buffer->resize(new_size); - } - } - - size_t size() const - { - return getNumIndices(); - } - - size_t capacity() const - { - return mStorageSize; - } - - static size_t getNumIndices() - { - return sNextStorageSlot; - } - - static self_t* getDefaultBuffer() - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - static bool sInitialized = false; - if (!sInitialized) - { - // this buffer is allowed to leak so that trace calls from global destructors have somewhere to put their data - // so as not to trigger an access violation - sDefaultBuffer = new AccumulatorBuffer(StaticAllocationMarker()); - sInitialized = true; - sDefaultBuffer->resize(DEFAULT_ACCUMULATOR_BUFFER_SIZE); - } - return sDefaultBuffer; - } - - private: - ACCUMULATOR* mStorage; - size_t mStorageSize; - static size_t sNextStorageSlot; - static self_t* sDefaultBuffer; - }; - - template size_t AccumulatorBuffer::sNextStorageSlot = 0; - template AccumulatorBuffer* AccumulatorBuffer::sDefaultBuffer = NULL; - - class EventAccumulator - { - public: - typedef F64 value_t; - static F64 getDefaultValue() { return NaN; } - - EventAccumulator() - : mSum(0), - mMin(F32(NaN)), - mMax(F32(NaN)), - mMean(NaN), - mSumOfSquares(0), - mNumSamples(0), - mLastValue(NaN) - {} - - void record(F64 value) - { - if (mNumSamples == 0) - { - mSum = value; - mMean = value; - mMin = value; - mMax = value; - } - else - { - mSum += value; - F64 old_mean = mMean; - mMean += (value - old_mean) / (F64)mNumSamples; - mSumOfSquares += (value - old_mean) * (value - mMean); - - if (value < mMin) { mMin = value; } - else if (value > mMax) { mMax = value; } - } - - mNumSamples++; - mLastValue = value; - } - - void addSamples(const EventAccumulator& other, EBufferAppendType append_type); - void reset(const EventAccumulator* other); - void sync(F64SecondsImplicit) {} - - F64 getSum() const { return mSum; } - F32 getMin() const { return mMin; } - F32 getMax() const { return mMax; } - F64 getLastValue() const { return mLastValue; } - F64 getMean() const { return mMean; } - F64 getStandardDeviation() const { return sqrtf(mSumOfSquares / mNumSamples); } - F64 getSumOfSquares() const { return mSumOfSquares; } - S32 getSampleCount() const { return mNumSamples; } - bool hasValue() const { return mNumSamples > 0; } - - // helper utility to calculate combined sumofsquares total - static F64 mergeSumsOfSquares(const EventAccumulator& a, const EventAccumulator& b); - - private: - F64 mSum, - mLastValue; - - F64 mMean, - mSumOfSquares; - - F32 mMin, - mMax; - - S32 mNumSamples; - }; - - - class SampleAccumulator - { - public: - typedef F64 value_t; - static F64 getDefaultValue() { return NaN; } - - SampleAccumulator() - : mSum(0), - mMin(F32(NaN)), - mMax(F32(NaN)), - mMean(NaN), - mSumOfSquares(0), - mLastSampleTimeStamp(0), - mTotalSamplingTime(0), - mNumSamples(0), - mLastValue(NaN), - mHasValue(false) - {} - - void sample(F64 value) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - F64SecondsImplicit time_stamp = LLTimer::getTotalSeconds(); - - // store effect of last value - sync(time_stamp); - - if (!mHasValue) - { - mHasValue = true; - - mMin = value; - mMax = value; - mMean = value; - mLastSampleTimeStamp = time_stamp; - } - else - { - if (value < mMin) { mMin = value; } - else if (value > mMax) { mMax = value; } - } - - mLastValue = value; - mNumSamples++; - } - - void addSamples(const SampleAccumulator& other, EBufferAppendType append_type); - void reset(const SampleAccumulator* other); - - void sync(F64SecondsImplicit time_stamp) - { - if (mHasValue && time_stamp != mLastSampleTimeStamp) - { - F64SecondsImplicit delta_time = time_stamp - mLastSampleTimeStamp; - mSum += mLastValue * delta_time; - mTotalSamplingTime += delta_time; - F64 old_mean = mMean; - mMean += (delta_time / mTotalSamplingTime) * (mLastValue - old_mean); - mSumOfSquares += delta_time * (mLastValue - old_mean) * (mLastValue - mMean); - } - mLastSampleTimeStamp = time_stamp; - } - - F64 getSum() const { return mSum; } - F32 getMin() const { return mMin; } - F32 getMax() const { return mMax; } - F64 getLastValue() const { return mLastValue; } - F64 getMean() const { return mMean; } - F64 getStandardDeviation() const { return sqrtf(mSumOfSquares / mTotalSamplingTime); } - F64 getSumOfSquares() const { return mSumOfSquares; } - F64SecondsImplicit getSamplingTime() const { return mTotalSamplingTime; } - S32 getSampleCount() const { return mNumSamples; } - bool hasValue() const { return mHasValue; } - - // helper utility to calculate combined sumofsquares total - static F64 mergeSumsOfSquares(const SampleAccumulator& a, const SampleAccumulator& b); - - private: - F64 mSum, - mLastValue; - - F64 mMean, - mSumOfSquares; - - F64SecondsImplicit - mLastSampleTimeStamp, - mTotalSamplingTime; - - F32 mMin, - mMax; - - S32 mNumSamples; - // distinct from mNumSamples, since we might have inherited a last value from - // a previous sampling period - bool mHasValue; - }; - - class CountAccumulator - { - public: - typedef F64 value_t; - static F64 getDefaultValue() { return 0; } - - CountAccumulator() - : mSum(0), - mNumSamples(0) - {} - - void add(F64 value) - { - mNumSamples++; - mSum += value; - } - - void addSamples(const CountAccumulator& other, EBufferAppendType /*type*/) - { - mSum += other.mSum; - mNumSamples += other.mNumSamples; - } - - void reset(const CountAccumulator* other) - { - mNumSamples = 0; - mSum = 0; - } - - void sync(F64SecondsImplicit) {} - - F64 getSum() const { return mSum; } - - S32 getSampleCount() const { return mNumSamples; } - - bool hasValue() const { return true; } - - private: - F64 mSum; - - S32 mNumSamples; - }; - - class alignas(32) TimeBlockAccumulator - { - public: - typedef F64Seconds value_t; - static F64Seconds getDefaultValue() { return F64Seconds(0); } - - typedef TimeBlockAccumulator self_t; - - // fake classes that allows us to view different facets of underlying statistic - struct CallCountFacet - { - typedef S32 value_t; - }; - - struct SelfTimeFacet - { - typedef F64Seconds value_t; - }; - - // arrays are allocated with 32 byte alignment - void *operator new [](size_t size) - { - return ll_aligned_malloc<32>(size); - } - - void operator delete[](void* ptr, size_t size) - { - ll_aligned_free<32>(ptr); - } - - TimeBlockAccumulator(); - void addSamples(const self_t& other, EBufferAppendType append_type); - void reset(const self_t* other); - void sync(F64SecondsImplicit) {} - bool hasValue() const { return true; } - - // - // members - // - U64 mTotalTimeCounter, - mSelfTimeCounter; - S32 mCalls; - class BlockTimerStatHandle* mParent; // last acknowledged parent of this time block - class BlockTimerStatHandle* mLastCaller; // used to bootstrap tree construction - U16 mActiveCount; // number of timers with this ID active on stack - bool mMoveUpTree; // needs to be moved up the tree of timers at the end of frame - - }; - - class BlockTimerStatHandle; - - class TimeBlockTreeNode - { - public: - TimeBlockTreeNode(); - - void setParent(BlockTimerStatHandle* parent); - BlockTimerStatHandle* getParent() { return mParent; } - - BlockTimerStatHandle* mBlock; - BlockTimerStatHandle* mParent; - std::vector mChildren; - bool mCollapsed; - bool mNeedsSorting; - }; - - struct BlockTimerStackRecord - { - class BlockTimer* mActiveTimer; - class BlockTimerStatHandle* mTimeBlock; - U64 mChildTime; - }; - - struct AccumulatorBufferGroup : public LLRefCount - { - AccumulatorBufferGroup(); - AccumulatorBufferGroup(const AccumulatorBufferGroup&); - ~AccumulatorBufferGroup(); - - void handOffTo(AccumulatorBufferGroup& other); - void makeCurrent(); - bool isCurrent() const; - static void clearCurrent(); - - void append(const AccumulatorBufferGroup& other); - void merge(const AccumulatorBufferGroup& other); - void reset(AccumulatorBufferGroup* other = NULL); - void sync(); - - AccumulatorBuffer mCounts; - AccumulatorBuffer mSamples; - AccumulatorBuffer mEvents; - AccumulatorBuffer mStackTimers; - }; + const F64 NaN = std::numeric_limits::quiet_NaN(); + + enum EBufferAppendType + { + SEQUENTIAL, + NON_SEQUENTIAL + }; + + template + class AccumulatorBuffer : public LLRefCount + { + typedef AccumulatorBuffer self_t; + static const S32 DEFAULT_ACCUMULATOR_BUFFER_SIZE = 32; + private: + struct StaticAllocationMarker { }; + + AccumulatorBuffer(StaticAllocationMarker m) + : mStorageSize(0), + mStorage(NULL) + {} + + public: + AccumulatorBuffer() + : mStorageSize(0), + mStorage(NULL) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + const AccumulatorBuffer& other = *getDefaultBuffer(); + resize(sNextStorageSlot); + for (S32 i = 0; i < sNextStorageSlot; i++) + { + mStorage[i] = other.mStorage[i]; + } + } + + ~AccumulatorBuffer() + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + if (isCurrent()) + { + LLThreadLocalSingletonPointer::setInstance(NULL); + } + delete[] mStorage; + } + + LL_FORCE_INLINE ACCUMULATOR& operator[](size_t index) + { + return mStorage[index]; + } + + LL_FORCE_INLINE const ACCUMULATOR& operator[](size_t index) const + { + return mStorage[index]; + } + + + AccumulatorBuffer(const AccumulatorBuffer& other) + : mStorageSize(0), + mStorage(NULL) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + resize(sNextStorageSlot); + for (S32 i = 0; i < sNextStorageSlot; i++) + { + mStorage[i] = other.mStorage[i]; + } + } + + void addSamples(const AccumulatorBuffer& other, EBufferAppendType append_type) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + llassert(mStorageSize >= sNextStorageSlot && other.mStorageSize >= sNextStorageSlot); + for (size_t i = 0; i < sNextStorageSlot; i++) + { + mStorage[i].addSamples(other.mStorage[i], append_type); + } + } + + void copyFrom(const AccumulatorBuffer& other) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + llassert(mStorageSize >= sNextStorageSlot && other.mStorageSize >= sNextStorageSlot); + for (size_t i = 0; i < sNextStorageSlot; i++) + { + mStorage[i] = other.mStorage[i]; + } + } + + void reset(const AccumulatorBuffer* other = NULL) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + llassert(mStorageSize >= sNextStorageSlot); + for (size_t i = 0; i < sNextStorageSlot; i++) + { + mStorage[i].reset(other ? &other->mStorage[i] : NULL); + } + } + + void sync(F64SecondsImplicit time_stamp) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + llassert(mStorageSize >= sNextStorageSlot); + for (size_t i = 0; i < sNextStorageSlot; i++) + { + mStorage[i].sync(time_stamp); + } + } + + void makeCurrent() + { + LLThreadLocalSingletonPointer::setInstance(mStorage); + } + + bool isCurrent() const + { + return LLThreadLocalSingletonPointer::getInstance() == mStorage; + } + + static void clearCurrent() + { + LLThreadLocalSingletonPointer::setInstance(NULL); + } + + // NOTE: this is not thread-safe. We assume that slots are reserved in the main thread before any child threads are spawned + size_t reserveSlot() + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + size_t next_slot = sNextStorageSlot++; + if (next_slot >= mStorageSize) + { + // don't perform doubling, as this should only happen during startup + // want to keep a tight bounds as we will have a lot of these buffers + resize(mStorageSize + mStorageSize / 2); + } + llassert(mStorage && next_slot < mStorageSize); + return next_slot; + } + + void resize(size_t new_size) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + if (new_size <= mStorageSize) return; + + ACCUMULATOR* old_storage = mStorage; + mStorage = new ACCUMULATOR[new_size]; + if (old_storage) + { + for (S32 i = 0; i < mStorageSize; i++) + { + mStorage[i] = old_storage[i]; + } + } + mStorageSize = new_size; + delete[] old_storage; + + self_t* default_buffer = getDefaultBuffer(); + if (this != default_buffer + && new_size > default_buffer->size()) + { + //NB: this is not thread safe, but we assume that all resizing occurs during static initialization + default_buffer->resize(new_size); + } + } + + size_t size() const + { + return getNumIndices(); + } + + size_t capacity() const + { + return mStorageSize; + } + + static size_t getNumIndices() + { + return sNextStorageSlot; + } + + static self_t* getDefaultBuffer() + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + static bool sInitialized = false; + if (!sInitialized) + { + // this buffer is allowed to leak so that trace calls from global destructors have somewhere to put their data + // so as not to trigger an access violation + sDefaultBuffer = new AccumulatorBuffer(StaticAllocationMarker()); + sInitialized = true; + sDefaultBuffer->resize(DEFAULT_ACCUMULATOR_BUFFER_SIZE); + } + return sDefaultBuffer; + } + + private: + ACCUMULATOR* mStorage; + size_t mStorageSize; + static size_t sNextStorageSlot; + static self_t* sDefaultBuffer; + }; + + template size_t AccumulatorBuffer::sNextStorageSlot = 0; + template AccumulatorBuffer* AccumulatorBuffer::sDefaultBuffer = NULL; + + class EventAccumulator + { + public: + typedef F64 value_t; + static F64 getDefaultValue() { return NaN; } + + EventAccumulator() + : mSum(0), + mMin(F32(NaN)), + mMax(F32(NaN)), + mMean(NaN), + mSumOfSquares(0), + mNumSamples(0), + mLastValue(NaN) + {} + + void record(F64 value) + { + if (mNumSamples == 0) + { + mSum = value; + mMean = value; + mMin = value; + mMax = value; + } + else + { + mSum += value; + F64 old_mean = mMean; + mMean += (value - old_mean) / (F64)mNumSamples; + mSumOfSquares += (value - old_mean) * (value - mMean); + + if (value < mMin) { mMin = value; } + else if (value > mMax) { mMax = value; } + } + + mNumSamples++; + mLastValue = value; + } + + void addSamples(const EventAccumulator& other, EBufferAppendType append_type); + void reset(const EventAccumulator* other); + void sync(F64SecondsImplicit) {} + + F64 getSum() const { return mSum; } + F32 getMin() const { return mMin; } + F32 getMax() const { return mMax; } + F64 getLastValue() const { return mLastValue; } + F64 getMean() const { return mMean; } + F64 getStandardDeviation() const { return sqrtf(mSumOfSquares / mNumSamples); } + F64 getSumOfSquares() const { return mSumOfSquares; } + S32 getSampleCount() const { return mNumSamples; } + bool hasValue() const { return mNumSamples > 0; } + + // helper utility to calculate combined sumofsquares total + static F64 mergeSumsOfSquares(const EventAccumulator& a, const EventAccumulator& b); + + private: + F64 mSum, + mLastValue; + + F64 mMean, + mSumOfSquares; + + F32 mMin, + mMax; + + S32 mNumSamples; + }; + + + class SampleAccumulator + { + public: + typedef F64 value_t; + static F64 getDefaultValue() { return NaN; } + + SampleAccumulator() + : mSum(0), + mMin(F32(NaN)), + mMax(F32(NaN)), + mMean(NaN), + mSumOfSquares(0), + mLastSampleTimeStamp(0), + mTotalSamplingTime(0), + mNumSamples(0), + mLastValue(NaN), + mHasValue(false) + {} + + void sample(F64 value) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + F64SecondsImplicit time_stamp = LLTimer::getTotalSeconds(); + + // store effect of last value + sync(time_stamp); + + if (!mHasValue) + { + mHasValue = true; + + mMin = value; + mMax = value; + mMean = value; + mLastSampleTimeStamp = time_stamp; + } + else + { + if (value < mMin) { mMin = value; } + else if (value > mMax) { mMax = value; } + } + + mLastValue = value; + mNumSamples++; + } + + void addSamples(const SampleAccumulator& other, EBufferAppendType append_type); + void reset(const SampleAccumulator* other); + + void sync(F64SecondsImplicit time_stamp) + { + if (mHasValue && time_stamp != mLastSampleTimeStamp) + { + F64SecondsImplicit delta_time = time_stamp - mLastSampleTimeStamp; + mSum += mLastValue * delta_time; + mTotalSamplingTime += delta_time; + F64 old_mean = mMean; + mMean += (delta_time / mTotalSamplingTime) * (mLastValue - old_mean); + mSumOfSquares += delta_time * (mLastValue - old_mean) * (mLastValue - mMean); + } + mLastSampleTimeStamp = time_stamp; + } + + F64 getSum() const { return mSum; } + F32 getMin() const { return mMin; } + F32 getMax() const { return mMax; } + F64 getLastValue() const { return mLastValue; } + F64 getMean() const { return mMean; } + F64 getStandardDeviation() const { return sqrtf(mSumOfSquares / mTotalSamplingTime); } + F64 getSumOfSquares() const { return mSumOfSquares; } + F64SecondsImplicit getSamplingTime() const { return mTotalSamplingTime; } + S32 getSampleCount() const { return mNumSamples; } + bool hasValue() const { return mHasValue; } + + // helper utility to calculate combined sumofsquares total + static F64 mergeSumsOfSquares(const SampleAccumulator& a, const SampleAccumulator& b); + + private: + F64 mSum, + mLastValue; + + F64 mMean, + mSumOfSquares; + + F64SecondsImplicit + mLastSampleTimeStamp, + mTotalSamplingTime; + + F32 mMin, + mMax; + + S32 mNumSamples; + // distinct from mNumSamples, since we might have inherited a last value from + // a previous sampling period + bool mHasValue; + }; + + class CountAccumulator + { + public: + typedef F64 value_t; + static F64 getDefaultValue() { return 0; } + + CountAccumulator() + : mSum(0), + mNumSamples(0) + {} + + void add(F64 value) + { + mNumSamples++; + mSum += value; + } + + void addSamples(const CountAccumulator& other, EBufferAppendType /*type*/) + { + mSum += other.mSum; + mNumSamples += other.mNumSamples; + } + + void reset(const CountAccumulator* other) + { + mNumSamples = 0; + mSum = 0; + } + + void sync(F64SecondsImplicit) {} + + F64 getSum() const { return mSum; } + + S32 getSampleCount() const { return mNumSamples; } + + bool hasValue() const { return true; } + + private: + F64 mSum; + + S32 mNumSamples; + }; + + class alignas(32) TimeBlockAccumulator + { + public: + typedef F64Seconds value_t; + static F64Seconds getDefaultValue() { return F64Seconds(0); } + + typedef TimeBlockAccumulator self_t; + + // fake classes that allows us to view different facets of underlying statistic + struct CallCountFacet + { + typedef S32 value_t; + }; + + struct SelfTimeFacet + { + typedef F64Seconds value_t; + }; + + // arrays are allocated with 32 byte alignment + void *operator new [](size_t size) + { + return ll_aligned_malloc<32>(size); + } + + void operator delete[](void* ptr, size_t size) + { + ll_aligned_free<32>(ptr); + } + + TimeBlockAccumulator(); + void addSamples(const self_t& other, EBufferAppendType append_type); + void reset(const self_t* other); + void sync(F64SecondsImplicit) {} + bool hasValue() const { return true; } + + // + // members + // + U64 mTotalTimeCounter, + mSelfTimeCounter; + S32 mCalls; + class BlockTimerStatHandle* mParent; // last acknowledged parent of this time block + class BlockTimerStatHandle* mLastCaller; // used to bootstrap tree construction + U16 mActiveCount; // number of timers with this ID active on stack + bool mMoveUpTree; // needs to be moved up the tree of timers at the end of frame + + }; + + class BlockTimerStatHandle; + + class TimeBlockTreeNode + { + public: + TimeBlockTreeNode(); + + void setParent(BlockTimerStatHandle* parent); + BlockTimerStatHandle* getParent() { return mParent; } + + BlockTimerStatHandle* mBlock; + BlockTimerStatHandle* mParent; + std::vector mChildren; + bool mCollapsed; + bool mNeedsSorting; + }; + + struct BlockTimerStackRecord + { + class BlockTimer* mActiveTimer; + class BlockTimerStatHandle* mTimeBlock; + U64 mChildTime; + }; + + struct AccumulatorBufferGroup : public LLRefCount + { + AccumulatorBufferGroup(); + AccumulatorBufferGroup(const AccumulatorBufferGroup&); + ~AccumulatorBufferGroup(); + + void handOffTo(AccumulatorBufferGroup& other); + void makeCurrent(); + bool isCurrent() const; + static void clearCurrent(); + + void append(const AccumulatorBufferGroup& other); + void merge(const AccumulatorBufferGroup& other); + void reset(AccumulatorBufferGroup* other = NULL); + void sync(); + + AccumulatorBuffer mCounts; + AccumulatorBuffer mSamples; + AccumulatorBuffer mEvents; + AccumulatorBuffer mStackTimers; + }; } #endif // LL_LLTRACEACCUMULATORS_H diff --git a/indra/llcommon/lltracerecording.cpp b/indra/llcommon/lltracerecording.cpp index 075e7c1d28..1ec83be7cb 100644 --- a/indra/llcommon/lltracerecording.cpp +++ b/indra/llcommon/lltracerecording.cpp @@ -34,7 +34,7 @@ inline F64 lerp(F64 a, F64 b, F64 u) { - return a + ((b - a) * u); + return a + ((b - a) * u); } namespace LLTrace @@ -45,388 +45,388 @@ namespace LLTrace /////////////////////////////////////////////////////////////////////// Recording::Recording(EPlayState state) -: mElapsedSeconds(0), - mActiveBuffers(NULL) +: mElapsedSeconds(0), + mActiveBuffers(NULL) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - mBuffers = new AccumulatorBufferGroup(); - setPlayState(state); + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + mBuffers = new AccumulatorBufferGroup(); + setPlayState(state); } Recording::Recording( const Recording& other ) -: mActiveBuffers(NULL) +: mActiveBuffers(NULL) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - *this = other; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + *this = other; } Recording& Recording::operator = (const Recording& other) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - // this will allow us to seamlessly start without affecting any data we've acquired from other - setPlayState(PAUSED); + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + // this will allow us to seamlessly start without affecting any data we've acquired from other + setPlayState(PAUSED); - const_cast(other).update(); - EPlayState other_play_state = other.getPlayState(); + const_cast(other).update(); + EPlayState other_play_state = other.getPlayState(); - mBuffers = other.mBuffers; + mBuffers = other.mBuffers; - // above call will clear mElapsedSeconds as a side effect, so copy it here - mElapsedSeconds = other.mElapsedSeconds; - mSamplingTimer = other.mSamplingTimer; + // above call will clear mElapsedSeconds as a side effect, so copy it here + mElapsedSeconds = other.mElapsedSeconds; + mSamplingTimer = other.mSamplingTimer; - setPlayState(other_play_state); + setPlayState(other_play_state); - return *this; + return *this; } Recording::~Recording() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - // allow recording destruction without thread recorder running, - // otherwise thread shutdown could crash if a recording outlives the thread recorder - // besides, recording construction and destruction is fine without a recorder...just don't attempt to start one - if (isStarted() && LLTrace::get_thread_recorder() != NULL) - { - LLTrace::get_thread_recorder()->deactivate(mBuffers.write()); - } + // allow recording destruction without thread recorder running, + // otherwise thread shutdown could crash if a recording outlives the thread recorder + // besides, recording construction and destruction is fine without a recorder...just don't attempt to start one + if (isStarted() && LLTrace::get_thread_recorder() != NULL) + { + LLTrace::get_thread_recorder()->deactivate(mBuffers.write()); + } } // brings recording to front of recorder stack, with up to date info void Recording::update() { #if LL_TRACE_ENABLED - if (isStarted()) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - mElapsedSeconds += mSamplingTimer.getElapsedTimeF64(); - - // must have - llassert(mActiveBuffers != NULL - && LLTrace::get_thread_recorder() != NULL); - - if (!mActiveBuffers->isCurrent() && LLTrace::get_thread_recorder() != NULL) - { - AccumulatorBufferGroup* buffers = mBuffers.write(); - LLTrace::get_thread_recorder()->deactivate(buffers); - mActiveBuffers = LLTrace::get_thread_recorder()->activate(buffers); - } - - mSamplingTimer.reset(); - } + if (isStarted()) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + mElapsedSeconds += mSamplingTimer.getElapsedTimeF64(); + + // must have + llassert(mActiveBuffers != NULL + && LLTrace::get_thread_recorder() != NULL); + + if (!mActiveBuffers->isCurrent() && LLTrace::get_thread_recorder() != NULL) + { + AccumulatorBufferGroup* buffers = mBuffers.write(); + LLTrace::get_thread_recorder()->deactivate(buffers); + mActiveBuffers = LLTrace::get_thread_recorder()->activate(buffers); + } + + mSamplingTimer.reset(); + } #endif } void Recording::handleReset() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; #if LL_TRACE_ENABLED - mBuffers.write()->reset(); + mBuffers.write()->reset(); - mElapsedSeconds = F64Seconds(0.0); - mSamplingTimer.reset(); + mElapsedSeconds = F64Seconds(0.0); + mSamplingTimer.reset(); #endif } void Recording::handleStart() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; #if LL_TRACE_ENABLED - mSamplingTimer.reset(); - mBuffers.setStayUnique(true); - // must have thread recorder running on this thread - llassert(LLTrace::get_thread_recorder() != NULL); - mActiveBuffers = LLTrace::get_thread_recorder()->activate(mBuffers.write()); + mSamplingTimer.reset(); + mBuffers.setStayUnique(true); + // must have thread recorder running on this thread + llassert(LLTrace::get_thread_recorder() != NULL); + mActiveBuffers = LLTrace::get_thread_recorder()->activate(mBuffers.write()); #endif } void Recording::handleStop() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; #if LL_TRACE_ENABLED - mElapsedSeconds += mSamplingTimer.getElapsedTimeF64(); - // must have thread recorder running on this thread - llassert(LLTrace::get_thread_recorder() != NULL); - LLTrace::get_thread_recorder()->deactivate(mBuffers.write()); - mActiveBuffers = NULL; - mBuffers.setStayUnique(false); + mElapsedSeconds += mSamplingTimer.getElapsedTimeF64(); + // must have thread recorder running on this thread + llassert(LLTrace::get_thread_recorder() != NULL); + LLTrace::get_thread_recorder()->deactivate(mBuffers.write()); + mActiveBuffers = NULL; + mBuffers.setStayUnique(false); #endif } void Recording::handleSplitTo(Recording& other) { #if LL_TRACE_ENABLED - mBuffers.write()->handOffTo(*other.mBuffers.write()); + mBuffers.write()->handOffTo(*other.mBuffers.write()); #endif } void Recording::appendRecording( Recording& other ) { #if LL_TRACE_ENABLED - update(); - other.update(); - mBuffers.write()->append(*other.mBuffers); - mElapsedSeconds += other.mElapsedSeconds; + update(); + other.update(); + mBuffers.write()->append(*other.mBuffers); + mElapsedSeconds += other.mElapsedSeconds; #endif } bool Recording::hasValue(const StatType& stat) { - update(); - const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()]; - const TimeBlockAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mStackTimers[stat.getIndex()] : NULL; - return accumulator.hasValue() || (active_accumulator && active_accumulator->hasValue()); + update(); + const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()]; + const TimeBlockAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mStackTimers[stat.getIndex()] : NULL; + return accumulator.hasValue() || (active_accumulator && active_accumulator->hasValue()); } F64Seconds Recording::getSum(const StatType& stat) { - update(); - const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()]; - const TimeBlockAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mStackTimers[stat.getIndex()] : NULL; - return F64Seconds((F64)(accumulator.mTotalTimeCounter) + (F64)(active_accumulator ? active_accumulator->mTotalTimeCounter : 0)) - / (F64)LLTrace::BlockTimer::countsPerSecond(); + update(); + const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()]; + const TimeBlockAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mStackTimers[stat.getIndex()] : NULL; + return F64Seconds((F64)(accumulator.mTotalTimeCounter) + (F64)(active_accumulator ? active_accumulator->mTotalTimeCounter : 0)) + / (F64)LLTrace::BlockTimer::countsPerSecond(); } F64Seconds Recording::getSum(const StatType& stat) { - update(); - const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()]; - const TimeBlockAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mStackTimers[stat.getIndex()] : NULL; - return F64Seconds(((F64)(accumulator.mSelfTimeCounter) + (F64)(active_accumulator ? active_accumulator->mSelfTimeCounter : 0)) / (F64)LLTrace::BlockTimer::countsPerSecond()); + update(); + const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()]; + const TimeBlockAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mStackTimers[stat.getIndex()] : NULL; + return F64Seconds(((F64)(accumulator.mSelfTimeCounter) + (F64)(active_accumulator ? active_accumulator->mSelfTimeCounter : 0)) / (F64)LLTrace::BlockTimer::countsPerSecond()); } S32 Recording::getSum(const StatType& stat) { - update(); - const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()]; - const TimeBlockAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mStackTimers[stat.getIndex()] : NULL; - return accumulator.mCalls + (active_accumulator ? active_accumulator->mCalls : 0); + update(); + const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()]; + const TimeBlockAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mStackTimers[stat.getIndex()] : NULL; + return accumulator.mCalls + (active_accumulator ? active_accumulator->mCalls : 0); } F64Seconds Recording::getPerSec(const StatType& stat) { - update(); - const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()]; - const TimeBlockAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mStackTimers[stat.getIndex()] : NULL; + update(); + const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()]; + const TimeBlockAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mStackTimers[stat.getIndex()] : NULL; - return F64Seconds((F64)(accumulator.mTotalTimeCounter + (active_accumulator ? active_accumulator->mTotalTimeCounter : 0)) - / ((F64)LLTrace::BlockTimer::countsPerSecond() * mElapsedSeconds.value())); + return F64Seconds((F64)(accumulator.mTotalTimeCounter + (active_accumulator ? active_accumulator->mTotalTimeCounter : 0)) + / ((F64)LLTrace::BlockTimer::countsPerSecond() * mElapsedSeconds.value())); } F64Seconds Recording::getPerSec(const StatType& stat) { - update(); - const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()]; - const TimeBlockAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mStackTimers[stat.getIndex()] : NULL; + update(); + const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()]; + const TimeBlockAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mStackTimers[stat.getIndex()] : NULL; - return F64Seconds((F64)(accumulator.mSelfTimeCounter + (active_accumulator ? active_accumulator->mSelfTimeCounter : 0)) - / ((F64)LLTrace::BlockTimer::countsPerSecond() * mElapsedSeconds.value())); + return F64Seconds((F64)(accumulator.mSelfTimeCounter + (active_accumulator ? active_accumulator->mSelfTimeCounter : 0)) + / ((F64)LLTrace::BlockTimer::countsPerSecond() * mElapsedSeconds.value())); } F32 Recording::getPerSec(const StatType& stat) { - update(); - const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()]; - const TimeBlockAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mStackTimers[stat.getIndex()] : NULL; - return (F32)(accumulator.mCalls + (active_accumulator ? active_accumulator->mCalls : 0)) / mElapsedSeconds.value(); + update(); + const TimeBlockAccumulator& accumulator = mBuffers->mStackTimers[stat.getIndex()]; + const TimeBlockAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mStackTimers[stat.getIndex()] : NULL; + return (F32)(accumulator.mCalls + (active_accumulator ? active_accumulator->mCalls : 0)) / mElapsedSeconds.value(); } bool Recording::hasValue(const StatType& stat) { - update(); - const CountAccumulator& accumulator = mBuffers->mCounts[stat.getIndex()]; - const CountAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mCounts[stat.getIndex()] : NULL; - return accumulator.hasValue() || (active_accumulator ? active_accumulator->hasValue() : false); + update(); + const CountAccumulator& accumulator = mBuffers->mCounts[stat.getIndex()]; + const CountAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mCounts[stat.getIndex()] : NULL; + return accumulator.hasValue() || (active_accumulator ? active_accumulator->hasValue() : false); } F64 Recording::getSum(const StatType& stat) { - update(); - const CountAccumulator& accumulator = mBuffers->mCounts[stat.getIndex()]; - const CountAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mCounts[stat.getIndex()] : NULL; - return accumulator.getSum() + (active_accumulator ? active_accumulator->getSum() : 0); + update(); + const CountAccumulator& accumulator = mBuffers->mCounts[stat.getIndex()]; + const CountAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mCounts[stat.getIndex()] : NULL; + return accumulator.getSum() + (active_accumulator ? active_accumulator->getSum() : 0); } F64 Recording::getPerSec( const StatType& stat ) { - update(); - const CountAccumulator& accumulator = mBuffers->mCounts[stat.getIndex()]; - const CountAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mCounts[stat.getIndex()] : NULL; - F64 sum = accumulator.getSum() + (active_accumulator ? active_accumulator->getSum() : 0); - return sum / mElapsedSeconds.value(); + update(); + const CountAccumulator& accumulator = mBuffers->mCounts[stat.getIndex()]; + const CountAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mCounts[stat.getIndex()] : NULL; + F64 sum = accumulator.getSum() + (active_accumulator ? active_accumulator->getSum() : 0); + return sum / mElapsedSeconds.value(); } S32 Recording::getSampleCount( const StatType& stat ) { - update(); - const CountAccumulator& accumulator = mBuffers->mCounts[stat.getIndex()]; - const CountAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mCounts[stat.getIndex()] : NULL; - return accumulator.getSampleCount() + (active_accumulator ? active_accumulator->getSampleCount() : 0); + update(); + const CountAccumulator& accumulator = mBuffers->mCounts[stat.getIndex()]; + const CountAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mCounts[stat.getIndex()] : NULL; + return accumulator.getSampleCount() + (active_accumulator ? active_accumulator->getSampleCount() : 0); } bool Recording::hasValue(const StatType& stat) { - update(); - const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()]; - const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL; - return accumulator.hasValue() || (active_accumulator && active_accumulator->hasValue()); + update(); + const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()]; + const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL; + return accumulator.hasValue() || (active_accumulator && active_accumulator->hasValue()); } F64 Recording::getMin( const StatType& stat ) { - update(); - const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()]; - const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL; - return llmin(accumulator.getMin(), active_accumulator && active_accumulator->hasValue() ? active_accumulator->getMin() : F32_MAX); + update(); + const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()]; + const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL; + return llmin(accumulator.getMin(), active_accumulator && active_accumulator->hasValue() ? active_accumulator->getMin() : F32_MAX); } F64 Recording::getMax( const StatType& stat ) { - update(); - const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()]; - const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL; - return llmax(accumulator.getMax(), active_accumulator && active_accumulator->hasValue() ? active_accumulator->getMax() : F32_MIN); + update(); + const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()]; + const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL; + return llmax(accumulator.getMax(), active_accumulator && active_accumulator->hasValue() ? active_accumulator->getMax() : F32_MIN); } F64 Recording::getMean( const StatType& stat ) { - update(); - const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()]; - const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL; - if (active_accumulator && active_accumulator->hasValue()) - { - F32 t = 0.0f; - S32 div = accumulator.getSampleCount() + active_accumulator->getSampleCount(); - if (div > 0) - { - t = active_accumulator->getSampleCount() / div; - } - return lerp(accumulator.getMean(), active_accumulator->getMean(), t); - } - else - { - return accumulator.getMean(); - } + update(); + const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()]; + const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL; + if (active_accumulator && active_accumulator->hasValue()) + { + F32 t = 0.0f; + S32 div = accumulator.getSampleCount() + active_accumulator->getSampleCount(); + if (div > 0) + { + t = active_accumulator->getSampleCount() / div; + } + return lerp(accumulator.getMean(), active_accumulator->getMean(), t); + } + else + { + return accumulator.getMean(); + } } F64 Recording::getStandardDeviation( const StatType& stat ) { - update(); - const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()]; - const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL; + update(); + const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()]; + const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL; - if (active_accumulator && active_accumulator->hasValue()) - { - F64 sum_of_squares = SampleAccumulator::mergeSumsOfSquares(accumulator, *active_accumulator); - return sqrtf(sum_of_squares / (accumulator.getSamplingTime() + active_accumulator->getSamplingTime())); - } - else - { - return accumulator.getStandardDeviation(); - } + if (active_accumulator && active_accumulator->hasValue()) + { + F64 sum_of_squares = SampleAccumulator::mergeSumsOfSquares(accumulator, *active_accumulator); + return sqrtf(sum_of_squares / (accumulator.getSamplingTime() + active_accumulator->getSamplingTime())); + } + else + { + return accumulator.getStandardDeviation(); + } } F64 Recording::getLastValue( const StatType& stat ) { - update(); - const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()]; - const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL; - return (active_accumulator && active_accumulator->hasValue() ? active_accumulator->getLastValue() : accumulator.getLastValue()); + update(); + const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()]; + const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL; + return (active_accumulator && active_accumulator->hasValue() ? active_accumulator->getLastValue() : accumulator.getLastValue()); } S32 Recording::getSampleCount( const StatType& stat ) { - update(); - const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()]; - const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL; - return accumulator.getSampleCount() + (active_accumulator && active_accumulator->hasValue() ? active_accumulator->getSampleCount() : 0); + update(); + const SampleAccumulator& accumulator = mBuffers->mSamples[stat.getIndex()]; + const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL; + return accumulator.getSampleCount() + (active_accumulator && active_accumulator->hasValue() ? active_accumulator->getSampleCount() : 0); } bool Recording::hasValue(const StatType& stat) { - update(); - const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()]; - const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL; - return accumulator.hasValue() || (active_accumulator && active_accumulator->hasValue()); + update(); + const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()]; + const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL; + return accumulator.hasValue() || (active_accumulator && active_accumulator->hasValue()); } F64 Recording::getSum( const StatType& stat) { - update(); - const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()]; - const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL; - return (F64)(accumulator.getSum() + (active_accumulator && active_accumulator->hasValue() ? active_accumulator->getSum() : 0)); + update(); + const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()]; + const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL; + return (F64)(accumulator.getSum() + (active_accumulator && active_accumulator->hasValue() ? active_accumulator->getSum() : 0)); } F64 Recording::getMin( const StatType& stat ) { - update(); - const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()]; - const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL; - return llmin(accumulator.getMin(), active_accumulator && active_accumulator->hasValue() ? active_accumulator->getMin() : F32_MAX); + update(); + const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()]; + const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL; + return llmin(accumulator.getMin(), active_accumulator && active_accumulator->hasValue() ? active_accumulator->getMin() : F32_MAX); } F64 Recording::getMax( const StatType& stat ) { - update(); - const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()]; - const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL; - return llmax(accumulator.getMax(), active_accumulator && active_accumulator->hasValue() ? active_accumulator->getMax() : F32_MIN); + update(); + const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()]; + const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL; + return llmax(accumulator.getMax(), active_accumulator && active_accumulator->hasValue() ? active_accumulator->getMax() : F32_MIN); } F64 Recording::getMean( const StatType& stat ) { - update(); - const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()]; - const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL; - if (active_accumulator && active_accumulator->hasValue()) - { - F32 t = 0.0f; - S32 div = accumulator.getSampleCount() + active_accumulator->getSampleCount(); - if (div > 0) - { - t = active_accumulator->getSampleCount() / div; - } - return lerp(accumulator.getMean(), active_accumulator->getMean(), t); - } - else - { - return accumulator.getMean(); - } + update(); + const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()]; + const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL; + if (active_accumulator && active_accumulator->hasValue()) + { + F32 t = 0.0f; + S32 div = accumulator.getSampleCount() + active_accumulator->getSampleCount(); + if (div > 0) + { + t = active_accumulator->getSampleCount() / div; + } + return lerp(accumulator.getMean(), active_accumulator->getMean(), t); + } + else + { + return accumulator.getMean(); + } } F64 Recording::getStandardDeviation( const StatType& stat ) { - update(); - const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()]; - const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL; + update(); + const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()]; + const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL; - if (active_accumulator && active_accumulator->hasValue()) - { - F64 sum_of_squares = EventAccumulator::mergeSumsOfSquares(accumulator, *active_accumulator); - return sqrtf(sum_of_squares / (accumulator.getSampleCount() + active_accumulator->getSampleCount())); - } - else - { - return accumulator.getStandardDeviation(); - } + if (active_accumulator && active_accumulator->hasValue()) + { + F64 sum_of_squares = EventAccumulator::mergeSumsOfSquares(accumulator, *active_accumulator); + return sqrtf(sum_of_squares / (accumulator.getSampleCount() + active_accumulator->getSampleCount())); + } + else + { + return accumulator.getStandardDeviation(); + } } F64 Recording::getLastValue( const StatType& stat ) { - update(); - const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()]; - const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL; - return active_accumulator ? active_accumulator->getLastValue() : accumulator.getLastValue(); + update(); + const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()]; + const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL; + return active_accumulator ? active_accumulator->getLastValue() : accumulator.getLastValue(); } S32 Recording::getSampleCount( const StatType& stat ) { - update(); - const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()]; - const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL; - return accumulator.getSampleCount() + (active_accumulator ? active_accumulator->getSampleCount() : 0); + update(); + const EventAccumulator& accumulator = mBuffers->mEvents[stat.getIndex()]; + const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL; + return accumulator.getSampleCount() + (active_accumulator ? active_accumulator->getSampleCount() : 0); } /////////////////////////////////////////////////////////////////////// @@ -434,408 +434,408 @@ S32 Recording::getSampleCount( const StatType& stat ) /////////////////////////////////////////////////////////////////////// PeriodicRecording::PeriodicRecording( size_t num_periods, EPlayState state) -: mAutoResize(num_periods == 0), - mCurPeriod(0), - mNumRecordedPeriods(0), - // This guarantee that mRecordingPeriods cannot be empty is essential for - // code in several methods. - mRecordingPeriods(num_periods ? num_periods : 1) +: mAutoResize(num_periods == 0), + mCurPeriod(0), + mNumRecordedPeriods(0), + // This guarantee that mRecordingPeriods cannot be empty is essential for + // code in several methods. + mRecordingPeriods(num_periods ? num_periods : 1) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - setPlayState(state); + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + setPlayState(state); } PeriodicRecording::~PeriodicRecording() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; } void PeriodicRecording::nextPeriod() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - if (mAutoResize) - { - mRecordingPeriods.push_back(Recording()); - } + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + if (mAutoResize) + { + mRecordingPeriods.push_back(Recording()); + } - Recording& old_recording = getCurRecording(); - inci(mCurPeriod); - old_recording.splitTo(getCurRecording()); + Recording& old_recording = getCurRecording(); + inci(mCurPeriod); + old_recording.splitTo(getCurRecording()); - // Since mRecordingPeriods always has at least one entry, we can always - // safely subtract 1 from its size(). - mNumRecordedPeriods = llmin(mRecordingPeriods.size() - 1, mNumRecordedPeriods + 1); + // Since mRecordingPeriods always has at least one entry, we can always + // safely subtract 1 from its size(). + mNumRecordedPeriods = llmin(mRecordingPeriods.size() - 1, mNumRecordedPeriods + 1); } void PeriodicRecording::appendRecording(Recording& recording) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - getCurRecording().appendRecording(recording); - nextPeriod(); + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + getCurRecording().appendRecording(recording); + nextPeriod(); } void PeriodicRecording::appendPeriodicRecording( PeriodicRecording& other ) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - if (other.mRecordingPeriods.empty()) return; - - getCurRecording().update(); - other.getCurRecording().update(); - - const auto other_num_recordings = other.getNumRecordedPeriods(); - const auto other_current_recording_index = other.mCurPeriod; - const auto other_oldest_recording_index = other.previ(other_current_recording_index, other_num_recordings); - - // append first recording into our current slot - getCurRecording().appendRecording(other.mRecordingPeriods[other_oldest_recording_index]); - - // from now on, add new recordings for everything after the first - auto other_index = other.nexti(other_oldest_recording_index); - - if (mAutoResize) - { - // push back recordings for everything in the middle - while (other_index != other_current_recording_index) - { - mRecordingPeriods.push_back(other.mRecordingPeriods[other_index]); - other.inci(other_index); - } - - // add final recording, if it wasn't already added as the first - if (other_num_recordings > 1) - { - mRecordingPeriods.push_back(other.mRecordingPeriods[other_current_recording_index]); - } - - // mRecordingPeriods is never empty() - mCurPeriod = mRecordingPeriods.size() - 1; - mNumRecordedPeriods = mCurPeriod; - } - else - { - auto num_to_copy = llmin(mRecordingPeriods.size(), other_num_recordings); - // already consumed the first recording from other, so start counting at 1 - for (size_t n = 1, srci = other_index, dsti = mCurPeriod; - n < num_to_copy; - ++n, other.inci(srci), inci(dsti)) - { - mRecordingPeriods[dsti] = other.mRecordingPeriods[srci]; - } - - // want argument to % to be positive, otherwise result could be negative and thus out of bounds - llassert(num_to_copy >= 1); - // advance to last recording period copied, and make that our current period - inci(mCurPeriod, num_to_copy - 1); - mNumRecordedPeriods = llmin(mRecordingPeriods.size() - 1, mNumRecordedPeriods + num_to_copy - 1); - } - - // end with fresh period, otherwise next appendPeriodicRecording() will merge the first - // recording period with the last one appended here - nextPeriod(); - getCurRecording().setPlayState(getPlayState()); + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + if (other.mRecordingPeriods.empty()) return; + + getCurRecording().update(); + other.getCurRecording().update(); + + const auto other_num_recordings = other.getNumRecordedPeriods(); + const auto other_current_recording_index = other.mCurPeriod; + const auto other_oldest_recording_index = other.previ(other_current_recording_index, other_num_recordings); + + // append first recording into our current slot + getCurRecording().appendRecording(other.mRecordingPeriods[other_oldest_recording_index]); + + // from now on, add new recordings for everything after the first + auto other_index = other.nexti(other_oldest_recording_index); + + if (mAutoResize) + { + // push back recordings for everything in the middle + while (other_index != other_current_recording_index) + { + mRecordingPeriods.push_back(other.mRecordingPeriods[other_index]); + other.inci(other_index); + } + + // add final recording, if it wasn't already added as the first + if (other_num_recordings > 1) + { + mRecordingPeriods.push_back(other.mRecordingPeriods[other_current_recording_index]); + } + + // mRecordingPeriods is never empty() + mCurPeriod = mRecordingPeriods.size() - 1; + mNumRecordedPeriods = mCurPeriod; + } + else + { + auto num_to_copy = llmin(mRecordingPeriods.size(), other_num_recordings); + // already consumed the first recording from other, so start counting at 1 + for (size_t n = 1, srci = other_index, dsti = mCurPeriod; + n < num_to_copy; + ++n, other.inci(srci), inci(dsti)) + { + mRecordingPeriods[dsti] = other.mRecordingPeriods[srci]; + } + + // want argument to % to be positive, otherwise result could be negative and thus out of bounds + llassert(num_to_copy >= 1); + // advance to last recording period copied, and make that our current period + inci(mCurPeriod, num_to_copy - 1); + mNumRecordedPeriods = llmin(mRecordingPeriods.size() - 1, mNumRecordedPeriods + num_to_copy - 1); + } + + // end with fresh period, otherwise next appendPeriodicRecording() will merge the first + // recording period with the last one appended here + nextPeriod(); + getCurRecording().setPlayState(getPlayState()); } F64Seconds PeriodicRecording::getDuration() const { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - F64Seconds duration; - for (size_t n = 0; n < mRecordingPeriods.size(); ++n) - { - duration += mRecordingPeriods[nexti(mCurPeriod, n)].getDuration(); - } - return duration; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + F64Seconds duration; + for (size_t n = 0; n < mRecordingPeriods.size(); ++n) + { + duration += mRecordingPeriods[nexti(mCurPeriod, n)].getDuration(); + } + return duration; } LLTrace::Recording PeriodicRecording::snapshotCurRecording() const { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - Recording recording_copy(getCurRecording()); - recording_copy.stop(); - return recording_copy; + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + Recording recording_copy(getCurRecording()); + recording_copy.stop(); + return recording_copy; } Recording& PeriodicRecording::getLastRecording() { - return getPrevRecording(1); + return getPrevRecording(1); } const Recording& PeriodicRecording::getLastRecording() const { - return getPrevRecording(1); + return getPrevRecording(1); } Recording& PeriodicRecording::getCurRecording() { - return mRecordingPeriods[mCurPeriod]; + return mRecordingPeriods[mCurPeriod]; } const Recording& PeriodicRecording::getCurRecording() const { - return mRecordingPeriods[mCurPeriod]; + return mRecordingPeriods[mCurPeriod]; } Recording& PeriodicRecording::getPrevRecording( size_t offset ) { - // reuse const implementation, but return non-const reference - return const_cast( - const_cast(this)->getPrevRecording(offset)); + // reuse const implementation, but return non-const reference + return const_cast( + const_cast(this)->getPrevRecording(offset)); } const Recording& PeriodicRecording::getPrevRecording( size_t offset ) const { - return mRecordingPeriods[previ(mCurPeriod, offset)]; + return mRecordingPeriods[previ(mCurPeriod, offset)]; } void PeriodicRecording::handleStart() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - getCurRecording().start(); + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + getCurRecording().start(); } void PeriodicRecording::handleStop() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - getCurRecording().pause(); + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + getCurRecording().pause(); } void PeriodicRecording::handleReset() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - getCurRecording().stop(); - - if (mAutoResize) - { - mRecordingPeriods.clear(); - mRecordingPeriods.push_back(Recording()); - } - else - { - for (Recording& rec : mRecordingPeriods) - { - rec.reset(); - } - } - mCurPeriod = 0; - mNumRecordedPeriods = 0; - getCurRecording().setPlayState(getPlayState()); + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + getCurRecording().stop(); + + if (mAutoResize) + { + mRecordingPeriods.clear(); + mRecordingPeriods.push_back(Recording()); + } + else + { + for (Recording& rec : mRecordingPeriods) + { + rec.reset(); + } + } + mCurPeriod = 0; + mNumRecordedPeriods = 0; + getCurRecording().setPlayState(getPlayState()); } void PeriodicRecording::handleSplitTo(PeriodicRecording& other) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - getCurRecording().splitTo(other.getCurRecording()); + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + getCurRecording().splitTo(other.getCurRecording()); } F64 PeriodicRecording::getPeriodMin( const StatType& stat, size_t num_periods /*= std::numeric_limits::max()*/ ) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - num_periods = llmin(num_periods, getNumRecordedPeriods()); + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + num_periods = llmin(num_periods, getNumRecordedPeriods()); - bool has_value = false; - F64 min_val = std::numeric_limits::max(); - for (size_t i = 1; i <= num_periods; i++) - { - Recording& recording = getPrevRecording(i); - if (recording.hasValue(stat)) - { - min_val = llmin(min_val, recording.getMin(stat)); - has_value = true; - } - } + bool has_value = false; + F64 min_val = std::numeric_limits::max(); + for (size_t i = 1; i <= num_periods; i++) + { + Recording& recording = getPrevRecording(i); + if (recording.hasValue(stat)) + { + min_val = llmin(min_val, recording.getMin(stat)); + has_value = true; + } + } - return has_value - ? min_val - : NaN; + return has_value + ? min_val + : NaN; } F64 PeriodicRecording::getPeriodMax( const StatType& stat, size_t num_periods /*= std::numeric_limits::max()*/ ) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - num_periods = llmin(num_periods, getNumRecordedPeriods()); + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + num_periods = llmin(num_periods, getNumRecordedPeriods()); - bool has_value = false; - F64 max_val = std::numeric_limits::min(); - for (size_t i = 1; i <= num_periods; i++) - { - Recording& recording = getPrevRecording(i); - if (recording.hasValue(stat)) - { - max_val = llmax(max_val, recording.getMax(stat)); - has_value = true; - } - } + bool has_value = false; + F64 max_val = std::numeric_limits::min(); + for (size_t i = 1; i <= num_periods; i++) + { + Recording& recording = getPrevRecording(i); + if (recording.hasValue(stat)) + { + max_val = llmax(max_val, recording.getMax(stat)); + has_value = true; + } + } - return has_value - ? max_val - : NaN; + return has_value + ? max_val + : NaN; } // calculates means using aggregates per period F64 PeriodicRecording::getPeriodMean( const StatType& stat, size_t num_periods /*= std::numeric_limits::max()*/ ) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - num_periods = llmin(num_periods, getNumRecordedPeriods()); + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + num_periods = llmin(num_periods, getNumRecordedPeriods()); - F64 mean = 0; - S32 valid_period_count = 0; + F64 mean = 0; + S32 valid_period_count = 0; - for (size_t i = 1; i <= num_periods; i++) - { - Recording& recording = getPrevRecording(i); - if (recording.hasValue(stat)) - { - mean += recording.getMean(stat); - valid_period_count++; - } - } + for (size_t i = 1; i <= num_periods; i++) + { + Recording& recording = getPrevRecording(i); + if (recording.hasValue(stat)) + { + mean += recording.getMean(stat); + valid_period_count++; + } + } - return valid_period_count - ? mean / (F64)valid_period_count - : NaN; + return valid_period_count + ? mean / (F64)valid_period_count + : NaN; } F64 PeriodicRecording::getPeriodStandardDeviation( const StatType& stat, size_t num_periods /*= std::numeric_limits::max()*/ ) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - num_periods = llmin(num_periods, getNumRecordedPeriods()); + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + num_periods = llmin(num_periods, getNumRecordedPeriods()); - F64 period_mean = getPeriodMean(stat, num_periods); - F64 sum_of_squares = 0; - S32 valid_period_count = 0; + F64 period_mean = getPeriodMean(stat, num_periods); + F64 sum_of_squares = 0; + S32 valid_period_count = 0; - for (size_t i = 1; i <= num_periods; i++) - { - Recording& recording = getPrevRecording(i); - if (recording.hasValue(stat)) - { - F64 delta = recording.getMean(stat) - period_mean; - sum_of_squares += delta * delta; - valid_period_count++; - } - } + for (size_t i = 1; i <= num_periods; i++) + { + Recording& recording = getPrevRecording(i); + if (recording.hasValue(stat)) + { + F64 delta = recording.getMean(stat) - period_mean; + sum_of_squares += delta * delta; + valid_period_count++; + } + } - return valid_period_count - ? sqrt((F64)sum_of_squares / (F64)valid_period_count) - : NaN; + return valid_period_count + ? sqrt((F64)sum_of_squares / (F64)valid_period_count) + : NaN; } F64 PeriodicRecording::getPeriodMin( const StatType& stat, size_t num_periods /*= std::numeric_limits::max()*/ ) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - num_periods = llmin(num_periods, getNumRecordedPeriods()); + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + num_periods = llmin(num_periods, getNumRecordedPeriods()); - bool has_value = false; - F64 min_val = std::numeric_limits::max(); - for (size_t i = 1; i <= num_periods; i++) - { - Recording& recording = getPrevRecording(i); - if (recording.hasValue(stat)) - { - min_val = llmin(min_val, recording.getMin(stat)); - has_value = true; - } - } + bool has_value = false; + F64 min_val = std::numeric_limits::max(); + for (size_t i = 1; i <= num_periods; i++) + { + Recording& recording = getPrevRecording(i); + if (recording.hasValue(stat)) + { + min_val = llmin(min_val, recording.getMin(stat)); + has_value = true; + } + } - return has_value - ? min_val - : NaN; + return has_value + ? min_val + : NaN; } F64 PeriodicRecording::getPeriodMax(const StatType& stat, size_t num_periods /*= std::numeric_limits::max()*/) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - num_periods = llmin(num_periods, getNumRecordedPeriods()); + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + num_periods = llmin(num_periods, getNumRecordedPeriods()); - bool has_value = false; - F64 max_val = std::numeric_limits::min(); - for (size_t i = 1; i <= num_periods; i++) - { - Recording& recording = getPrevRecording(i); - if (recording.hasValue(stat)) - { - max_val = llmax(max_val, recording.getMax(stat)); - has_value = true; - } - } + bool has_value = false; + F64 max_val = std::numeric_limits::min(); + for (size_t i = 1; i <= num_periods; i++) + { + Recording& recording = getPrevRecording(i); + if (recording.hasValue(stat)) + { + max_val = llmax(max_val, recording.getMax(stat)); + has_value = true; + } + } - return has_value - ? max_val - : NaN; + return has_value + ? max_val + : NaN; } F64 PeriodicRecording::getPeriodMean( const StatType& stat, size_t num_periods /*= std::numeric_limits::max()*/ ) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - num_periods = llmin(num_periods, getNumRecordedPeriods()); + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + num_periods = llmin(num_periods, getNumRecordedPeriods()); - S32 valid_period_count = 0; - F64 mean = 0; + S32 valid_period_count = 0; + F64 mean = 0; - for (size_t i = 1; i <= num_periods; i++) - { - Recording& recording = getPrevRecording(i); - if (recording.hasValue(stat)) - { - mean += recording.getMean(stat); - valid_period_count++; - } - } + for (size_t i = 1; i <= num_periods; i++) + { + Recording& recording = getPrevRecording(i); + if (recording.hasValue(stat)) + { + mean += recording.getMean(stat); + valid_period_count++; + } + } - return valid_period_count - ? mean / F64(valid_period_count) - : NaN; + return valid_period_count + ? mean / F64(valid_period_count) + : NaN; } F64 PeriodicRecording::getPeriodMedian( const StatType& stat, size_t num_periods /*= std::numeric_limits::max()*/ ) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - num_periods = llmin(num_periods, getNumRecordedPeriods()); - - std::vector buf; - for (size_t i = 1; i <= num_periods; i++) - { - Recording& recording = getPrevRecording(i); - if (recording.getDuration() > (F32Seconds)0.f) - { - if (recording.hasValue(stat)) - { - buf.push_back(recording.getMean(stat)); - } - } - } - if (buf.size()==0) - { - return 0.0f; - } - std::sort(buf.begin(), buf.end()); - - return F64((buf.size() % 2 == 0) ? (buf[buf.size() / 2 - 1] + buf[buf.size() / 2]) / 2 : buf[buf.size() / 2]); + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + num_periods = llmin(num_periods, getNumRecordedPeriods()); + + std::vector buf; + for (size_t i = 1; i <= num_periods; i++) + { + Recording& recording = getPrevRecording(i); + if (recording.getDuration() > (F32Seconds)0.f) + { + if (recording.hasValue(stat)) + { + buf.push_back(recording.getMean(stat)); + } + } + } + if (buf.size()==0) + { + return 0.0f; + } + std::sort(buf.begin(), buf.end()); + + return F64((buf.size() % 2 == 0) ? (buf[buf.size() / 2 - 1] + buf[buf.size() / 2]) / 2 : buf[buf.size() / 2]); } F64 PeriodicRecording::getPeriodStandardDeviation( const StatType& stat, size_t num_periods /*= std::numeric_limits::max()*/ ) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - num_periods = llmin(num_periods, getNumRecordedPeriods()); + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + num_periods = llmin(num_periods, getNumRecordedPeriods()); - F64 period_mean = getPeriodMean(stat, num_periods); - S32 valid_period_count = 0; - F64 sum_of_squares = 0; + F64 period_mean = getPeriodMean(stat, num_periods); + S32 valid_period_count = 0; + F64 sum_of_squares = 0; - for (size_t i = 1; i <= num_periods; i++) - { - Recording& recording = getPrevRecording(i); - if (recording.hasValue(stat)) - { - F64 delta = recording.getMean(stat) - period_mean; - sum_of_squares += delta * delta; - valid_period_count++; - } - } + for (size_t i = 1; i <= num_periods; i++) + { + Recording& recording = getPrevRecording(i); + if (recording.hasValue(stat)) + { + F64 delta = recording.getMean(stat) - period_mean; + sum_of_squares += delta * delta; + valid_period_count++; + } + } - return valid_period_count - ? sqrt(sum_of_squares / (F64)valid_period_count) - : NaN; + return valid_period_count + ? sqrt(sum_of_squares / (F64)valid_period_count) + : NaN; } /////////////////////////////////////////////////////////////////////// @@ -844,36 +844,36 @@ F64 PeriodicRecording::getPeriodStandardDeviation( const StatType class LLStopWatchControlsMixin -: public LLStopWatchControlsMixinCommon +: public LLStopWatchControlsMixinCommon { public: - typedef LLStopWatchControlsMixin self_t; - virtual void splitTo(DERIVED& other) - { - EPlayState play_state = getPlayState(); - stop(); - other.reset(); + typedef LLStopWatchControlsMixin self_t; + virtual void splitTo(DERIVED& other) + { + EPlayState play_state = getPlayState(); + stop(); + other.reset(); - handleSplitTo(other); + handleSplitTo(other); - other.setPlayState(play_state); - } + other.setPlayState(play_state); + } - virtual void splitFrom(DERIVED& other) - { - static_cast(other).handleSplitTo(*static_cast(this)); - } + virtual void splitFrom(DERIVED& other) + { + static_cast(other).handleSplitTo(*static_cast(this)); + } private: - self_t& operator = (const self_t& other) - { - // don't do anything, derived class must implement logic - } - - // atomically stop this object while starting the other - // no data can be missed in between stop and start - virtual void handleSplitTo(DERIVED& other) {}; + self_t& operator = (const self_t& other) + { + // don't do anything, derived class must implement logic + } + + // atomically stop this object while starting the other + // no data can be missed in between stop and start + virtual void handleSplitTo(DERIVED& other) {}; }; namespace LLTrace { - template - class StatType; - - template - class CountStatHandle; - - template - class SampleStatHandle; - - template - class EventStatHandle; - - template - struct RelatedTypes - { - typedef F64 fractional_t; - typedef T sum_t; - }; - - template - struct RelatedTypes > - { - typedef LLUnit::fractional_t, UNIT_T> fractional_t; - typedef LLUnit::sum_t, UNIT_T> sum_t; - }; - - template<> - struct RelatedTypes - { - typedef F64 fractional_t; - typedef S32 sum_t; - }; - - class Recording - : public LLStopWatchControlsMixin - { - public: - Recording(EPlayState state = LLStopWatchControlsMixinCommon::STOPPED); - - Recording(const Recording& other); - ~Recording(); - - Recording& operator = (const Recording& other); - - // accumulate data from subsequent, non-overlapping recording - void appendRecording(Recording& other); - - // grab latest recorded data - void update(); - - // ensure that buffers are exclusively owned by this recording - void makeUnique() { mBuffers.makeUnique(); } - - // Timer accessors - bool hasValue(const StatType& stat); - F64Seconds getSum(const StatType& stat); - F64Seconds getSum(const StatType& stat); - S32 getSum(const StatType& stat); - - F64Seconds getPerSec(const StatType& stat); - F64Seconds getPerSec(const StatType& stat); - F32 getPerSec(const StatType& stat); - - // CountStatHandle accessors - bool hasValue(const StatType& stat); - F64 getSum(const StatType& stat); - template - typename RelatedTypes::sum_t getSum(const CountStatHandle& stat) - { - return (typename RelatedTypes::sum_t)getSum(static_cast&> (stat)); - } - - F64 getPerSec(const StatType& stat); - template - typename RelatedTypes::fractional_t getPerSec(const CountStatHandle& stat) - { - return (typename RelatedTypes::fractional_t)getPerSec(static_cast&> (stat)); - } - - S32 getSampleCount(const StatType& stat); - - - // SampleStatHandle accessors - bool hasValue(const StatType& stat); - - F64 getMin(const StatType& stat); - template - T getMin(const SampleStatHandle& stat) - { - return (T)getMin(static_cast&> (stat)); - } - - F64 getMax(const StatType& stat); - template - T getMax(const SampleStatHandle& stat) - { - return (T)getMax(static_cast&> (stat)); - } - - F64 getMean(const StatType& stat); - template - typename RelatedTypes::fractional_t getMean(SampleStatHandle& stat) - { - return (typename RelatedTypes::fractional_t)getMean(static_cast&> (stat)); - } - - F64 getStandardDeviation(const StatType& stat); - template - typename RelatedTypes::fractional_t getStandardDeviation(const SampleStatHandle& stat) - { - return (typename RelatedTypes::fractional_t)getStandardDeviation(static_cast&> (stat)); - } - - F64 getLastValue(const StatType& stat); - template - T getLastValue(const SampleStatHandle& stat) - { - return (T)getLastValue(static_cast&> (stat)); - } - - S32 getSampleCount(const StatType& stat); - - // EventStatHandle accessors - bool hasValue(const StatType& stat); - - F64 getSum(const StatType& stat); - template - typename RelatedTypes::sum_t getSum(const EventStatHandle& stat) - { - return (typename RelatedTypes::sum_t)getSum(static_cast&> (stat)); - } - - F64 getMin(const StatType& stat); - template - T getMin(const EventStatHandle& stat) - { - return (T)getMin(static_cast&> (stat)); - } - - F64 getMax(const StatType& stat); - template - T getMax(const EventStatHandle& stat) - { - return (T)getMax(static_cast&> (stat)); - } - - F64 getMean(const StatType& stat); - template - typename RelatedTypes::fractional_t getMean(EventStatHandle& stat) - { - return (typename RelatedTypes::fractional_t)getMean(static_cast&> (stat)); - } - - F64 getStandardDeviation(const StatType& stat); - template - typename RelatedTypes::fractional_t getStandardDeviation(const EventStatHandle& stat) - { - return (typename RelatedTypes::fractional_t)getStandardDeviation(static_cast&> (stat)); - } - - F64 getLastValue(const StatType& stat); - template - T getLastValue(const EventStatHandle& stat) - { - return (T)getLastValue(static_cast&> (stat)); - } - - S32 getSampleCount(const StatType& stat); - - F64Seconds getDuration() const { return mElapsedSeconds; } - - protected: - friend class ThreadRecorder; - - // implementation for LLStopWatchControlsMixin - /*virtual*/ void handleStart(); - /*virtual*/ void handleStop(); - /*virtual*/ void handleReset(); - /*virtual*/ void handleSplitTo(Recording& other); - - // returns data for current thread - class ThreadRecorder* getThreadRecorder(); - - LLTimer mSamplingTimer; - F64Seconds mElapsedSeconds; - LLCopyOnWritePointer mBuffers; - AccumulatorBufferGroup* mActiveBuffers; - - }; - - class LL_COMMON_API PeriodicRecording - : public LLStopWatchControlsMixin - { - public: - PeriodicRecording(size_t num_periods, EPlayState state = STOPPED); - ~PeriodicRecording(); - - void nextPeriod(); - auto getNumRecordedPeriods() - { - // current period counts if not active - return mNumRecordedPeriods + (isStarted() ? 0 : 1); - } - - F64Seconds getDuration() const; - - void appendPeriodicRecording(PeriodicRecording& other); - void appendRecording(Recording& recording); - Recording& getLastRecording(); - const Recording& getLastRecording() const; - Recording& getCurRecording(); - const Recording& getCurRecording() const; - Recording& getPrevRecording(size_t offset); - const Recording& getPrevRecording(size_t offset) const; - Recording snapshotCurRecording() const; - - template - auto getSampleCount(const StatType& stat, size_t num_periods = std::numeric_limits::max()) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - num_periods = llmin(num_periods, getNumRecordedPeriods()); - - size_t num_samples = 0; - for (size_t i = 1; i <= num_periods; i++) - { - Recording& recording = getPrevRecording(i); - num_samples += recording.getSampleCount(stat); - } - return num_samples; - } - - // - // PERIODIC MIN - // - - // catch all for stats that have a defined sum - template - typename T::value_t getPeriodMin(const StatType& stat, size_t num_periods = std::numeric_limits::max()) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - num_periods = llmin(num_periods, getNumRecordedPeriods()); - - bool has_value = false; - typename T::value_t min_val(std::numeric_limits::max()); - for (size_t i = 1; i <= num_periods; i++) - { - Recording& recording = getPrevRecording(i); - if (recording.hasValue(stat)) - { - min_val = llmin(min_val, recording.getSum(stat)); - has_value = true; - } - } - - return has_value - ? min_val - : T::getDefaultValue(); - } - - template - T getPeriodMin(const CountStatHandle& stat, size_t num_periods = std::numeric_limits::max()) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - return T(getPeriodMin(static_cast&>(stat), num_periods)); - } - - F64 getPeriodMin(const StatType& stat, size_t num_periods = std::numeric_limits::max()); - template - T getPeriodMin(const SampleStatHandle& stat, size_t num_periods = std::numeric_limits::max()) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - return T(getPeriodMin(static_cast&>(stat), num_periods)); - } - - F64 getPeriodMin(const StatType& stat, size_t num_periods = std::numeric_limits::max()); - template - T getPeriodMin(const EventStatHandle& stat, size_t num_periods = std::numeric_limits::max()) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - return T(getPeriodMin(static_cast&>(stat), num_periods)); - } - - template - typename RelatedTypes::fractional_t getPeriodMinPerSec(const StatType& stat, size_t num_periods = std::numeric_limits::max()) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - num_periods = llmin(num_periods, getNumRecordedPeriods()); - - typename RelatedTypes::fractional_t min_val(std::numeric_limits::max()); - for (size_t i = 1; i <= num_periods; i++) - { - Recording& recording = getPrevRecording(i); - min_val = llmin(min_val, recording.getPerSec(stat)); - } - return (typename RelatedTypes::fractional_t) min_val; - } - - template - typename RelatedTypes::fractional_t getPeriodMinPerSec(const CountStatHandle& stat, size_t num_periods = std::numeric_limits::max()) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - return typename RelatedTypes::fractional_t(getPeriodMinPerSec(static_cast&>(stat), num_periods)); - } - - // - // PERIODIC MAX - // - - // catch all for stats that have a defined sum - template - typename T::value_t getPeriodMax(const StatType& stat, size_t num_periods = std::numeric_limits::max()) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - num_periods = llmin(num_periods, getNumRecordedPeriods()); - - bool has_value = false; - typename T::value_t max_val(std::numeric_limits::min()); - for (size_t i = 1; i <= num_periods; i++) - { - Recording& recording = getPrevRecording(i); - if (recording.hasValue(stat)) - { - max_val = llmax(max_val, recording.getSum(stat)); - has_value = true; - } - } - - return has_value - ? max_val - : T::getDefaultValue(); - } - - template - T getPeriodMax(const CountStatHandle& stat, size_t num_periods = std::numeric_limits::max()) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - return T(getPeriodMax(static_cast&>(stat), num_periods)); - } - - F64 getPeriodMax(const StatType& stat, size_t num_periods = std::numeric_limits::max()); - template - T getPeriodMax(const SampleStatHandle& stat, size_t num_periods = std::numeric_limits::max()) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - return T(getPeriodMax(static_cast&>(stat), num_periods)); - } - - F64 getPeriodMax(const StatType& stat, size_t num_periods = std::numeric_limits::max()); - template - T getPeriodMax(const EventStatHandle& stat, size_t num_periods = std::numeric_limits::max()) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - return T(getPeriodMax(static_cast&>(stat), num_periods)); - } - - template - typename RelatedTypes::fractional_t getPeriodMaxPerSec(const StatType& stat, size_t num_periods = std::numeric_limits::max()) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - num_periods = llmin(num_periods, getNumRecordedPeriods()); - - F64 max_val = std::numeric_limits::min(); - for (size_t i = 1; i <= num_periods; i++) - { - Recording& recording = getPrevRecording(i); - max_val = llmax(max_val, recording.getPerSec(stat)); - } - return (typename RelatedTypes::fractional_t)max_val; - } - - template - typename RelatedTypes::fractional_t getPeriodMaxPerSec(const CountStatHandle& stat, size_t num_periods = std::numeric_limits::max()) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - return typename RelatedTypes::fractional_t(getPeriodMaxPerSec(static_cast&>(stat), num_periods)); - } - - // - // PERIODIC MEAN - // - - // catch all for stats that have a defined sum - template - typename RelatedTypes::fractional_t getPeriodMean(const StatType& stat, size_t num_periods = std::numeric_limits::max()) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - num_periods = llmin(num_periods, getNumRecordedPeriods()); - - typename RelatedTypes::fractional_t mean(0); - - for (size_t i = 1; i <= num_periods; i++) - { - Recording& recording = getPrevRecording(i); - if (recording.getDuration() > (F32Seconds)0.f) - { - mean += recording.getSum(stat); - } - } - return (num_periods - ? typename RelatedTypes::fractional_t(mean / num_periods) - : typename RelatedTypes::fractional_t(NaN)); - } - - template - typename RelatedTypes::fractional_t getPeriodMean(const CountStatHandle& stat, size_t num_periods = std::numeric_limits::max()) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - return typename RelatedTypes::fractional_t(getPeriodMean(static_cast&>(stat), num_periods)); - } - F64 getPeriodMean(const StatType& stat, size_t num_periods = std::numeric_limits::max()); - template - typename RelatedTypes::fractional_t getPeriodMean(const SampleStatHandle& stat, size_t num_periods = std::numeric_limits::max()) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - return typename RelatedTypes::fractional_t(getPeriodMean(static_cast&>(stat), num_periods)); - } - - F64 getPeriodMean(const StatType& stat, size_t num_periods = std::numeric_limits::max()); - template - typename RelatedTypes::fractional_t getPeriodMean(const EventStatHandle& stat, size_t num_periods = std::numeric_limits::max()) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - return typename RelatedTypes::fractional_t(getPeriodMean(static_cast&>(stat), num_periods)); - } - - template - typename RelatedTypes::fractional_t getPeriodMeanPerSec(const StatType& stat, size_t num_periods = std::numeric_limits::max()) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - num_periods = llmin(num_periods, getNumRecordedPeriods()); - - typename RelatedTypes::fractional_t mean = 0; - - for (size_t i = 1; i <= num_periods; i++) - { - Recording& recording = getPrevRecording(i); - if (recording.getDuration() > (F32Seconds)0.f) - { - mean += recording.getPerSec(stat); - } - } - - return (num_periods - ? typename RelatedTypes::fractional_t(mean / num_periods) - : typename RelatedTypes::fractional_t(NaN)); - } - - template - typename RelatedTypes::fractional_t getPeriodMeanPerSec(const CountStatHandle& stat, size_t num_periods = std::numeric_limits::max()) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - return typename RelatedTypes::fractional_t(getPeriodMeanPerSec(static_cast&>(stat), num_periods)); - } - - F64 getPeriodMedian( const StatType& stat, size_t num_periods = std::numeric_limits::max()); - - template - typename RelatedTypes::fractional_t getPeriodMedianPerSec(const StatType& stat, size_t num_periods = std::numeric_limits::max()) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - num_periods = llmin(num_periods, getNumRecordedPeriods()); - - std::vector ::fractional_t> buf; - for (size_t i = 1; i <= num_periods; i++) - { - Recording& recording = getPrevRecording(i); - if (recording.getDuration() > (F32Seconds)0.f) - { - buf.push_back(recording.getPerSec(stat)); - } - } - std::sort(buf.begin(), buf.end()); - - return typename RelatedTypes::fractional_t((buf.size() % 2 == 0) ? (buf[buf.size() / 2 - 1] + buf[buf.size() / 2]) / 2 : buf[buf.size() / 2]); - } - - template - typename RelatedTypes::fractional_t getPeriodMedianPerSec(const CountStatHandle& stat, size_t num_periods = std::numeric_limits::max()) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - return typename RelatedTypes::fractional_t(getPeriodMedianPerSec(static_cast&>(stat), num_periods)); - } - - // - // PERIODIC STANDARD DEVIATION - // - - F64 getPeriodStandardDeviation(const StatType& stat, size_t num_periods = std::numeric_limits::max()); - - template - typename RelatedTypes::fractional_t getPeriodStandardDeviation(const SampleStatHandle& stat, size_t num_periods = std::numeric_limits::max()) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - return typename RelatedTypes::fractional_t(getPeriodStandardDeviation(static_cast&>(stat), num_periods)); - } - - F64 getPeriodStandardDeviation(const StatType& stat, size_t num_periods = std::numeric_limits::max()); - template - typename RelatedTypes::fractional_t getPeriodStandardDeviation(const EventStatHandle& stat, size_t num_periods = std::numeric_limits::max()) - { - LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - return typename RelatedTypes::fractional_t(getPeriodStandardDeviation(static_cast&>(stat), num_periods)); - } - - private: - // implementation for LLStopWatchControlsMixin - /*virtual*/ void handleStart(); - /*virtual*/ void handleStop(); - /*virtual*/ void handleReset(); - /*virtual*/ void handleSplitTo(PeriodicRecording& other); - - // helper methods for wraparound ring-buffer arithmetic - inline - size_t wrapi(size_t i) const - { - return i % mRecordingPeriods.size(); - } - - inline - size_t nexti(size_t i, size_t offset=1) const - { - return wrapi(i + offset); - } - - inline - size_t previ(size_t i, size_t offset=1) const - { - auto num_periods = mRecordingPeriods.size(); - // constrain offset - offset = llclamp(offset, 0, num_periods - 1); - // add size() so expression can't go (unsigned) "negative" - return wrapi(i + num_periods - offset); - } - - inline - void inci(size_t& i, size_t offset=1) const - { - i = nexti(i, offset); - } - - private: - std::vector mRecordingPeriods; - const bool mAutoResize; - size_t mCurPeriod; - size_t mNumRecordedPeriods; - }; - - PeriodicRecording& get_frame_recording(); - - class ExtendableRecording - : public LLStopWatchControlsMixin - { - public: - void extend(); - - Recording& getAcceptedRecording() { return mAcceptedRecording; } - const Recording& getAcceptedRecording() const {return mAcceptedRecording;} - - Recording& getPotentialRecording() { return mPotentialRecording; } - const Recording& getPotentialRecording() const { return mPotentialRecording;} - - private: - // implementation for LLStopWatchControlsMixin - /*virtual*/ void handleStart(); - /*virtual*/ void handleStop(); - /*virtual*/ void handleReset(); - /*virtual*/ void handleSplitTo(ExtendableRecording& other); - - private: - Recording mAcceptedRecording; - Recording mPotentialRecording; - }; - - class ExtendablePeriodicRecording - : public LLStopWatchControlsMixin - { - public: - ExtendablePeriodicRecording(); - void extend(); - - PeriodicRecording& getResults() { return mAcceptedRecording; } - const PeriodicRecording& getResults() const {return mAcceptedRecording;} - - void nextPeriod() { mPotentialRecording.nextPeriod(); } - - private: - // implementation for LLStopWatchControlsMixin - /*virtual*/ void handleStart(); - /*virtual*/ void handleStop(); - /*virtual*/ void handleReset(); - /*virtual*/ void handleSplitTo(ExtendablePeriodicRecording& other); - - private: - PeriodicRecording mAcceptedRecording; - PeriodicRecording mPotentialRecording; - }; + template + class StatType; + + template + class CountStatHandle; + + template + class SampleStatHandle; + + template + class EventStatHandle; + + template + struct RelatedTypes + { + typedef F64 fractional_t; + typedef T sum_t; + }; + + template + struct RelatedTypes > + { + typedef LLUnit::fractional_t, UNIT_T> fractional_t; + typedef LLUnit::sum_t, UNIT_T> sum_t; + }; + + template<> + struct RelatedTypes + { + typedef F64 fractional_t; + typedef S32 sum_t; + }; + + class Recording + : public LLStopWatchControlsMixin + { + public: + Recording(EPlayState state = LLStopWatchControlsMixinCommon::STOPPED); + + Recording(const Recording& other); + ~Recording(); + + Recording& operator = (const Recording& other); + + // accumulate data from subsequent, non-overlapping recording + void appendRecording(Recording& other); + + // grab latest recorded data + void update(); + + // ensure that buffers are exclusively owned by this recording + void makeUnique() { mBuffers.makeUnique(); } + + // Timer accessors + bool hasValue(const StatType& stat); + F64Seconds getSum(const StatType& stat); + F64Seconds getSum(const StatType& stat); + S32 getSum(const StatType& stat); + + F64Seconds getPerSec(const StatType& stat); + F64Seconds getPerSec(const StatType& stat); + F32 getPerSec(const StatType& stat); + + // CountStatHandle accessors + bool hasValue(const StatType& stat); + F64 getSum(const StatType& stat); + template + typename RelatedTypes::sum_t getSum(const CountStatHandle& stat) + { + return (typename RelatedTypes::sum_t)getSum(static_cast&> (stat)); + } + + F64 getPerSec(const StatType& stat); + template + typename RelatedTypes::fractional_t getPerSec(const CountStatHandle& stat) + { + return (typename RelatedTypes::fractional_t)getPerSec(static_cast&> (stat)); + } + + S32 getSampleCount(const StatType& stat); + + + // SampleStatHandle accessors + bool hasValue(const StatType& stat); + + F64 getMin(const StatType& stat); + template + T getMin(const SampleStatHandle& stat) + { + return (T)getMin(static_cast&> (stat)); + } + + F64 getMax(const StatType& stat); + template + T getMax(const SampleStatHandle& stat) + { + return (T)getMax(static_cast&> (stat)); + } + + F64 getMean(const StatType& stat); + template + typename RelatedTypes::fractional_t getMean(SampleStatHandle& stat) + { + return (typename RelatedTypes::fractional_t)getMean(static_cast&> (stat)); + } + + F64 getStandardDeviation(const StatType& stat); + template + typename RelatedTypes::fractional_t getStandardDeviation(const SampleStatHandle& stat) + { + return (typename RelatedTypes::fractional_t)getStandardDeviation(static_cast&> (stat)); + } + + F64 getLastValue(const StatType& stat); + template + T getLastValue(const SampleStatHandle& stat) + { + return (T)getLastValue(static_cast&> (stat)); + } + + S32 getSampleCount(const StatType& stat); + + // EventStatHandle accessors + bool hasValue(const StatType& stat); + + F64 getSum(const StatType& stat); + template + typename RelatedTypes::sum_t getSum(const EventStatHandle& stat) + { + return (typename RelatedTypes::sum_t)getSum(static_cast&> (stat)); + } + + F64 getMin(const StatType& stat); + template + T getMin(const EventStatHandle& stat) + { + return (T)getMin(static_cast&> (stat)); + } + + F64 getMax(const StatType& stat); + template + T getMax(const EventStatHandle& stat) + { + return (T)getMax(static_cast&> (stat)); + } + + F64 getMean(const StatType& stat); + template + typename RelatedTypes::fractional_t getMean(EventStatHandle& stat) + { + return (typename RelatedTypes::fractional_t)getMean(static_cast&> (stat)); + } + + F64 getStandardDeviation(const StatType& stat); + template + typename RelatedTypes::fractional_t getStandardDeviation(const EventStatHandle& stat) + { + return (typename RelatedTypes::fractional_t)getStandardDeviation(static_cast&> (stat)); + } + + F64 getLastValue(const StatType& stat); + template + T getLastValue(const EventStatHandle& stat) + { + return (T)getLastValue(static_cast&> (stat)); + } + + S32 getSampleCount(const StatType& stat); + + F64Seconds getDuration() const { return mElapsedSeconds; } + + protected: + friend class ThreadRecorder; + + // implementation for LLStopWatchControlsMixin + /*virtual*/ void handleStart(); + /*virtual*/ void handleStop(); + /*virtual*/ void handleReset(); + /*virtual*/ void handleSplitTo(Recording& other); + + // returns data for current thread + class ThreadRecorder* getThreadRecorder(); + + LLTimer mSamplingTimer; + F64Seconds mElapsedSeconds; + LLCopyOnWritePointer mBuffers; + AccumulatorBufferGroup* mActiveBuffers; + + }; + + class LL_COMMON_API PeriodicRecording + : public LLStopWatchControlsMixin + { + public: + PeriodicRecording(size_t num_periods, EPlayState state = STOPPED); + ~PeriodicRecording(); + + void nextPeriod(); + auto getNumRecordedPeriods() + { + // current period counts if not active + return mNumRecordedPeriods + (isStarted() ? 0 : 1); + } + + F64Seconds getDuration() const; + + void appendPeriodicRecording(PeriodicRecording& other); + void appendRecording(Recording& recording); + Recording& getLastRecording(); + const Recording& getLastRecording() const; + Recording& getCurRecording(); + const Recording& getCurRecording() const; + Recording& getPrevRecording(size_t offset); + const Recording& getPrevRecording(size_t offset) const; + Recording snapshotCurRecording() const; + + template + auto getSampleCount(const StatType& stat, size_t num_periods = std::numeric_limits::max()) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + num_periods = llmin(num_periods, getNumRecordedPeriods()); + + size_t num_samples = 0; + for (size_t i = 1; i <= num_periods; i++) + { + Recording& recording = getPrevRecording(i); + num_samples += recording.getSampleCount(stat); + } + return num_samples; + } + + // + // PERIODIC MIN + // + + // catch all for stats that have a defined sum + template + typename T::value_t getPeriodMin(const StatType& stat, size_t num_periods = std::numeric_limits::max()) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + num_periods = llmin(num_periods, getNumRecordedPeriods()); + + bool has_value = false; + typename T::value_t min_val(std::numeric_limits::max()); + for (size_t i = 1; i <= num_periods; i++) + { + Recording& recording = getPrevRecording(i); + if (recording.hasValue(stat)) + { + min_val = llmin(min_val, recording.getSum(stat)); + has_value = true; + } + } + + return has_value + ? min_val + : T::getDefaultValue(); + } + + template + T getPeriodMin(const CountStatHandle& stat, size_t num_periods = std::numeric_limits::max()) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + return T(getPeriodMin(static_cast&>(stat), num_periods)); + } + + F64 getPeriodMin(const StatType& stat, size_t num_periods = std::numeric_limits::max()); + template + T getPeriodMin(const SampleStatHandle& stat, size_t num_periods = std::numeric_limits::max()) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + return T(getPeriodMin(static_cast&>(stat), num_periods)); + } + + F64 getPeriodMin(const StatType& stat, size_t num_periods = std::numeric_limits::max()); + template + T getPeriodMin(const EventStatHandle& stat, size_t num_periods = std::numeric_limits::max()) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + return T(getPeriodMin(static_cast&>(stat), num_periods)); + } + + template + typename RelatedTypes::fractional_t getPeriodMinPerSec(const StatType& stat, size_t num_periods = std::numeric_limits::max()) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + num_periods = llmin(num_periods, getNumRecordedPeriods()); + + typename RelatedTypes::fractional_t min_val(std::numeric_limits::max()); + for (size_t i = 1; i <= num_periods; i++) + { + Recording& recording = getPrevRecording(i); + min_val = llmin(min_val, recording.getPerSec(stat)); + } + return (typename RelatedTypes::fractional_t) min_val; + } + + template + typename RelatedTypes::fractional_t getPeriodMinPerSec(const CountStatHandle& stat, size_t num_periods = std::numeric_limits::max()) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + return typename RelatedTypes::fractional_t(getPeriodMinPerSec(static_cast&>(stat), num_periods)); + } + + // + // PERIODIC MAX + // + + // catch all for stats that have a defined sum + template + typename T::value_t getPeriodMax(const StatType& stat, size_t num_periods = std::numeric_limits::max()) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + num_periods = llmin(num_periods, getNumRecordedPeriods()); + + bool has_value = false; + typename T::value_t max_val(std::numeric_limits::min()); + for (size_t i = 1; i <= num_periods; i++) + { + Recording& recording = getPrevRecording(i); + if (recording.hasValue(stat)) + { + max_val = llmax(max_val, recording.getSum(stat)); + has_value = true; + } + } + + return has_value + ? max_val + : T::getDefaultValue(); + } + + template + T getPeriodMax(const CountStatHandle& stat, size_t num_periods = std::numeric_limits::max()) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + return T(getPeriodMax(static_cast&>(stat), num_periods)); + } + + F64 getPeriodMax(const StatType& stat, size_t num_periods = std::numeric_limits::max()); + template + T getPeriodMax(const SampleStatHandle& stat, size_t num_periods = std::numeric_limits::max()) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + return T(getPeriodMax(static_cast&>(stat), num_periods)); + } + + F64 getPeriodMax(const StatType& stat, size_t num_periods = std::numeric_limits::max()); + template + T getPeriodMax(const EventStatHandle& stat, size_t num_periods = std::numeric_limits::max()) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + return T(getPeriodMax(static_cast&>(stat), num_periods)); + } + + template + typename RelatedTypes::fractional_t getPeriodMaxPerSec(const StatType& stat, size_t num_periods = std::numeric_limits::max()) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + num_periods = llmin(num_periods, getNumRecordedPeriods()); + + F64 max_val = std::numeric_limits::min(); + for (size_t i = 1; i <= num_periods; i++) + { + Recording& recording = getPrevRecording(i); + max_val = llmax(max_val, recording.getPerSec(stat)); + } + return (typename RelatedTypes::fractional_t)max_val; + } + + template + typename RelatedTypes::fractional_t getPeriodMaxPerSec(const CountStatHandle& stat, size_t num_periods = std::numeric_limits::max()) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + return typename RelatedTypes::fractional_t(getPeriodMaxPerSec(static_cast&>(stat), num_periods)); + } + + // + // PERIODIC MEAN + // + + // catch all for stats that have a defined sum + template + typename RelatedTypes::fractional_t getPeriodMean(const StatType& stat, size_t num_periods = std::numeric_limits::max()) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + num_periods = llmin(num_periods, getNumRecordedPeriods()); + + typename RelatedTypes::fractional_t mean(0); + + for (size_t i = 1; i <= num_periods; i++) + { + Recording& recording = getPrevRecording(i); + if (recording.getDuration() > (F32Seconds)0.f) + { + mean += recording.getSum(stat); + } + } + return (num_periods + ? typename RelatedTypes::fractional_t(mean / num_periods) + : typename RelatedTypes::fractional_t(NaN)); + } + + template + typename RelatedTypes::fractional_t getPeriodMean(const CountStatHandle& stat, size_t num_periods = std::numeric_limits::max()) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + return typename RelatedTypes::fractional_t(getPeriodMean(static_cast&>(stat), num_periods)); + } + F64 getPeriodMean(const StatType& stat, size_t num_periods = std::numeric_limits::max()); + template + typename RelatedTypes::fractional_t getPeriodMean(const SampleStatHandle& stat, size_t num_periods = std::numeric_limits::max()) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + return typename RelatedTypes::fractional_t(getPeriodMean(static_cast&>(stat), num_periods)); + } + + F64 getPeriodMean(const StatType& stat, size_t num_periods = std::numeric_limits::max()); + template + typename RelatedTypes::fractional_t getPeriodMean(const EventStatHandle& stat, size_t num_periods = std::numeric_limits::max()) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + return typename RelatedTypes::fractional_t(getPeriodMean(static_cast&>(stat), num_periods)); + } + + template + typename RelatedTypes::fractional_t getPeriodMeanPerSec(const StatType& stat, size_t num_periods = std::numeric_limits::max()) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + num_periods = llmin(num_periods, getNumRecordedPeriods()); + + typename RelatedTypes::fractional_t mean = 0; + + for (size_t i = 1; i <= num_periods; i++) + { + Recording& recording = getPrevRecording(i); + if (recording.getDuration() > (F32Seconds)0.f) + { + mean += recording.getPerSec(stat); + } + } + + return (num_periods + ? typename RelatedTypes::fractional_t(mean / num_periods) + : typename RelatedTypes::fractional_t(NaN)); + } + + template + typename RelatedTypes::fractional_t getPeriodMeanPerSec(const CountStatHandle& stat, size_t num_periods = std::numeric_limits::max()) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + return typename RelatedTypes::fractional_t(getPeriodMeanPerSec(static_cast&>(stat), num_periods)); + } + + F64 getPeriodMedian( const StatType& stat, size_t num_periods = std::numeric_limits::max()); + + template + typename RelatedTypes::fractional_t getPeriodMedianPerSec(const StatType& stat, size_t num_periods = std::numeric_limits::max()) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + num_periods = llmin(num_periods, getNumRecordedPeriods()); + + std::vector ::fractional_t> buf; + for (size_t i = 1; i <= num_periods; i++) + { + Recording& recording = getPrevRecording(i); + if (recording.getDuration() > (F32Seconds)0.f) + { + buf.push_back(recording.getPerSec(stat)); + } + } + std::sort(buf.begin(), buf.end()); + + return typename RelatedTypes::fractional_t((buf.size() % 2 == 0) ? (buf[buf.size() / 2 - 1] + buf[buf.size() / 2]) / 2 : buf[buf.size() / 2]); + } + + template + typename RelatedTypes::fractional_t getPeriodMedianPerSec(const CountStatHandle& stat, size_t num_periods = std::numeric_limits::max()) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + return typename RelatedTypes::fractional_t(getPeriodMedianPerSec(static_cast&>(stat), num_periods)); + } + + // + // PERIODIC STANDARD DEVIATION + // + + F64 getPeriodStandardDeviation(const StatType& stat, size_t num_periods = std::numeric_limits::max()); + + template + typename RelatedTypes::fractional_t getPeriodStandardDeviation(const SampleStatHandle& stat, size_t num_periods = std::numeric_limits::max()) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + return typename RelatedTypes::fractional_t(getPeriodStandardDeviation(static_cast&>(stat), num_periods)); + } + + F64 getPeriodStandardDeviation(const StatType& stat, size_t num_periods = std::numeric_limits::max()); + template + typename RelatedTypes::fractional_t getPeriodStandardDeviation(const EventStatHandle& stat, size_t num_periods = std::numeric_limits::max()) + { + LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; + return typename RelatedTypes::fractional_t(getPeriodStandardDeviation(static_cast&>(stat), num_periods)); + } + + private: + // implementation for LLStopWatchControlsMixin + /*virtual*/ void handleStart(); + /*virtual*/ void handleStop(); + /*virtual*/ void handleReset(); + /*virtual*/ void handleSplitTo(PeriodicRecording& other); + + // helper methods for wraparound ring-buffer arithmetic + inline + size_t wrapi(size_t i) const + { + return i % mRecordingPeriods.size(); + } + + inline + size_t nexti(size_t i, size_t offset=1) const + { + return wrapi(i + offset); + } + + inline + size_t previ(size_t i, size_t offset=1) const + { + auto num_periods = mRecordingPeriods.size(); + // constrain offset + offset = llclamp(offset, 0, num_periods - 1); + // add size() so expression can't go (unsigned) "negative" + return wrapi(i + num_periods - offset); + } + + inline + void inci(size_t& i, size_t offset=1) const + { + i = nexti(i, offset); + } + + private: + std::vector mRecordingPeriods; + const bool mAutoResize; + size_t mCurPeriod; + size_t mNumRecordedPeriods; + }; + + PeriodicRecording& get_frame_recording(); + + class ExtendableRecording + : public LLStopWatchControlsMixin + { + public: + void extend(); + + Recording& getAcceptedRecording() { return mAcceptedRecording; } + const Recording& getAcceptedRecording() const {return mAcceptedRecording;} + + Recording& getPotentialRecording() { return mPotentialRecording; } + const Recording& getPotentialRecording() const { return mPotentialRecording;} + + private: + // implementation for LLStopWatchControlsMixin + /*virtual*/ void handleStart(); + /*virtual*/ void handleStop(); + /*virtual*/ void handleReset(); + /*virtual*/ void handleSplitTo(ExtendableRecording& other); + + private: + Recording mAcceptedRecording; + Recording mPotentialRecording; + }; + + class ExtendablePeriodicRecording + : public LLStopWatchControlsMixin + { + public: + ExtendablePeriodicRecording(); + void extend(); + + PeriodicRecording& getResults() { return mAcceptedRecording; } + const PeriodicRecording& getResults() const {return mAcceptedRecording;} + + void nextPeriod() { mPotentialRecording.nextPeriod(); } + + private: + // implementation for LLStopWatchControlsMixin + /*virtual*/ void handleStart(); + /*virtual*/ void handleStop(); + /*virtual*/ void handleReset(); + /*virtual*/ void handleSplitTo(ExtendablePeriodicRecording& other); + + private: + PeriodicRecording mAcceptedRecording; + PeriodicRecording mPotentialRecording; + }; } #endif // LL_LLTRACERECORDING_H diff --git a/indra/llcommon/lltracethreadrecorder.cpp b/indra/llcommon/lltracethreadrecorder.cpp index 914bfb55dc..be3e585ef8 100644 --- a/indra/llcommon/lltracethreadrecorder.cpp +++ b/indra/llcommon/lltracethreadrecorder.cpp @@ -1,24 +1,24 @@ -/** +/** * @file lltracethreadrecorder.cpp * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2012, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -41,203 +41,203 @@ static ThreadRecorder* sMasterThreadRecorder = NULL; /////////////////////////////////////////////////////////////////////// ThreadRecorder::ThreadRecorder() -: mParentRecorder(NULL) +: mParentRecorder(NULL) { - init(); + init(); } void ThreadRecorder::init() { #if LL_TRACE_ENABLED - LLThreadLocalSingletonPointer::setInstance(&mBlockTimerStackRecord); - //NB: the ordering of initialization in this function is very fragile due to a large number of implicit dependencies - set_thread_recorder(this); - BlockTimerStatHandle& root_time_block = BlockTimer::getRootTimeBlock(); + LLThreadLocalSingletonPointer::setInstance(&mBlockTimerStackRecord); + //NB: the ordering of initialization in this function is very fragile due to a large number of implicit dependencies + set_thread_recorder(this); + BlockTimerStatHandle& root_time_block = BlockTimer::getRootTimeBlock(); - BlockTimerStackRecord* timer_stack = LLThreadLocalSingletonPointer::getInstance(); - timer_stack->mTimeBlock = &root_time_block; - timer_stack->mActiveTimer = NULL; + BlockTimerStackRecord* timer_stack = LLThreadLocalSingletonPointer::getInstance(); + timer_stack->mTimeBlock = &root_time_block; + timer_stack->mActiveTimer = NULL; - mNumTimeBlockTreeNodes = AccumulatorBuffer::getDefaultBuffer()->size(); + mNumTimeBlockTreeNodes = AccumulatorBuffer::getDefaultBuffer()->size(); - mTimeBlockTreeNodes = new TimeBlockTreeNode[mNumTimeBlockTreeNodes]; + mTimeBlockTreeNodes = new TimeBlockTreeNode[mNumTimeBlockTreeNodes]; - activate(&mThreadRecordingBuffers); + activate(&mThreadRecordingBuffers); - // initialize time block parent pointers - for (auto& base : BlockTimerStatHandle::instance_snapshot()) - { - // because of indirect derivation from LLInstanceTracker, have to downcast - BlockTimerStatHandle& time_block = static_cast(base); - TimeBlockTreeNode& tree_node = mTimeBlockTreeNodes[time_block.getIndex()]; - tree_node.mBlock = &time_block; - tree_node.mParent = &root_time_block; + // initialize time block parent pointers + for (auto& base : BlockTimerStatHandle::instance_snapshot()) + { + // because of indirect derivation from LLInstanceTracker, have to downcast + BlockTimerStatHandle& time_block = static_cast(base); + TimeBlockTreeNode& tree_node = mTimeBlockTreeNodes[time_block.getIndex()]; + tree_node.mBlock = &time_block; + tree_node.mParent = &root_time_block; - time_block.getCurrentAccumulator().mParent = &root_time_block; - } + time_block.getCurrentAccumulator().mParent = &root_time_block; + } - mRootTimer = new BlockTimer(root_time_block); - timer_stack->mActiveTimer = mRootTimer; + mRootTimer = new BlockTimer(root_time_block); + timer_stack->mActiveTimer = mRootTimer; - BlockTimer::getRootTimeBlock().getCurrentAccumulator().mActiveCount = 1; + BlockTimer::getRootTimeBlock().getCurrentAccumulator().mActiveCount = 1; - //claim_alloc(gTraceMemStat, this); - //claim_alloc(gTraceMemStat, mRootTimer); - //claim_alloc(gTraceMemStat, sizeof(TimeBlockTreeNode) * mNumTimeBlockTreeNodes); + //claim_alloc(gTraceMemStat, this); + //claim_alloc(gTraceMemStat, mRootTimer); + //claim_alloc(gTraceMemStat, sizeof(TimeBlockTreeNode) * mNumTimeBlockTreeNodes); #endif } ThreadRecorder::ThreadRecorder( ThreadRecorder& parent ) -: mParentRecorder(&parent) +: mParentRecorder(&parent) { - init(); - mParentRecorder->addChildRecorder(this); + init(); + mParentRecorder->addChildRecorder(this); } ThreadRecorder::~ThreadRecorder() { #if LL_TRACE_ENABLED - LLThreadLocalSingletonPointer::setInstance(NULL); + LLThreadLocalSingletonPointer::setInstance(NULL); - //disclaim_alloc(gTraceMemStat, this); - //disclaim_alloc(gTraceMemStat, sizeof(BlockTimer)); - //disclaim_alloc(gTraceMemStat, sizeof(TimeBlockTreeNode) * mNumTimeBlockTreeNodes); + //disclaim_alloc(gTraceMemStat, this); + //disclaim_alloc(gTraceMemStat, sizeof(BlockTimer)); + //disclaim_alloc(gTraceMemStat, sizeof(TimeBlockTreeNode) * mNumTimeBlockTreeNodes); - deactivate(&mThreadRecordingBuffers); + deactivate(&mThreadRecordingBuffers); - delete mRootTimer; + delete mRootTimer; - if (!mActiveRecordings.empty()) - { - std::for_each(mActiveRecordings.begin(), mActiveRecordings.end(), DeletePointer()); - mActiveRecordings.clear(); - } + if (!mActiveRecordings.empty()) + { + std::for_each(mActiveRecordings.begin(), mActiveRecordings.end(), DeletePointer()); + mActiveRecordings.clear(); + } - set_thread_recorder(NULL); - delete[] mTimeBlockTreeNodes; + set_thread_recorder(NULL); + delete[] mTimeBlockTreeNodes; - if (mParentRecorder) - { - mParentRecorder->removeChildRecorder(this); - } + if (mParentRecorder) + { + mParentRecorder->removeChildRecorder(this); + } #endif } TimeBlockTreeNode* ThreadRecorder::getTimeBlockTreeNode( size_t index ) { #if LL_TRACE_ENABLED - if (0 <= index && index < mNumTimeBlockTreeNodes) - { - return &mTimeBlockTreeNodes[index]; - } + if (0 <= index && index < mNumTimeBlockTreeNodes) + { + return &mTimeBlockTreeNodes[index]; + } #endif - return NULL; + return NULL; } AccumulatorBufferGroup* ThreadRecorder::activate( AccumulatorBufferGroup* recording) { #if LL_TRACE_ENABLED - ActiveRecording* active_recording = new ActiveRecording(recording); - if (!mActiveRecordings.empty()) - { - AccumulatorBufferGroup& prev_active_recording = mActiveRecordings.back()->mPartialRecording; - prev_active_recording.sync(); - BlockTimer::updateTimes(); - prev_active_recording.handOffTo(active_recording->mPartialRecording); - } - mActiveRecordings.push_back(active_recording); - - mActiveRecordings.back()->mPartialRecording.makeCurrent(); - return &active_recording->mPartialRecording; + ActiveRecording* active_recording = new ActiveRecording(recording); + if (!mActiveRecordings.empty()) + { + AccumulatorBufferGroup& prev_active_recording = mActiveRecordings.back()->mPartialRecording; + prev_active_recording.sync(); + BlockTimer::updateTimes(); + prev_active_recording.handOffTo(active_recording->mPartialRecording); + } + mActiveRecordings.push_back(active_recording); + + mActiveRecordings.back()->mPartialRecording.makeCurrent(); + return &active_recording->mPartialRecording; #else - return NULL; + return NULL; #endif } ThreadRecorder::active_recording_list_t::iterator ThreadRecorder::bringUpToDate( AccumulatorBufferGroup* recording ) { #if LL_TRACE_ENABLED - if (mActiveRecordings.empty()) return mActiveRecordings.end(); - - mActiveRecordings.back()->mPartialRecording.sync(); - BlockTimer::updateTimes(); - - active_recording_list_t::reverse_iterator it, end_it; - for (it = mActiveRecordings.rbegin(), end_it = mActiveRecordings.rend(); - it != end_it; - ++it) - { - ActiveRecording* cur_recording = *it; - - active_recording_list_t::reverse_iterator next_it = it; - ++next_it; - - // if we have another recording further down in the stack... - if (next_it != mActiveRecordings.rend()) - { - // ...push our gathered data down to it - (*next_it)->mPartialRecording.append(cur_recording->mPartialRecording); - } - - // copy accumulated measurements into result buffer and clear accumulator (mPartialRecording) - cur_recording->movePartialToTarget(); - - if (cur_recording->mTargetRecording == recording) - { - // found the recording, so return it - break; - } - } - - if (it == end_it) - { - LL_WARNS() << "Recording not active on this thread" << LL_ENDL; - } - - return (++it).base(); + if (mActiveRecordings.empty()) return mActiveRecordings.end(); + + mActiveRecordings.back()->mPartialRecording.sync(); + BlockTimer::updateTimes(); + + active_recording_list_t::reverse_iterator it, end_it; + for (it = mActiveRecordings.rbegin(), end_it = mActiveRecordings.rend(); + it != end_it; + ++it) + { + ActiveRecording* cur_recording = *it; + + active_recording_list_t::reverse_iterator next_it = it; + ++next_it; + + // if we have another recording further down in the stack... + if (next_it != mActiveRecordings.rend()) + { + // ...push our gathered data down to it + (*next_it)->mPartialRecording.append(cur_recording->mPartialRecording); + } + + // copy accumulated measurements into result buffer and clear accumulator (mPartialRecording) + cur_recording->movePartialToTarget(); + + if (cur_recording->mTargetRecording == recording) + { + // found the recording, so return it + break; + } + } + + if (it == end_it) + { + LL_WARNS() << "Recording not active on this thread" << LL_ENDL; + } + + return (++it).base(); #else - return ThreadRecorder::active_recording_list_t::iterator(); + return ThreadRecorder::active_recording_list_t::iterator(); #endif } void ThreadRecorder::deactivate( AccumulatorBufferGroup* recording ) { #if LL_TRACE_ENABLED - active_recording_list_t::iterator recording_it = bringUpToDate(recording); - // this method should only be called on a thread where the recorder is active - llassert_always(recording_it != mActiveRecordings.end()); - - ActiveRecording* recording_to_remove = *recording_it; - bool was_current = recording_to_remove->mPartialRecording.isCurrent(); - llassert(recording_to_remove->mTargetRecording == recording); - mActiveRecordings.erase(recording_it); - if (was_current) - { - if (mActiveRecordings.empty()) - { - AccumulatorBufferGroup::clearCurrent(); - } - else - { - mActiveRecordings.back()->mPartialRecording.makeCurrent(); - } - } - delete recording_to_remove; + active_recording_list_t::iterator recording_it = bringUpToDate(recording); + // this method should only be called on a thread where the recorder is active + llassert_always(recording_it != mActiveRecordings.end()); + + ActiveRecording* recording_to_remove = *recording_it; + bool was_current = recording_to_remove->mPartialRecording.isCurrent(); + llassert(recording_to_remove->mTargetRecording == recording); + mActiveRecordings.erase(recording_it); + if (was_current) + { + if (mActiveRecordings.empty()) + { + AccumulatorBufferGroup::clearCurrent(); + } + else + { + mActiveRecordings.back()->mPartialRecording.makeCurrent(); + } + } + delete recording_to_remove; #endif } -ThreadRecorder::ActiveRecording::ActiveRecording( AccumulatorBufferGroup* target ) -: mTargetRecording(target) +ThreadRecorder::ActiveRecording::ActiveRecording( AccumulatorBufferGroup* target ) +: mTargetRecording(target) {} void ThreadRecorder::ActiveRecording::movePartialToTarget() { #if LL_TRACE_ENABLED - mTargetRecording->append(mPartialRecording); - // reset based on self to keep history - mPartialRecording.reset(&mPartialRecording); + mTargetRecording->append(mPartialRecording); + // reset based on self to keep history + mPartialRecording.reset(&mPartialRecording); #endif } @@ -246,30 +246,30 @@ void ThreadRecorder::ActiveRecording::movePartialToTarget() void ThreadRecorder::addChildRecorder( class ThreadRecorder* child ) { #if LL_TRACE_ENABLED - { LLMutexLock lock(&mChildListMutex); - mChildThreadRecorders.push_back(child); - } + { LLMutexLock lock(&mChildListMutex); + mChildThreadRecorders.push_back(child); + } #endif } // called by child thread void ThreadRecorder::removeChildRecorder( class ThreadRecorder* child ) -{ +{ #if LL_TRACE_ENABLED - { LLMutexLock lock(&mChildListMutex); - mChildThreadRecorders.remove(child); - } + { LLMutexLock lock(&mChildListMutex); + mChildThreadRecorders.remove(child); + } #endif } void ThreadRecorder::pushToParent() { #if LL_TRACE_ENABLED - { LLMutexLock lock(&mSharedRecordingMutex); - LLTrace::get_thread_recorder()->bringUpToDate(&mThreadRecordingBuffers); - mSharedRecordingBuffers.append(mThreadRecordingBuffers); - mThreadRecordingBuffers.reset(); - } + { LLMutexLock lock(&mSharedRecordingMutex); + LLTrace::get_thread_recorder()->bringUpToDate(&mThreadRecordingBuffers); + mSharedRecordingBuffers.append(mThreadRecordingBuffers); + mThreadRecordingBuffers.reset(); + } #endif } @@ -278,48 +278,48 @@ void ThreadRecorder::pullFromChildren() { #if LL_TRACE_ENABLED LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; - if (mActiveRecordings.empty()) return; + if (mActiveRecordings.empty()) return; - { LLMutexLock lock(&mChildListMutex); + { LLMutexLock lock(&mChildListMutex); - AccumulatorBufferGroup& target_recording_buffers = mActiveRecordings.back()->mPartialRecording; - target_recording_buffers.sync(); - for (LLTrace::ThreadRecorder* rec : mChildThreadRecorders) - { LLMutexLock lock(&(rec->mSharedRecordingMutex)); + AccumulatorBufferGroup& target_recording_buffers = mActiveRecordings.back()->mPartialRecording; + target_recording_buffers.sync(); + for (LLTrace::ThreadRecorder* rec : mChildThreadRecorders) + { LLMutexLock lock(&(rec->mSharedRecordingMutex)); - target_recording_buffers.merge(rec->mSharedRecordingBuffers); - rec->mSharedRecordingBuffers.reset(); - } - } + target_recording_buffers.merge(rec->mSharedRecordingBuffers); + rec->mSharedRecordingBuffers.reset(); + } + } #endif } void set_master_thread_recorder( ThreadRecorder* recorder ) { - sMasterThreadRecorder = recorder; + sMasterThreadRecorder = recorder; } ThreadRecorder* get_master_thread_recorder() { - return sMasterThreadRecorder; + return sMasterThreadRecorder; } ThreadRecorder*& get_thread_recorder_ptr() { - static thread_local ThreadRecorder* s_thread_recorder; - return s_thread_recorder; + static thread_local ThreadRecorder* s_thread_recorder; + return s_thread_recorder; } ThreadRecorder* get_thread_recorder() { - return get_thread_recorder_ptr(); + return get_thread_recorder_ptr(); } void set_thread_recorder( ThreadRecorder* recorder ) { - get_thread_recorder_ptr() = recorder; + get_thread_recorder_ptr() = recorder; } } diff --git a/indra/llcommon/lltracethreadrecorder.h b/indra/llcommon/lltracethreadrecorder.h index 8ee6729ac6..e3eadfb0bd 100644 --- a/indra/llcommon/lltracethreadrecorder.h +++ b/indra/llcommon/lltracethreadrecorder.h @@ -1,25 +1,25 @@ -/** +/** * @file lltrace.h * @brief Runtime statistics accumulation. * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2012, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -35,67 +35,67 @@ namespace LLTrace { - class LL_COMMON_API ThreadRecorder - { - protected: - struct ActiveRecording; - typedef std::vector active_recording_list_t; - public: - ThreadRecorder(); - explicit ThreadRecorder(ThreadRecorder& parent); + class LL_COMMON_API ThreadRecorder + { + protected: + struct ActiveRecording; + typedef std::vector active_recording_list_t; + public: + ThreadRecorder(); + explicit ThreadRecorder(ThreadRecorder& parent); - ~ThreadRecorder(); + ~ThreadRecorder(); - AccumulatorBufferGroup* activate(AccumulatorBufferGroup* recording); - void deactivate(AccumulatorBufferGroup* recording); - active_recording_list_t::iterator bringUpToDate(AccumulatorBufferGroup* recording); + AccumulatorBufferGroup* activate(AccumulatorBufferGroup* recording); + void deactivate(AccumulatorBufferGroup* recording); + active_recording_list_t::iterator bringUpToDate(AccumulatorBufferGroup* recording); - void addChildRecorder(class ThreadRecorder* child); - void removeChildRecorder(class ThreadRecorder* child); + void addChildRecorder(class ThreadRecorder* child); + void removeChildRecorder(class ThreadRecorder* child); - // call this periodically to gather stats data from child threads - void pullFromChildren(); - void pushToParent(); + // call this periodically to gather stats data from child threads + void pullFromChildren(); + void pushToParent(); - TimeBlockTreeNode* getTimeBlockTreeNode(size_t index); + TimeBlockTreeNode* getTimeBlockTreeNode(size_t index); - protected: - void init(); + protected: + void init(); - protected: - struct ActiveRecording - { - ActiveRecording(AccumulatorBufferGroup* target); + protected: + struct ActiveRecording + { + ActiveRecording(AccumulatorBufferGroup* target); - AccumulatorBufferGroup* mTargetRecording; - AccumulatorBufferGroup mPartialRecording; + AccumulatorBufferGroup* mTargetRecording; + AccumulatorBufferGroup mPartialRecording; - void movePartialToTarget(); - }; + void movePartialToTarget(); + }; - AccumulatorBufferGroup mThreadRecordingBuffers; + AccumulatorBufferGroup mThreadRecordingBuffers; - BlockTimerStackRecord mBlockTimerStackRecord; - active_recording_list_t mActiveRecordings; + BlockTimerStackRecord mBlockTimerStackRecord; + active_recording_list_t mActiveRecordings; - class BlockTimer* mRootTimer; - TimeBlockTreeNode* mTimeBlockTreeNodes; - size_t mNumTimeBlockTreeNodes; - typedef std::list child_thread_recorder_list_t; + class BlockTimer* mRootTimer; + TimeBlockTreeNode* mTimeBlockTreeNodes; + size_t mNumTimeBlockTreeNodes; + typedef std::list child_thread_recorder_list_t; - child_thread_recorder_list_t mChildThreadRecorders; // list of child thread recorders associated with this master - LLMutex mChildListMutex; // protects access to child list - LLMutex mSharedRecordingMutex; - AccumulatorBufferGroup mSharedRecordingBuffers; - ThreadRecorder* mParentRecorder; + child_thread_recorder_list_t mChildThreadRecorders; // list of child thread recorders associated with this master + LLMutex mChildListMutex; // protects access to child list + LLMutex mSharedRecordingMutex; + AccumulatorBufferGroup mSharedRecordingBuffers; + ThreadRecorder* mParentRecorder; - }; + }; - ThreadRecorder* get_thread_recorder(); - void set_thread_recorder(ThreadRecorder*); + ThreadRecorder* get_thread_recorder(); + void set_thread_recorder(ThreadRecorder*); - void set_master_thread_recorder(ThreadRecorder*); - ThreadRecorder* get_master_thread_recorder(); + void set_master_thread_recorder(ThreadRecorder*); + ThreadRecorder* get_master_thread_recorder(); } #endif // LL_LLTRACETHREADRECORDER_H diff --git a/indra/llcommon/lltreeiterators.h b/indra/llcommon/lltreeiterators.h index ba861ae70b..cef501b987 100644 --- a/indra/llcommon/lltreeiterators.h +++ b/indra/llcommon/lltreeiterators.h @@ -33,25 +33,25 @@ * 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$ */ @@ -338,9 +338,9 @@ public: /// 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) + : mBeginFunc(beginfunc), + mEndFunc(endfunc), + mSkipChildren(false) { // Only push back this node if it's non-NULL! if (node) @@ -364,13 +364,13 @@ private: 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; + 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; } @@ -400,7 +400,7 @@ private: /// functor to extract end() child iterator func_type mEndFunc; /// flag which controls traversal of children (skip children of current node if true) - bool mSkipChildren; + bool mSkipChildren; }; /** @@ -446,10 +446,10 @@ public: /// 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) - { + : mBeginFunc(beginfunc), + mEndFunc(endfunc), + mSkipAncestors(false) + { if (! node) return; mPending.push_back(typename list_type::value_type(node, false)); @@ -478,24 +478,24 @@ private: /// 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; - } - }; + 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; - } + 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()) @@ -536,13 +536,13 @@ private: } /// list of the nodes yet to be processed - list_type mPending; + list_type mPending; /// functor to extract begin() child iterator - func_type mBeginFunc; + func_type mBeginFunc; /// functor to extract end() child iterator - func_type mEndFunc; - /// flags logic to skip traversal of ancestors of current node - bool mSkipAncestors; + func_type mEndFunc; + /// flags logic to skip traversal of ancestors of current node + bool mSkipAncestors; }; /** diff --git a/indra/llcommon/llunits.h b/indra/llcommon/llunits.h index 0fcb8281a0..122d4557bf 100644 --- a/indra/llcommon/llunits.h +++ b/indra/llcommon/llunits.h @@ -1,25 +1,25 @@ -/** +/** * @file llunits.h * @brief Unit definitions * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2012, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -51,10 +51,10 @@ LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Gigabytes); namespace LLUnits { // technically, these are kibibits, mibibits, etc. but we should stick with commonly accepted terminology -LL_DECLARE_DERIVED_UNIT(Bits, "b", Bytes, * 8 ); -LL_DECLARE_DERIVED_UNIT(Kilobits, "Kb", Bits, / 1024); -LL_DECLARE_DERIVED_UNIT(Megabits, "Mb", Kilobits, / 1024); -LL_DECLARE_DERIVED_UNIT(Gigabits, "Gb", Megabits, / 1024); +LL_DECLARE_DERIVED_UNIT(Bits, "b", Bytes, * 8 ); +LL_DECLARE_DERIVED_UNIT(Kilobits, "Kb", Bits, / 1024); +LL_DECLARE_DERIVED_UNIT(Megabits, "Mb", Kilobits, / 1024); +LL_DECLARE_DERIVED_UNIT(Gigabits, "Gb", Megabits, / 1024); } LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Bits); @@ -65,12 +65,12 @@ LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Gigabits); namespace LLUnits { LL_DECLARE_BASE_UNIT(Seconds, "s"); -LL_DECLARE_DERIVED_UNIT(Minutes, "min", Seconds, / 60); -LL_DECLARE_DERIVED_UNIT(Hours, "h", Minutes, / 60); -LL_DECLARE_DERIVED_UNIT(Days, "d", Hours, / 24); -LL_DECLARE_DERIVED_UNIT(Milliseconds, "ms", Seconds, * 1000); -LL_DECLARE_DERIVED_UNIT(Microseconds, "\x09\x3cs", Milliseconds, * 1000); -LL_DECLARE_DERIVED_UNIT(Nanoseconds, "ns", Microseconds, * 1000); +LL_DECLARE_DERIVED_UNIT(Minutes, "min", Seconds, / 60); +LL_DECLARE_DERIVED_UNIT(Hours, "h", Minutes, / 60); +LL_DECLARE_DERIVED_UNIT(Days, "d", Hours, / 24); +LL_DECLARE_DERIVED_UNIT(Milliseconds, "ms", Seconds, * 1000); +LL_DECLARE_DERIVED_UNIT(Microseconds, "\x09\x3cs", Milliseconds, * 1000); +LL_DECLARE_DERIVED_UNIT(Nanoseconds, "ns", Microseconds, * 1000); } LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Seconds); @@ -84,9 +84,9 @@ LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Nanoseconds); namespace LLUnits { LL_DECLARE_BASE_UNIT(Meters, "m"); -LL_DECLARE_DERIVED_UNIT(Kilometers, "km", Meters, / 1000); -LL_DECLARE_DERIVED_UNIT(Centimeters, "cm", Meters, * 100); -LL_DECLARE_DERIVED_UNIT(Millimeters, "mm", Meters, * 1000); +LL_DECLARE_DERIVED_UNIT(Kilometers, "km", Meters, / 1000); +LL_DECLARE_DERIVED_UNIT(Centimeters, "cm", Meters, * 100); +LL_DECLARE_DERIVED_UNIT(Millimeters, "mm", Meters, * 1000); } LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Meters); diff --git a/indra/llcommon/llunittype.h b/indra/llcommon/llunittype.h index 81f244e422..83ce0d05a8 100644 --- a/indra/llcommon/llunittype.h +++ b/indra/llcommon/llunittype.h @@ -1,25 +1,25 @@ -/** +/** * @file llunit.h * @brief Unit conversion classes * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2012, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -32,122 +32,122 @@ #include "llerror.h" //lightweight replacement of type traits for simple type equality check -template +template struct LLIsSameType { - static const bool value = false; + static const bool value = false; }; template struct LLIsSameType { - static const bool value = true; + static const bool value = true; }; // workaround for decltype() not existing and typeof() not working inline in gcc 4.2 template struct LLResultTypeAdd { - typedef LL_TYPEOF(S() + T()) type_t; + typedef LL_TYPEOF(S() + T()) type_t; }; template struct LLResultTypeSubtract { - typedef LL_TYPEOF(S() - T()) type_t; + typedef LL_TYPEOF(S() - T()) type_t; }; template struct LLResultTypeMultiply { - typedef LL_TYPEOF(S() * T()) type_t; + typedef LL_TYPEOF(S() * T()) type_t; }; template struct LLResultTypeDivide { - typedef LL_TYPEOF(S() / T(1)) type_t; + typedef LL_TYPEOF(S() / T(1)) type_t; }; template struct LLResultTypePromote { - typedef LL_TYPEOF((true) ? S() : T()) type_t; + typedef LL_TYPEOF((true) ? S() : T()) type_t; }; template struct LLUnit { - typedef LLUnit self_t; - typedef STORAGE_TYPE storage_t; - typedef void is_unit_t; - - // value initialization - LL_FORCE_INLINE explicit LLUnit(storage_t value = storage_t()) - : mValue(value) - {} - - - LL_FORCE_INLINE static self_t convert(self_t v) - { - return v; - } - - template - LL_FORCE_INLINE static self_t convert(LLUnit v) - { - self_t result; - result.mValue = (STORAGE_TYPE)v.value(); - return result; - } - - template - LL_FORCE_INLINE static self_t convert(LLUnit v) - { - self_t result; - STORAGE_TYPE divisor = ll_convert_units(v, result); - result.mValue /= divisor; - return result; - } - - template - LL_FORCE_INLINE static self_t convert(LLUnit v) - { - typedef typename LLResultTypePromote::type_t result_storage_t; - LLUnit result; - result_storage_t divisor = ll_convert_units(v, result); - result.value(result.value() / divisor); - return self_t(result.value()); - } - - - // unit initialization and conversion - template - LL_FORCE_INLINE LLUnit(LLUnit other) - : mValue(convert(other).mValue) - {} - - LL_FORCE_INLINE storage_t value() const - { - return mValue; - } - - LL_FORCE_INLINE void value(const storage_t& value) - { - mValue = value; - } - - template - storage_t valueInUnits() const - { - return LLUnit(*this).value(); - } - - template - void valueInUnits(const storage_t& value) const - { - *this = LLUnit(value); - } + typedef LLUnit self_t; + typedef STORAGE_TYPE storage_t; + typedef void is_unit_t; + + // value initialization + LL_FORCE_INLINE explicit LLUnit(storage_t value = storage_t()) + : mValue(value) + {} + + + LL_FORCE_INLINE static self_t convert(self_t v) + { + return v; + } + + template + LL_FORCE_INLINE static self_t convert(LLUnit v) + { + self_t result; + result.mValue = (STORAGE_TYPE)v.value(); + return result; + } + + template + LL_FORCE_INLINE static self_t convert(LLUnit v) + { + self_t result; + STORAGE_TYPE divisor = ll_convert_units(v, result); + result.mValue /= divisor; + return result; + } + + template + LL_FORCE_INLINE static self_t convert(LLUnit v) + { + typedef typename LLResultTypePromote::type_t result_storage_t; + LLUnit result; + result_storage_t divisor = ll_convert_units(v, result); + result.value(result.value() / divisor); + return self_t(result.value()); + } + + + // unit initialization and conversion + template + LL_FORCE_INLINE LLUnit(LLUnit other) + : mValue(convert(other).mValue) + {} + + LL_FORCE_INLINE storage_t value() const + { + return mValue; + } + + LL_FORCE_INLINE void value(const storage_t& value) + { + mValue = value; + } + + template + storage_t valueInUnits() const + { + return LLUnit(*this).value(); + } + + template + void valueInUnits(const storage_t& value) const + { + *this = LLUnit(value); + } LL_FORCE_INLINE operator storage_t() const { @@ -155,81 +155,81 @@ struct LLUnit } /*LL_FORCE_INLINE self_t& operator= (storage_t v) - { - value(v); + { + value(v); return *this; - }*/ - - LL_FORCE_INLINE void operator += (self_t other) - { - mValue += convert(other).mValue; - } - - LL_FORCE_INLINE void operator -= (self_t other) - { - mValue -= convert(other).mValue; - } - - LL_FORCE_INLINE void operator *= (const storage_t& multiplicand) - { - mValue *= multiplicand; - } - - LL_FORCE_INLINE void operator *= (const self_t& multiplicand) - { - // spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template - LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE, "Multiplication of unit types not supported."); - } - - LL_FORCE_INLINE void operator /= (const storage_t& divisor) - { - mValue /= divisor; - } - - void operator /= (const self_t& divisor) - { - // spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template - LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE, "Illegal in-place division of unit types."); - } - - template - LL_FORCE_INLINE bool operator == (const LLUnit& other) const - { - return mValue == convert(other).value(); - } - - template - LL_FORCE_INLINE bool operator != (const LLUnit& other) const - { - return mValue != convert(other).value(); - } - - template - LL_FORCE_INLINE bool operator < (const LLUnit& other) const - { - return mValue < convert(other).value(); - } - - template - LL_FORCE_INLINE bool operator <= (const LLUnit& other) const - { - return mValue <= convert(other).value(); - } - - template - LL_FORCE_INLINE bool operator > (const LLUnit& other) const - { - return mValue > convert(other).value(); - } - - template - LL_FORCE_INLINE bool operator >= (const LLUnit& other) const - { - return mValue >= convert(other).value(); - } + }*/ + + LL_FORCE_INLINE void operator += (self_t other) + { + mValue += convert(other).mValue; + } + + LL_FORCE_INLINE void operator -= (self_t other) + { + mValue -= convert(other).mValue; + } + + LL_FORCE_INLINE void operator *= (const storage_t& multiplicand) + { + mValue *= multiplicand; + } + + LL_FORCE_INLINE void operator *= (const self_t& multiplicand) + { + // spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template + LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE, "Multiplication of unit types not supported."); + } + + LL_FORCE_INLINE void operator /= (const storage_t& divisor) + { + mValue /= divisor; + } + + void operator /= (const self_t& divisor) + { + // spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template + LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE, "Illegal in-place division of unit types."); + } + + template + LL_FORCE_INLINE bool operator == (const LLUnit& other) const + { + return mValue == convert(other).value(); + } + + template + LL_FORCE_INLINE bool operator != (const LLUnit& other) const + { + return mValue != convert(other).value(); + } + + template + LL_FORCE_INLINE bool operator < (const LLUnit& other) const + { + return mValue < convert(other).value(); + } + + template + LL_FORCE_INLINE bool operator <= (const LLUnit& other) const + { + return mValue <= convert(other).value(); + } + + template + LL_FORCE_INLINE bool operator > (const LLUnit& other) const + { + return mValue > convert(other).value(); + } + + template + LL_FORCE_INLINE bool operator >= (const LLUnit& other) const + { + return mValue >= convert(other).value(); + } protected: - storage_t mValue; + storage_t mValue; }; template @@ -251,161 +251,161 @@ std::istream& operator >>(std::istream& s, LLUnit& unit) template struct LLUnitImplicit : public LLUnit { - typedef LLUnitImplicit self_t; - typedef typename LLUnit::storage_t storage_t; - typedef LLUnit base_t; - - LL_FORCE_INLINE LLUnitImplicit(storage_t value = storage_t()) - : base_t(value) - {} - - template - LL_FORCE_INLINE LLUnitImplicit(LLUnit other) - : base_t(other) - {} - - // unlike LLUnit, LLUnitImplicit is *implicitly* convertable to a POD value (F32, S32, etc) - // this allows for interoperability with legacy code - LL_FORCE_INLINE operator storage_t() const - { - return base_t::value(); - } - - using base_t::operator +=; - LL_FORCE_INLINE void operator += (storage_t value) - { + typedef LLUnitImplicit self_t; + typedef typename LLUnit::storage_t storage_t; + typedef LLUnit base_t; + + LL_FORCE_INLINE LLUnitImplicit(storage_t value = storage_t()) + : base_t(value) + {} + + template + LL_FORCE_INLINE LLUnitImplicit(LLUnit other) + : base_t(other) + {} + + // unlike LLUnit, LLUnitImplicit is *implicitly* convertable to a POD value (F32, S32, etc) + // this allows for interoperability with legacy code + LL_FORCE_INLINE operator storage_t() const + { + return base_t::value(); + } + + using base_t::operator +=; + LL_FORCE_INLINE void operator += (storage_t value) + { base_t::mValue += value; - } + } - // this overload exists to explicitly catch use of another implicit unit - // without ambiguity between conversion to storage_t vs conversion to base_t - template - LL_FORCE_INLINE void operator += (LLUnitImplicit other) - { + // this overload exists to explicitly catch use of another implicit unit + // without ambiguity between conversion to storage_t vs conversion to base_t + template + LL_FORCE_INLINE void operator += (LLUnitImplicit other) + { base_t::mValue += base_t::convert(other).value(); - } + } - using base_t::operator -=; - LL_FORCE_INLINE void operator -= (storage_t value) - { + using base_t::operator -=; + LL_FORCE_INLINE void operator -= (storage_t value) + { base_t::mValue -= value; - } + } - // this overload exists to explicitly catch use of another implicit unit - // without ambiguity between conversion to storage_t vs conversion to base_t - template - LL_FORCE_INLINE void operator -= (LLUnitImplicit other) - { + // this overload exists to explicitly catch use of another implicit unit + // without ambiguity between conversion to storage_t vs conversion to base_t + template + LL_FORCE_INLINE void operator -= (LLUnitImplicit other) + { base_t::mValue -= base_t::convert(other).value(); - } - - template - LL_FORCE_INLINE bool operator == (LLUnit other) const - { - return base_t::mValue == base_t::convert(other).value(); - } - - template - LL_FORCE_INLINE bool operator == (LLUnitImplicit other) const - { - return base_t::mValue == base_t::convert(other).value(); - } - - template - LL_FORCE_INLINE bool operator == (STORAGE_T other) const - { - return base_t::mValue == other; - } - - template - LL_FORCE_INLINE bool operator != (LLUnit other) const - { - return base_t::mValue != convert(other).value(); - } - - template - LL_FORCE_INLINE bool operator != (LLUnitImplicit other) const - { - return base_t::mValue != base_t::convert(other).value(); - } - - template - LL_FORCE_INLINE bool operator != (STORAGE_T other) const - { - return base_t::mValue != other; - } - - template - LL_FORCE_INLINE bool operator < (LLUnit other) const - { - return base_t::mValue < base_t::convert(other).value(); - } - - template - LL_FORCE_INLINE bool operator < (LLUnitImplicit other) const - { - return base_t::mValue < base_t::convert(other).value(); - } - - template - LL_FORCE_INLINE bool operator < (STORAGE_T other) const - { - return base_t::mValue < other; - } - - template - LL_FORCE_INLINE bool operator <= (LLUnit other) const - { - return base_t::mValue <= base_t::convert(other).value(); - } - - template - LL_FORCE_INLINE bool operator <= (LLUnitImplicit other) const - { - return base_t::mValue <= base_t::convert(other).value(); - } - - template - LL_FORCE_INLINE bool operator <= (STORAGE_T other) const - { - return base_t::mValue <= other; - } - - template - LL_FORCE_INLINE bool operator > (LLUnit other) const - { - return base_t::mValue > base_t::convert(other).value(); - } - - template - LL_FORCE_INLINE bool operator > (LLUnitImplicit other) const - { - return base_t::mValue > base_t::convert(other).value(); - } - - template - LL_FORCE_INLINE bool operator > (STORAGE_T other) const - { - return base_t::mValue > other; - } - - template - LL_FORCE_INLINE bool operator >= (LLUnit other) const - { - return base_t::mValue >= base_t::convert(other).value(); - } - - template - LL_FORCE_INLINE bool operator >= (LLUnitImplicit other) const - { - return base_t::mValue >= base_t::convert(other).value(); - } - - template - LL_FORCE_INLINE bool operator >= (STORAGE_T other) const - { - return base_t::mValue >= other; - } + } + + template + LL_FORCE_INLINE bool operator == (LLUnit other) const + { + return base_t::mValue == base_t::convert(other).value(); + } + + template + LL_FORCE_INLINE bool operator == (LLUnitImplicit other) const + { + return base_t::mValue == base_t::convert(other).value(); + } + + template + LL_FORCE_INLINE bool operator == (STORAGE_T other) const + { + return base_t::mValue == other; + } + + template + LL_FORCE_INLINE bool operator != (LLUnit other) const + { + return base_t::mValue != convert(other).value(); + } + + template + LL_FORCE_INLINE bool operator != (LLUnitImplicit other) const + { + return base_t::mValue != base_t::convert(other).value(); + } + + template + LL_FORCE_INLINE bool operator != (STORAGE_T other) const + { + return base_t::mValue != other; + } + + template + LL_FORCE_INLINE bool operator < (LLUnit other) const + { + return base_t::mValue < base_t::convert(other).value(); + } + + template + LL_FORCE_INLINE bool operator < (LLUnitImplicit other) const + { + return base_t::mValue < base_t::convert(other).value(); + } + + template + LL_FORCE_INLINE bool operator < (STORAGE_T other) const + { + return base_t::mValue < other; + } + + template + LL_FORCE_INLINE bool operator <= (LLUnit other) const + { + return base_t::mValue <= base_t::convert(other).value(); + } + + template + LL_FORCE_INLINE bool operator <= (LLUnitImplicit other) const + { + return base_t::mValue <= base_t::convert(other).value(); + } + + template + LL_FORCE_INLINE bool operator <= (STORAGE_T other) const + { + return base_t::mValue <= other; + } + + template + LL_FORCE_INLINE bool operator > (LLUnit other) const + { + return base_t::mValue > base_t::convert(other).value(); + } + + template + LL_FORCE_INLINE bool operator > (LLUnitImplicit other) const + { + return base_t::mValue > base_t::convert(other).value(); + } + + template + LL_FORCE_INLINE bool operator > (STORAGE_T other) const + { + return base_t::mValue > other; + } + + template + LL_FORCE_INLINE bool operator >= (LLUnit other) const + { + return base_t::mValue >= base_t::convert(other).value(); + } + + template + LL_FORCE_INLINE bool operator >= (LLUnitImplicit other) const + { + return base_t::mValue >= base_t::convert(other).value(); + } + + template + LL_FORCE_INLINE bool operator >= (STORAGE_T other) const + { + return base_t::mValue >= other; + } }; template @@ -427,49 +427,49 @@ std::istream& operator >>(std::istream& s, LLUnitImplicit& template LL_FORCE_INLINE S2 ll_convert_units(LLUnit in, LLUnit& out) { - S2 divisor(1); - - LL_STATIC_ASSERT((LLIsSameType::value - || !LLIsSameType::value - || !LLIsSameType::value), - "conversion requires compatible units"); - - if (LLIsSameType::value) - { - // T1 and T2 same type, just assign - out.value((S2)in.value()); - } - else if (T1::sLevel > T2::sLevel) - { - // reduce T1 - LLUnit new_in; - divisor *= (S2)ll_convert_units(in, new_in); - divisor *= (S2)ll_convert_units(new_in, out); - } - else - { - // reduce T2 - LLUnit new_out; - divisor *= (S2)ll_convert_units(in, new_out); - divisor *= (S2)ll_convert_units(new_out, out); - } - return divisor; + S2 divisor(1); + + LL_STATIC_ASSERT((LLIsSameType::value + || !LLIsSameType::value + || !LLIsSameType::value), + "conversion requires compatible units"); + + if (LLIsSameType::value) + { + // T1 and T2 same type, just assign + out.value((S2)in.value()); + } + else if (T1::sLevel > T2::sLevel) + { + // reduce T1 + LLUnit new_in; + divisor *= (S2)ll_convert_units(in, new_in); + divisor *= (S2)ll_convert_units(new_in, out); + } + else + { + // reduce T2 + LLUnit new_out; + divisor *= (S2)ll_convert_units(in, new_out); + divisor *= (S2)ll_convert_units(new_out, out); + } + return divisor; } template struct LLStorageType { - typedef T type_t; + typedef T type_t; }; template struct LLStorageType > { - typedef STORAGE_TYPE type_t; + typedef STORAGE_TYPE type_t; }; -// all of these operators need to perform type promotion on the storage type of the units, so they -// cannot be expressed as operations on identical types with implicit unit conversion +// all of these operators need to perform type promotion on the storage type of the units, so they +// cannot be expressed as operations on identical types with implicit unit conversion // e.g. typeof(S32Bytes(x) + F32Megabytes(y)) <==> F32Bytes // @@ -478,64 +478,64 @@ struct LLStorageType > template LL_FORCE_INLINE LLUnit::type_t, UNITS1> operator + (LLUnit first, LLUnit second) { - LLUnit::type_t, UNITS1> result(first); - result += second; - return result; + LLUnit::type_t, UNITS1> result(first); + result += second; + return result; } template LLUnit operator + (LLUnit first, UNITLESS second) { - LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE, "operator + requires compatible unit types"); - return LLUnit(0); + LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE, "operator + requires compatible unit types"); + return LLUnit(0); } template LLUnit operator + (UNITLESS first, LLUnit second) { - LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE, "operator + requires compatible unit types"); - return LLUnit(0); + LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE, "operator + requires compatible unit types"); + return LLUnit(0); } template LL_FORCE_INLINE LLUnitImplicit::type_t, UNITS1> operator + (LLUnitImplicit first, LLUnitImplicit second) { - LLUnitImplicit::type_t, UNITS1> result(first); - result += second; - return result; + LLUnitImplicit::type_t, UNITS1> result(first); + result += second; + return result; } template LL_FORCE_INLINE LLUnitImplicit::type_t, UNITS1> operator + (LLUnit first, LLUnitImplicit second) { - LLUnitImplicit::type_t, UNITS1> result(first); - result += second; - return result; + LLUnitImplicit::type_t, UNITS1> result(first); + result += second; + return result; } template LL_FORCE_INLINE LLUnitImplicit::type_t, UNITS1> operator + (LLUnitImplicit first, LLUnit second) { - LLUnitImplicit::type_t, UNITS1> result(first); - result += LLUnitImplicit(second); - return result; + LLUnitImplicit::type_t, UNITS1> result(first); + result += LLUnitImplicit(second); + return result; } template LL_FORCE_INLINE LLUnitImplicit::type_t>::type_t, UNITS> operator + (LLUnitImplicit first, UNITLESS_TYPE second) { - LLUnitImplicit::type_t>::type_t, UNITS> result(first); - result += second; - return result; + LLUnitImplicit::type_t>::type_t, UNITS> result(first); + result += second; + return result; } template LL_FORCE_INLINE LLUnitImplicit::type_t, STORAGE_TYPE>:: - type_t, UNITS> operator + (UNITLESS_TYPE first, LLUnitImplicit second) + type_t, UNITS> operator + (UNITLESS_TYPE first, LLUnitImplicit second) { - LLUnitImplicit::type_t, STORAGE_TYPE>::type_t, UNITS> result(first); - result += second; - return result; + LLUnitImplicit::type_t, STORAGE_TYPE>::type_t, UNITS> result(first); + result += second; + return result; } // @@ -544,63 +544,63 @@ LL_FORCE_INLINE LLUnitImplicit LL_FORCE_INLINE LLUnit::type_t, UNITS1> operator - (LLUnit first, LLUnit second) { - LLUnit::type_t, UNITS1> result(first); - result -= second; - return result; + LLUnit::type_t, UNITS1> result(first); + result -= second; + return result; } template LLUnit operator - (LLUnit first, UNITLESS second) { - LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE, "operator - requires compatible unit types"); - return LLUnit(0); + LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE, "operator - requires compatible unit types"); + return LLUnit(0); } template LLUnit operator - (UNITLESS first, LLUnit second) { - LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE, "operator - requires compatible unit types"); - return LLUnit(0); + LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE, "operator - requires compatible unit types"); + return LLUnit(0); } template LL_FORCE_INLINE LLUnitImplicit::type_t, UNITS1> operator - (LLUnitImplicit first, LLUnitImplicit second) { - LLUnitImplicit::type_t, UNITS1> result(first); - result -= second; - return result; + LLUnitImplicit::type_t, UNITS1> result(first); + result -= second; + return result; } template LL_FORCE_INLINE LLUnitImplicit::type_t, UNITS1> operator - (LLUnit first, LLUnitImplicit second) { - LLUnitImplicit::type_t, UNITS1> result(first); - result -= second; - return result; + LLUnitImplicit::type_t, UNITS1> result(first); + result -= second; + return result; } template LL_FORCE_INLINE LLUnitImplicit::type_t, UNITS1> operator - (LLUnitImplicit first, LLUnit second) { - LLUnitImplicit::type_t, UNITS1> result(first); - result -= LLUnitImplicit(second); - return result; + LLUnitImplicit::type_t, UNITS1> result(first); + result -= LLUnitImplicit(second); + return result; } template LL_FORCE_INLINE LLUnitImplicit::type_t>::type_t, UNITS> operator - (LLUnitImplicit first, UNITLESS_TYPE second) { - LLUnitImplicit::type_t>::type_t, UNITS> result(first); - result -= second; - return result; + LLUnitImplicit::type_t>::type_t, UNITS> result(first); + result -= second; + return result; } template LL_FORCE_INLINE LLUnitImplicit::type_t, STORAGE_TYPE>::type_t, UNITS> operator - (UNITLESS_TYPE first, LLUnitImplicit second) { - LLUnitImplicit::type_t, STORAGE_TYPE>::type_t, UNITS> result(first); - result -= second; - return result; + LLUnitImplicit::type_t, STORAGE_TYPE>::type_t, UNITS> result(first); + result -= second; + return result; } // @@ -609,41 +609,41 @@ LL_FORCE_INLINE LLUnitImplicit LLUnit operator * (LLUnit, LLUnit) { - // spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template - LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE1, "multiplication of unit types results in new unit type - not supported."); - return LLUnit(); + // spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template + LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE1, "multiplication of unit types results in new unit type - not supported."); + return LLUnit(); } template LL_FORCE_INLINE LLUnit::type_t>::type_t, UNITS> operator * (LLUnit first, UNITLESS_TYPE second) { - return LLUnit::type_t>::type_t, UNITS>(first.value() * second); + return LLUnit::type_t>::type_t, UNITS>(first.value() * second); } template LL_FORCE_INLINE LLUnit::type_t, STORAGE_TYPE>::type_t, UNITS> operator * (UNITLESS_TYPE first, LLUnit second) { - return LLUnit::type_t, STORAGE_TYPE>::type_t, UNITS>(first * second.value()); + return LLUnit::type_t, STORAGE_TYPE>::type_t, UNITS>(first * second.value()); } template LLUnitImplicit operator * (LLUnitImplicit, LLUnitImplicit) { - // spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template - LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE1, "multiplication of unit types results in new unit type - not supported."); - return LLUnitImplicit(); + // spurious use of dependent type to stop gcc from triggering the static assertion before instantiating the template + LL_BAD_TEMPLATE_INSTANTIATION(STORAGE_TYPE1, "multiplication of unit types results in new unit type - not supported."); + return LLUnitImplicit(); } template LL_FORCE_INLINE LLUnitImplicit::type_t>::type_t, UNITS> operator * (LLUnitImplicit first, UNITLESS_TYPE second) { - return LLUnitImplicit::type_t, UNITS>(first.value() * second); + return LLUnitImplicit::type_t, UNITS>(first.value() * second); } template LL_FORCE_INLINE LLUnitImplicit::type_t, STORAGE_TYPE>::type_t, UNITS> operator * (UNITLESS_TYPE first, LLUnitImplicit second) { - return LLUnitImplicit::type_t, STORAGE_TYPE>::type_t, UNITS>(first * second.value()); + return LLUnitImplicit::type_t, STORAGE_TYPE>::type_t, UNITS>(first * second.value()); } @@ -654,196 +654,196 @@ LL_FORCE_INLINE LLUnitImplicit LL_FORCE_INLINE LLUnit::type_t>::type_t, UNITS> operator / (LLUnit first, UNITLESS_TYPE second) { - return LLUnit::type_t>::type_t, UNITS>(first.value() / second); + return LLUnit::type_t>::type_t, UNITS>(first.value() / second); } template LL_FORCE_INLINE typename LLResultTypeDivide::type_t operator / (LLUnit first, LLUnit second) { - return first.value() / first.convert(second).value(); + return first.value() / first.convert(second).value(); } template LL_FORCE_INLINE LLUnitImplicit::type_t>::type_t, UNITS> operator / (LLUnitImplicit first, UNITLESS_TYPE second) { - return LLUnitImplicit::type_t>::type_t, UNITS>(first.value() / second); + return LLUnitImplicit::type_t>::type_t, UNITS>(first.value() / second); } template LL_FORCE_INLINE typename LLResultTypeDivide::type_t operator / (LLUnitImplicit first, LLUnitImplicit second) { - return (typename LLResultTypeDivide::type_t)(first.value() / first.convert(second).value()); + return (typename LLResultTypeDivide::type_t)(first.value() / first.convert(second).value()); } template LL_FORCE_INLINE typename LLResultTypeDivide::type_t operator / (LLUnit first, LLUnitImplicit second) { - return (typename LLResultTypeDivide::type_t)(first.value() / first.convert(second).value()); + return (typename LLResultTypeDivide::type_t)(first.value() / first.convert(second).value()); } template LL_FORCE_INLINE typename LLResultTypeDivide::type_t operator / (LLUnitImplicit first, LLUnit second) { - return (typename LLResultTypeDivide::type_t)(first.value() / first.convert(second).value()); + return (typename LLResultTypeDivide::type_t)(first.value() / first.convert(second).value()); } -template +template struct LLGetUnitLabel { - static const char* getUnitLabel() { return ""; } + static const char* getUnitLabel() { return ""; } }; template struct LLGetUnitLabel > { - static const char* getUnitLabel() { return T::getUnitLabel(); } + static const char* getUnitLabel() { return T::getUnitLabel(); } }; template struct LLUnitLinearOps { - typedef LLUnitLinearOps self_t; - - LLUnitLinearOps(T val) - : mValue(val), - mDivisor(1) - {} - - template - self_t operator * (OTHER_T other) - { - return mValue * other; - } - - template - self_t operator / (OTHER_T other) - { - mDivisor *= other; - return *this; - } - - template - self_t operator + (OTHER_T other) - { - mValue += other * mDivisor; - return *this; - } - - template - self_t operator - (OTHER_T other) - { - mValue -= other * mDivisor; - return *this; - } - - T mValue; - T mDivisor; + typedef LLUnitLinearOps self_t; + + LLUnitLinearOps(T val) + : mValue(val), + mDivisor(1) + {} + + template + self_t operator * (OTHER_T other) + { + return mValue * other; + } + + template + self_t operator / (OTHER_T other) + { + mDivisor *= other; + return *this; + } + + template + self_t operator + (OTHER_T other) + { + mValue += other * mDivisor; + return *this; + } + + template + self_t operator - (OTHER_T other) + { + mValue -= other * mDivisor; + return *this; + } + + T mValue; + T mDivisor; }; template struct LLUnitInverseLinearOps { - typedef LLUnitInverseLinearOps self_t; - - LLUnitInverseLinearOps(T val) - : mValue(val), - mDivisor(1), - mMultiplicand(1) - {} - - template - self_t operator * (OTHER_T other) - { - mDivisor *= other; - return *this; - } - - template - self_t operator / (OTHER_T other) - { - mValue *= other; - mMultiplicand *= other; - return *this; - } - - template - self_t operator + (OTHER_T other) - { - mValue -= other * mMultiplicand; - return *this; - } - - template - self_t operator - (OTHER_T other) - { - mValue += other * mMultiplicand; - return *this; - } - - T mValue; - T mDivisor; - T mMultiplicand; + typedef LLUnitInverseLinearOps self_t; + + LLUnitInverseLinearOps(T val) + : mValue(val), + mDivisor(1), + mMultiplicand(1) + {} + + template + self_t operator * (OTHER_T other) + { + mDivisor *= other; + return *this; + } + + template + self_t operator / (OTHER_T other) + { + mValue *= other; + mMultiplicand *= other; + return *this; + } + + template + self_t operator + (OTHER_T other) + { + mValue -= other * mMultiplicand; + return *this; + } + + template + self_t operator - (OTHER_T other) + { + mValue += other * mMultiplicand; + return *this; + } + + T mValue; + T mDivisor; + T mMultiplicand; }; #define LL_DECLARE_BASE_UNIT(base_unit_name, unit_label) \ struct base_unit_name \ { \ - static const int sLevel = 0; \ - typedef base_unit_name base_unit_t; \ - static const char* getUnitLabel() { return unit_label; } \ - template \ - static LLUnit fromValue(T value) { return LLUnit(value); } \ - template \ - static LLUnit fromValue(LLUnit value) \ - { return LLUnit(value); } \ + static const int sLevel = 0; \ + typedef base_unit_name base_unit_t; \ + static const char* getUnitLabel() { return unit_label; } \ + template \ + static LLUnit fromValue(T value) { return LLUnit(value); } \ + template \ + static LLUnit fromValue(LLUnit value) \ + { return LLUnit(value); } \ } -#define LL_DECLARE_DERIVED_UNIT(unit_name, unit_label, base_unit_name, conversion_operation) \ +#define LL_DECLARE_DERIVED_UNIT(unit_name, unit_label, base_unit_name, conversion_operation) \ struct unit_name \ { \ - static const int sLevel = base_unit_name::sLevel + 1; \ - typedef base_unit_name base_unit_t; \ - static const char* getUnitLabel() { return unit_label; } \ - template \ - static LLUnit fromValue(T value) { return LLUnit(value); } \ - template \ - static LLUnit fromValue(LLUnit value) \ - { return LLUnit(value); } \ + static const int sLevel = base_unit_name::sLevel + 1; \ + typedef base_unit_name base_unit_t; \ + static const char* getUnitLabel() { return unit_label; } \ + template \ + static LLUnit fromValue(T value) { return LLUnit(value); } \ + template \ + static LLUnit fromValue(LLUnit value) \ + { return LLUnit(value); } \ }; \ - \ + \ template \ LL_FORCE_INLINE S2 ll_convert_units(LLUnit in, LLUnit& out) \ { \ - typedef typename LLResultTypePromote::type_t result_storage_t; \ - LLUnitInverseLinearOps result = \ - LLUnitInverseLinearOps(in.value()) conversion_operation; \ - out = LLUnit((S2)result.mValue); \ - return result.mDivisor; \ + typedef typename LLResultTypePromote::type_t result_storage_t; \ + LLUnitInverseLinearOps result = \ + LLUnitInverseLinearOps(in.value()) conversion_operation; \ + out = LLUnit((S2)result.mValue); \ + return result.mDivisor; \ } \ \ template \ LL_FORCE_INLINE S2 ll_convert_units(LLUnit in, LLUnit& out) \ { \ - typedef typename LLResultTypePromote::type_t result_storage_t; \ - LLUnitLinearOps result = \ - LLUnitLinearOps(in.value()) conversion_operation; \ - out = LLUnit((S2)result.mValue); \ - return result.mDivisor; \ -} + typedef typename LLResultTypePromote::type_t result_storage_t; \ + LLUnitLinearOps result = \ + LLUnitLinearOps(in.value()) conversion_operation; \ + out = LLUnit((S2)result.mValue); \ + return result.mDivisor; \ +} #define LL_DECLARE_UNIT_TYPEDEFS(ns, unit_name) \ - typedef LLUnit F32##unit_name; \ - typedef LLUnitImplicit F32##unit_name##Implicit;\ - typedef LLUnit F64##unit_name; \ - typedef LLUnitImplicit F64##unit_name##Implicit;\ - typedef LLUnit S32##unit_name; \ - typedef LLUnitImplicit S32##unit_name##Implicit;\ - typedef LLUnit S64##unit_name; \ - typedef LLUnitImplicit S64##unit_name##Implicit;\ - typedef LLUnit U32##unit_name; \ - typedef LLUnitImplicit U32##unit_name##Implicit;\ - typedef LLUnit U64##unit_name; \ - typedef LLUnitImplicit U64##unit_name##Implicit + typedef LLUnit F32##unit_name; \ + typedef LLUnitImplicit F32##unit_name##Implicit;\ + typedef LLUnit F64##unit_name; \ + typedef LLUnitImplicit F64##unit_name##Implicit;\ + typedef LLUnit S32##unit_name; \ + typedef LLUnitImplicit S32##unit_name##Implicit;\ + typedef LLUnit S64##unit_name; \ + typedef LLUnitImplicit S64##unit_name##Implicit;\ + typedef LLUnit U32##unit_name; \ + typedef LLUnitImplicit U32##unit_name##Implicit;\ + typedef LLUnit U64##unit_name; \ + typedef LLUnitImplicit U64##unit_name##Implicit #endif //LL_UNITTYPE_H diff --git a/indra/llcommon/lluri.cpp b/indra/llcommon/lluri.cpp index 4fb92a8f3e..e93238f0e9 100644 --- a/indra/llcommon/lluri.cpp +++ b/indra/llcommon/lluri.cpp @@ -1,4 +1,4 @@ -/** +/** * @file lluri.cpp * @author Phoenix * @date 2006-02-08 @@ -7,21 +7,21 @@ * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -32,7 +32,7 @@ #include "lluri.h" #include "llsd.h" #include - + #include "lluuid.h" // system includes @@ -43,182 +43,182 @@ // static void LLURI::encodeCharacter(std::ostream& ostr, std::string::value_type val) { - ostr << "%" + ostr << "%" - << std::uppercase - << std::hex - << std::setw(2) - << std::setfill('0') + << std::uppercase + << std::hex + << std::setw(2) + << std::setfill('0') - // VWR-4010 Cannot cast to U32 because sign-extension on - // chars > 128 will result in FFFFFFC3 instead of F3. - << static_cast(static_cast(val)) + // VWR-4010 Cannot cast to U32 because sign-extension on + // chars > 128 will result in FFFFFFC3 instead of F3. + << static_cast(static_cast(val)) - // reset stream state - << std::nouppercase - << std::dec - << std::setfill(' '); + // reset stream state + << std::nouppercase + << std::dec + << std::setfill(' '); } // static std::string LLURI::escape( - const std::string& str, - const std::string& allowed, - bool is_allowed_sorted) -{ - // *NOTE: This size determination feels like a good value to - // me. If someone wante to come up with a more precise heuristic - // with some data to back up the assertion that 'sort is good' - // then feel free to change this test a bit. - if(!is_allowed_sorted && (str.size() > 2 * allowed.size())) - { - // if it's already sorted, or if the url is quite long, we - // want to optimize this process. - std::string sorted_allowed(allowed); - std::sort(sorted_allowed.begin(), sorted_allowed.end()); - return escape(str, sorted_allowed, true); - } - - std::ostringstream ostr; - std::string::const_iterator it = str.begin(); - std::string::const_iterator end = str.end(); - std::string::value_type c; - if(is_allowed_sorted) - { - std::string::const_iterator allowed_begin(allowed.begin()); - std::string::const_iterator allowed_end(allowed.end()); - for(; it != end; ++it) - { - c = *it; - if(std::binary_search(allowed_begin, allowed_end, c)) - { - ostr << c; - } - else - { - encodeCharacter(ostr, c); - } - } - } - else - { - for(; it != end; ++it) - { - c = *it; - if(allowed.find(c) == std::string::npos) - { - encodeCharacter(ostr, c); - } - else - { - ostr << c; - } - } - } - return ostr.str(); + const std::string& str, + const std::string& allowed, + bool is_allowed_sorted) +{ + // *NOTE: This size determination feels like a good value to + // me. If someone wante to come up with a more precise heuristic + // with some data to back up the assertion that 'sort is good' + // then feel free to change this test a bit. + if(!is_allowed_sorted && (str.size() > 2 * allowed.size())) + { + // if it's already sorted, or if the url is quite long, we + // want to optimize this process. + std::string sorted_allowed(allowed); + std::sort(sorted_allowed.begin(), sorted_allowed.end()); + return escape(str, sorted_allowed, true); + } + + std::ostringstream ostr; + std::string::const_iterator it = str.begin(); + std::string::const_iterator end = str.end(); + std::string::value_type c; + if(is_allowed_sorted) + { + std::string::const_iterator allowed_begin(allowed.begin()); + std::string::const_iterator allowed_end(allowed.end()); + for(; it != end; ++it) + { + c = *it; + if(std::binary_search(allowed_begin, allowed_end, c)) + { + ostr << c; + } + else + { + encodeCharacter(ostr, c); + } + } + } + else + { + for(; it != end; ++it) + { + c = *it; + if(allowed.find(c) == std::string::npos) + { + encodeCharacter(ostr, c); + } + else + { + ostr << c; + } + } + } + return ostr.str(); } // static std::string LLURI::unescape(const std::string& str) { - std::ostringstream ostr; - std::string::const_iterator it = str.begin(); - std::string::const_iterator end = str.end(); - for(; it != end; ++it) - { - if((*it) == '%') - { - ++it; - if(it == end) break; - - if(is_char_hex(*it)) - { - U8 c = hex_as_nybble(*it++); - - c = c << 4; - if (it == end) break; - - if(is_char_hex(*it)) - { - c |= hex_as_nybble(*it); - ostr.put((char)c); - } - else - { - ostr.put((char)c); - ostr.put(*it); - } - } - else - { - ostr.put('%'); - ostr.put(*it); - } - } - else - { - ostr.put(*it); - } - } - return ostr.str(); + std::ostringstream ostr; + std::string::const_iterator it = str.begin(); + std::string::const_iterator end = str.end(); + for(; it != end; ++it) + { + if((*it) == '%') + { + ++it; + if(it == end) break; + + if(is_char_hex(*it)) + { + U8 c = hex_as_nybble(*it++); + + c = c << 4; + if (it == end) break; + + if(is_char_hex(*it)) + { + c |= hex_as_nybble(*it); + ostr.put((char)c); + } + else + { + ostr.put((char)c); + ostr.put(*it); + } + } + else + { + ostr.put('%'); + ostr.put(*it); + } + } + else + { + ostr.put(*it); + } + } + return ostr.str(); } namespace { - const std::string unreserved() - { - static const std::string s = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" - "0123456789" - "-._~"; - return s; - } - const std::string path() - { - static const std::string s = - "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz" - "0123456789" - "$-_.+" - "!*'()," - "{}|\\^~[]`" - "<>#%" - ";/?:@&="; - return s; - } - const std::string sub_delims() - { - static const std::string s = "!$&'()*+,;="; - return s; - } - - std::string escapeHostAndPort(const std::string& s) - { return LLURI::escape(s, unreserved() + sub_delims() +":"); } - std::string escapePathComponent(const std::string& s) - { return LLURI::escape(s, unreserved() + sub_delims() + ":@"); } - std::string escapeQueryVariable(const std::string& s) - { return LLURI::escape(s, unreserved() + ":@!$'()*+,"); } // sub_delims - "&;=" + ":@" - std::string escapeQueryValue(const std::string& s) - { return LLURI::escape(s, unreserved() + ":@!$'()*+,="); } // sub_delims - "&;" + ":@" - std::string escapeUriQuery(const std::string& s) - { return LLURI::escape(s, unreserved() + ":@?&$;*+=%/"); } - std::string escapeUriData(const std::string& s) - { return LLURI::escape(s, unreserved() + "%"); } - std::string escapeUriPath(const std::string& s) - { return LLURI::escape(s, path()); } + const std::string unreserved() + { + static const std::string s = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + "0123456789" + "-._~"; + return s; + } + const std::string path() + { + static const std::string s = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789" + "$-_.+" + "!*'()," + "{}|\\^~[]`" + "<>#%" + ";/?:@&="; + return s; + } + const std::string sub_delims() + { + static const std::string s = "!$&'()*+,;="; + return s; + } + + std::string escapeHostAndPort(const std::string& s) + { return LLURI::escape(s, unreserved() + sub_delims() +":"); } + std::string escapePathComponent(const std::string& s) + { return LLURI::escape(s, unreserved() + sub_delims() + ":@"); } + std::string escapeQueryVariable(const std::string& s) + { return LLURI::escape(s, unreserved() + ":@!$'()*+,"); } // sub_delims - "&;=" + ":@" + std::string escapeQueryValue(const std::string& s) + { return LLURI::escape(s, unreserved() + ":@!$'()*+,="); } // sub_delims - "&;" + ":@" + std::string escapeUriQuery(const std::string& s) + { return LLURI::escape(s, unreserved() + ":@?&$;*+=%/"); } + std::string escapeUriData(const std::string& s) + { return LLURI::escape(s, unreserved() + "%"); } + std::string escapeUriPath(const std::string& s) + { return LLURI::escape(s, path()); } } //static std::string LLURI::escape(const std::string& str) { - static std::string default_allowed = unreserved(); - static bool initialized = false; - if(!initialized) - { - std::sort(default_allowed.begin(), default_allowed.end()); - initialized = true; - } - return escape(str, default_allowed, true); + static std::string default_allowed = unreserved(); + static bool initialized = false; + if(!initialized) + { + std::sort(default_allowed.begin(), default_allowed.end()); + initialized = true; + } + return escape(str, default_allowed, true); } //static @@ -306,126 +306,126 @@ LLURI::LLURI() LLURI::LLURI(const std::string& escaped_str) { - std::string::size_type delim_pos; - delim_pos = escaped_str.find(':'); - std::string temp; - if (delim_pos == std::string::npos) - { - mScheme = ""; - mEscapedOpaque = escaped_str; - } - else - { - mScheme = escaped_str.substr(0, delim_pos); - mEscapedOpaque = escaped_str.substr(delim_pos+1); - } - - parseAuthorityAndPathUsingOpaque(); - - delim_pos = mEscapedPath.find('?'); - if (delim_pos != std::string::npos) - { - mEscapedQuery = mEscapedPath.substr(delim_pos+1); - mEscapedPath = mEscapedPath.substr(0,delim_pos); - } + std::string::size_type delim_pos; + delim_pos = escaped_str.find(':'); + std::string temp; + if (delim_pos == std::string::npos) + { + mScheme = ""; + mEscapedOpaque = escaped_str; + } + else + { + mScheme = escaped_str.substr(0, delim_pos); + mEscapedOpaque = escaped_str.substr(delim_pos+1); + } + + parseAuthorityAndPathUsingOpaque(); + + delim_pos = mEscapedPath.find('?'); + if (delim_pos != std::string::npos) + { + mEscapedQuery = mEscapedPath.substr(delim_pos+1); + mEscapedPath = mEscapedPath.substr(0,delim_pos); + } } static BOOL isDefault(const std::string& scheme, U16 port) { - if (scheme == "http") - return port == 80; - if (scheme == "https") - return port == 443; - if (scheme == "ftp") - return port == 21; + if (scheme == "http") + return port == 80; + if (scheme == "https") + return port == 443; + if (scheme == "ftp") + return port == 21; - return FALSE; + return FALSE; } void LLURI::parseAuthorityAndPathUsingOpaque() { - if (mScheme == "http" || mScheme == "https" || - mScheme == "ftp" || mScheme == "secondlife" || - mScheme == "x-grid-location-info") - { - if (mEscapedOpaque.substr(0,2) != "//") - { - return; - } - - std::string::size_type delim_pos, delim_pos2; - delim_pos = mEscapedOpaque.find('/', 2); - delim_pos2 = mEscapedOpaque.find('?', 2); - // no path, no query - if (delim_pos == std::string::npos && - delim_pos2 == std::string::npos) - { - mEscapedAuthority = mEscapedOpaque.substr(2); - mEscapedPath = ""; - } - // path exist, no query - else if (delim_pos2 == std::string::npos) - { - mEscapedAuthority = mEscapedOpaque.substr(2,delim_pos-2); - mEscapedPath = mEscapedOpaque.substr(delim_pos); - } - // no path, only query - else if (delim_pos == std::string::npos || - delim_pos2 < delim_pos) - { - mEscapedAuthority = mEscapedOpaque.substr(2,delim_pos2-2); - // query part will be broken out later - mEscapedPath = mEscapedOpaque.substr(delim_pos2); - } - // path and query - else - { - mEscapedAuthority = mEscapedOpaque.substr(2,delim_pos-2); - // query part will be broken out later - mEscapedPath = mEscapedOpaque.substr(delim_pos); - } - } - else if (mScheme == "about") - { - mEscapedPath = mEscapedOpaque; - } + if (mScheme == "http" || mScheme == "https" || + mScheme == "ftp" || mScheme == "secondlife" || + mScheme == "x-grid-location-info") + { + if (mEscapedOpaque.substr(0,2) != "//") + { + return; + } + + std::string::size_type delim_pos, delim_pos2; + delim_pos = mEscapedOpaque.find('/', 2); + delim_pos2 = mEscapedOpaque.find('?', 2); + // no path, no query + if (delim_pos == std::string::npos && + delim_pos2 == std::string::npos) + { + mEscapedAuthority = mEscapedOpaque.substr(2); + mEscapedPath = ""; + } + // path exist, no query + else if (delim_pos2 == std::string::npos) + { + mEscapedAuthority = mEscapedOpaque.substr(2,delim_pos-2); + mEscapedPath = mEscapedOpaque.substr(delim_pos); + } + // no path, only query + else if (delim_pos == std::string::npos || + delim_pos2 < delim_pos) + { + mEscapedAuthority = mEscapedOpaque.substr(2,delim_pos2-2); + // query part will be broken out later + mEscapedPath = mEscapedOpaque.substr(delim_pos2); + } + // path and query + else + { + mEscapedAuthority = mEscapedOpaque.substr(2,delim_pos-2); + // query part will be broken out later + mEscapedPath = mEscapedOpaque.substr(delim_pos); + } + } + else if (mScheme == "about") + { + mEscapedPath = mEscapedOpaque; + } } LLURI::LLURI(const std::string& scheme, - const std::string& userName, - const std::string& password, - const std::string& hostName, - U16 port, - const std::string& escapedPath, - const std::string& escapedQuery) - : mScheme(scheme), - mEscapedPath(escapedPath), - mEscapedQuery(escapedQuery) -{ - std::ostringstream auth; - std::ostringstream opaque; - - opaque << "//"; - - if (!userName.empty()) - { - auth << escape(userName); - if (!password.empty()) - { - auth << ':' << escape(password); - } - auth << '@'; - } - auth << hostName; - if (!isDefault(scheme, port)) - { - auth << ':' << port; - } - mEscapedAuthority = auth.str(); - - opaque << mEscapedAuthority << escapedPath << escapedQuery; - - mEscapedOpaque = opaque.str(); + const std::string& userName, + const std::string& password, + const std::string& hostName, + U16 port, + const std::string& escapedPath, + const std::string& escapedQuery) + : mScheme(scheme), + mEscapedPath(escapedPath), + mEscapedQuery(escapedQuery) +{ + std::ostringstream auth; + std::ostringstream opaque; + + opaque << "//"; + + if (!userName.empty()) + { + auth << escape(userName); + if (!password.empty()) + { + auth << ':' << escape(password); + } + auth << '@'; + } + auth << hostName; + if (!isDefault(scheme, port)) + { + auth << ':' << port; + } + mEscapedAuthority = auth.str(); + + opaque << mEscapedAuthority << escapedPath << escapedQuery; + + mEscapedOpaque = opaque.str(); } LLURI::~LLURI() @@ -434,325 +434,325 @@ LLURI::~LLURI() // static LLURI LLURI::buildHTTP(const std::string& prefix, - const LLSD& path) -{ - LLURI result; - - // TODO: deal with '/' '?' '#' in host_port - if (prefix.find("://") != prefix.npos) - { - // it is a prefix - result = LLURI(prefix); - } - else - { - // it is just a host and optional port - result.mScheme = "http"; - result.mEscapedAuthority = escapeHostAndPort(prefix); - } - - if (path.isArray()) - { - // break out and escape each path component - for (LLSD::array_const_iterator it = path.beginArray(); - it != path.endArray(); - ++it) - { - LL_DEBUGS() << "PATH: inserting " << it->asString() << LL_ENDL; - result.mEscapedPath += "/" + escapePathComponent(it->asString()); - } - } - else if (path.isString()) - { - std::string pathstr(path); - // Trailing slash is significant in HTTP land. If caller specified, - // make a point of preserving. - std::string last_slash; - std::string::size_type len(pathstr.length()); - if (len && pathstr[len-1] == '/') - { - last_slash = "/"; - } - - // Escape every individual path component, recombining with slashes. - for (boost::split_iterator - ti(pathstr, boost::first_finder("/")), tend; - ti != tend; ++ti) - { - // Eliminate a leading slash or duplicate slashes anywhere. (Extra - // slashes show up here as empty components.) This test also - // eliminates a trailing slash, hence last_slash above. - if (! ti->empty()) - { - result.mEscapedPath - += "/" + escapePathComponent(std::string(ti->begin(), ti->end())); - } - } - - // Reinstate trailing slash, if any. - result.mEscapedPath += last_slash; - } - else if(path.isUndefined()) - { - // do nothing - } - else - { - LL_WARNS() << "Valid path arguments to buildHTTP are array, string, or undef, you passed type" - << path.type() << LL_ENDL; - } - result.mEscapedOpaque = "//" + result.mEscapedAuthority + - result.mEscapedPath; - return result; + const LLSD& path) +{ + LLURI result; + + // TODO: deal with '/' '?' '#' in host_port + if (prefix.find("://") != prefix.npos) + { + // it is a prefix + result = LLURI(prefix); + } + else + { + // it is just a host and optional port + result.mScheme = "http"; + result.mEscapedAuthority = escapeHostAndPort(prefix); + } + + if (path.isArray()) + { + // break out and escape each path component + for (LLSD::array_const_iterator it = path.beginArray(); + it != path.endArray(); + ++it) + { + LL_DEBUGS() << "PATH: inserting " << it->asString() << LL_ENDL; + result.mEscapedPath += "/" + escapePathComponent(it->asString()); + } + } + else if (path.isString()) + { + std::string pathstr(path); + // Trailing slash is significant in HTTP land. If caller specified, + // make a point of preserving. + std::string last_slash; + std::string::size_type len(pathstr.length()); + if (len && pathstr[len-1] == '/') + { + last_slash = "/"; + } + + // Escape every individual path component, recombining with slashes. + for (boost::split_iterator + ti(pathstr, boost::first_finder("/")), tend; + ti != tend; ++ti) + { + // Eliminate a leading slash or duplicate slashes anywhere. (Extra + // slashes show up here as empty components.) This test also + // eliminates a trailing slash, hence last_slash above. + if (! ti->empty()) + { + result.mEscapedPath + += "/" + escapePathComponent(std::string(ti->begin(), ti->end())); + } + } + + // Reinstate trailing slash, if any. + result.mEscapedPath += last_slash; + } + else if(path.isUndefined()) + { + // do nothing + } + else + { + LL_WARNS() << "Valid path arguments to buildHTTP are array, string, or undef, you passed type" + << path.type() << LL_ENDL; + } + result.mEscapedOpaque = "//" + result.mEscapedAuthority + + result.mEscapedPath; + return result; } // static LLURI LLURI::buildHTTP(const std::string& prefix, - const LLSD& path, - const LLSD& query) + const LLSD& path, + const LLSD& query) { - LLURI uri = buildHTTP(prefix, path); - // break out and escape each query component - uri.mEscapedQuery = mapToQueryString(query); - uri.mEscapedOpaque += uri.mEscapedQuery ; - uri.mEscapedQuery.erase(0,1); // trim the leading '?' - return uri; + LLURI uri = buildHTTP(prefix, path); + // break out and escape each query component + uri.mEscapedQuery = mapToQueryString(query); + uri.mEscapedOpaque += uri.mEscapedQuery ; + uri.mEscapedQuery.erase(0,1); // trim the leading '?' + return uri; } // static LLURI LLURI::buildHTTP(const std::string& host, - const U32& port, - const LLSD& path) + const U32& port, + const LLSD& path) { - return LLURI::buildHTTP(llformat("%s:%u", host.c_str(), port), path); + return LLURI::buildHTTP(llformat("%s:%u", host.c_str(), port), path); } // static LLURI LLURI::buildHTTP(const std::string& host, - const U32& port, - const LLSD& path, - const LLSD& query) + const U32& port, + const LLSD& path, + const LLSD& query) { - return LLURI::buildHTTP(llformat("%s:%u", host.c_str(), port), path, query); + return LLURI::buildHTTP(llformat("%s:%u", host.c_str(), port), path, query); } std::string LLURI::asString() const { - if (mScheme.empty()) - { - return mEscapedOpaque; - } - else - { - return mScheme + ":" + mEscapedOpaque; - } + if (mScheme.empty()) + { + return mEscapedOpaque; + } + else + { + return mScheme + ":" + mEscapedOpaque; + } } std::string LLURI::scheme() const { - return mScheme; + return mScheme; } std::string LLURI::opaque() const { - return unescape(mEscapedOpaque); + return unescape(mEscapedOpaque); } std::string LLURI::authority() const { - return unescape(mEscapedAuthority); + return unescape(mEscapedAuthority); } namespace { - void findAuthorityParts(const std::string& authority, - std::string& user, - std::string& host, - std::string& port) - { - std::string::size_type start_pos = authority.find('@'); - if (start_pos == std::string::npos) - { - user = ""; - start_pos = 0; - } - else - { - user = authority.substr(0, start_pos); - start_pos += 1; - } - - std::string::size_type end_pos = authority.find(':', start_pos); - if (end_pos == std::string::npos) - { - host = authority.substr(start_pos); - port = ""; - } - else - { - host = authority.substr(start_pos, end_pos - start_pos); - port = authority.substr(end_pos + 1); - } - } -} - + void findAuthorityParts(const std::string& authority, + std::string& user, + std::string& host, + std::string& port) + { + std::string::size_type start_pos = authority.find('@'); + if (start_pos == std::string::npos) + { + user = ""; + start_pos = 0; + } + else + { + user = authority.substr(0, start_pos); + start_pos += 1; + } + + std::string::size_type end_pos = authority.find(':', start_pos); + if (end_pos == std::string::npos) + { + host = authority.substr(start_pos); + port = ""; + } + else + { + host = authority.substr(start_pos, end_pos - start_pos); + port = authority.substr(end_pos + 1); + } + } +} + std::string LLURI::hostName() const { - std::string user, host, port; - findAuthorityParts(mEscapedAuthority, user, host, port); - return unescape(host); + std::string user, host, port; + findAuthorityParts(mEscapedAuthority, user, host, port); + return unescape(host); } std::string LLURI::userName() const { - std::string user, userPass, host, port; - findAuthorityParts(mEscapedAuthority, userPass, host, port); - std::string::size_type pos = userPass.find(':'); - if (pos != std::string::npos) - { - user = userPass.substr(0, pos); - } - return unescape(user); + std::string user, userPass, host, port; + findAuthorityParts(mEscapedAuthority, userPass, host, port); + std::string::size_type pos = userPass.find(':'); + if (pos != std::string::npos) + { + user = userPass.substr(0, pos); + } + return unescape(user); } std::string LLURI::password() const { - std::string pass, userPass, host, port; - findAuthorityParts(mEscapedAuthority, userPass, host, port); - std::string::size_type pos = userPass.find(':'); - if (pos != std::string::npos) - { - pass = userPass.substr(pos + 1); - } - return unescape(pass); + std::string pass, userPass, host, port; + findAuthorityParts(mEscapedAuthority, userPass, host, port); + std::string::size_type pos = userPass.find(':'); + if (pos != std::string::npos) + { + pass = userPass.substr(pos + 1); + } + return unescape(pass); } BOOL LLURI::defaultPort() const { - return isDefault(mScheme, hostPort()); + return isDefault(mScheme, hostPort()); } U16 LLURI::hostPort() const { - std::string user, host, port; - findAuthorityParts(mEscapedAuthority, user, host, port); - if (port.empty()) - { - if (mScheme == "http") - return 80; - if (mScheme == "https") - return 443; - if (mScheme == "ftp") - return 21; - return 0; - } - return atoi(port.c_str()); -} + std::string user, host, port; + findAuthorityParts(mEscapedAuthority, user, host, port); + if (port.empty()) + { + if (mScheme == "http") + return 80; + if (mScheme == "https") + return 443; + if (mScheme == "ftp") + return 21; + return 0; + } + return atoi(port.c_str()); +} std::string LLURI::path() const { - return unescape(mEscapedPath); + return unescape(mEscapedPath); } LLSD LLURI::pathArray() const { - typedef boost::tokenizer > tokenizer; - boost::char_separator sep("/", "", boost::drop_empty_tokens); - tokenizer tokens(mEscapedPath, sep); - tokenizer::iterator it = tokens.begin(); - tokenizer::iterator end = tokens.end(); + typedef boost::tokenizer > tokenizer; + boost::char_separator sep("/", "", boost::drop_empty_tokens); + tokenizer tokens(mEscapedPath, sep); + tokenizer::iterator it = tokens.begin(); + tokenizer::iterator end = tokens.end(); - LLSD params; - for (const std::string& str : tokens) - { - params.append(str); - } - return params; + LLSD params; + for (const std::string& str : tokens) + { + params.append(str); + } + return params; } std::string LLURI::query() const { - return unescape(mEscapedQuery); + return unescape(mEscapedQuery); } LLSD LLURI::queryMap() const { - return queryMap(mEscapedQuery); + return queryMap(mEscapedQuery); } // static LLSD LLURI::queryMap(std::string escaped_query_string) { - LL_DEBUGS() << "LLURI::queryMap query params: " << escaped_query_string << LL_ENDL; - - LLSD result = LLSD::emptyArray(); - while(!escaped_query_string.empty()) - { - // get tuple first - std::string tuple; - std::string::size_type tuple_begin = escaped_query_string.find('&'); - if (tuple_begin != std::string::npos) - { - tuple = escaped_query_string.substr(0, tuple_begin); - escaped_query_string = escaped_query_string.substr(tuple_begin+1); - } - else - { - tuple = escaped_query_string; - escaped_query_string = ""; - } - if (tuple.empty()) continue; - - // parse tuple - std::string::size_type key_end = tuple.find('='); - if (key_end != std::string::npos) - { - std::string key = unescape(tuple.substr(0,key_end)); - std::string value = unescape(tuple.substr(key_end+1)); - LL_DEBUGS() << "inserting key " << key << " value " << value << LL_ENDL; - result[key] = value; - } - else - { - LL_DEBUGS() << "inserting key " << unescape(tuple) << " value true" << LL_ENDL; - result[unescape(tuple)] = true; - } - } - return result; + LL_DEBUGS() << "LLURI::queryMap query params: " << escaped_query_string << LL_ENDL; + + LLSD result = LLSD::emptyArray(); + while(!escaped_query_string.empty()) + { + // get tuple first + std::string tuple; + std::string::size_type tuple_begin = escaped_query_string.find('&'); + if (tuple_begin != std::string::npos) + { + tuple = escaped_query_string.substr(0, tuple_begin); + escaped_query_string = escaped_query_string.substr(tuple_begin+1); + } + else + { + tuple = escaped_query_string; + escaped_query_string = ""; + } + if (tuple.empty()) continue; + + // parse tuple + std::string::size_type key_end = tuple.find('='); + if (key_end != std::string::npos) + { + std::string key = unescape(tuple.substr(0,key_end)); + std::string value = unescape(tuple.substr(key_end+1)); + LL_DEBUGS() << "inserting key " << key << " value " << value << LL_ENDL; + result[key] = value; + } + else + { + LL_DEBUGS() << "inserting key " << unescape(tuple) << " value true" << LL_ENDL; + result[unescape(tuple)] = true; + } + } + return result; } std::string LLURI::mapToQueryString(const LLSD& queryMap) { - std::string query_string; - if (queryMap.isMap()) - { - bool first_element = true; - LLSD::map_const_iterator iter = queryMap.beginMap(); - LLSD::map_const_iterator end = queryMap.endMap(); - std::ostringstream ostr; - for (; iter != end; ++iter) - { - if(first_element) - { - ostr << "?"; - first_element = false; - } - else - { - ostr << "&"; - } - ostr << escapeQueryVariable(iter->first); - if(iter->second.isDefined()) - { - ostr << "=" << escapeQueryValue(iter->second.asString()); - } - } - query_string = ostr.str(); - } - return query_string; + std::string query_string; + if (queryMap.isMap()) + { + bool first_element = true; + LLSD::map_const_iterator iter = queryMap.beginMap(); + LLSD::map_const_iterator end = queryMap.endMap(); + std::ostringstream ostr; + for (; iter != end; ++iter) + { + if(first_element) + { + ostr << "?"; + first_element = false; + } + else + { + ostr << "&"; + } + ostr << escapeQueryVariable(iter->first); + if(iter->second.isDefined()) + { + ostr << "=" << escapeQueryValue(iter->second.asString()); + } + } + query_string = ostr.str(); + } + return query_string; } bool operator!=(const LLURI& first, const LLURI& second) { - return (first.asString() != second.asString()); + return (first.asString() != second.asString()); } diff --git a/indra/llcommon/lluri.h b/indra/llcommon/lluri.h index b8fca0ca51..95c119dee9 100644 --- a/indra/llcommon/lluri.h +++ b/indra/llcommon/lluri.h @@ -1,4 +1,4 @@ -/** +/** * @file lluri.h * @author Phoenix * @date 2006-02-05 @@ -7,21 +7,21 @@ * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -35,7 +35,7 @@ class LLSD; class LLUUID; class LLApp; -/** +/** * * LLURI instances are immutable * See: http://www.ietf.org/rfc/rfc3986.txt @@ -47,144 +47,144 @@ public: LLURI(); LLURI(const std::string& escaped_str); LLURI(const std::string& scheme, - const std::string& userName, - const std::string& password, - const std::string& hostName, - U16 hostPort, - const std::string& escapedPath, - const std::string& escapedQuery); - + const std::string& userName, + const std::string& password, + const std::string& hostName, + U16 hostPort, + const std::string& escapedPath, + const std::string& escapedQuery); + // construct from escaped string, as would be transmitted on the net - ~LLURI(); - - static LLURI buildHTTP( - const std::string& prefix, - const LLSD& path); - - static LLURI buildHTTP( - const std::string& prefix, - const LLSD& path, - const LLSD& query); - ///< prefix is either a full URL prefix of the form - /// "http://example.com:8080", or it can be simply a host and - /// optional port like "example.com" or "example.com:8080", in - /// these cases, the "http://" will be added - - static LLURI buildHTTP( - const std::string& host, - const U32& port, - const LLSD& path); - static LLURI buildHTTP( - const std::string& host, - const U32& port, - const LLSD& path, - const LLSD& query); - - std::string asString() const; - ///< the whole URI, escaped as needed - - /** @name Parts of a URI */ - //@{ - // These functions return parts of the decoded URI. The returned - // strings are un-escaped as needed - - // for all schemes - std::string scheme() const; ///< ex.: "http", note lack of colon - std::string opaque() const; ///< everything after the colon - + ~LLURI(); + + static LLURI buildHTTP( + const std::string& prefix, + const LLSD& path); + + static LLURI buildHTTP( + const std::string& prefix, + const LLSD& path, + const LLSD& query); + ///< prefix is either a full URL prefix of the form + /// "http://example.com:8080", or it can be simply a host and + /// optional port like "example.com" or "example.com:8080", in + /// these cases, the "http://" will be added + + static LLURI buildHTTP( + const std::string& host, + const U32& port, + const LLSD& path); + static LLURI buildHTTP( + const std::string& host, + const U32& port, + const LLSD& path, + const LLSD& query); + + std::string asString() const; + ///< the whole URI, escaped as needed + + /** @name Parts of a URI */ + //@{ + // These functions return parts of the decoded URI. The returned + // strings are un-escaped as needed + + // for all schemes + std::string scheme() const; ///< ex.: "http", note lack of colon + std::string opaque() const; ///< everything after the colon + // for schemes that follow path like syntax (http, https, ftp) - std::string authority() const; // ex.: "host.com:80" - std::string hostName() const; // ex.: "host.com" + std::string authority() const; // ex.: "host.com:80" + std::string hostName() const; // ex.: "host.com" std::string userName() const; std::string password() const; - U16 hostPort() const; // ex.: 80, will include implicit port - BOOL defaultPort() const; // true if port is default for scheme + U16 hostPort() const; // ex.: 80, will include implicit port + BOOL defaultPort() const; // true if port is default for scheme const std::string& escapedPath() const { return mEscapedPath; } - std::string path() const; // ex.: "/abc/def", includes leading slash - LLSD pathArray() const; // above decoded into an array of strings - std::string query() const; // ex.: "x=34", section after "?" + std::string path() const; // ex.: "/abc/def", includes leading slash + LLSD pathArray() const; // above decoded into an array of strings + std::string query() const; // ex.: "x=34", section after "?" const std::string& escapedQuery() const { return mEscapedQuery; } - LLSD queryMap() const; // above decoded into a map + LLSD queryMap() const; // above decoded into a map static LLSD queryMap(std::string escaped_query_string); - /** - * @brief given a name value map, return a serialized query string. - * - - * @param query_map a map of name value. every value must be - * representable as a string. - * @return Returns an url query string of '?n1=v1&n2=v2&...' - */ - static std::string mapToQueryString(const LLSD& query_map); - - /** @name Escaping Utilities */ - //@{ - /** - * @brief 'Escape' symbol into stream - * - * @param ostr Output stream. - * @param val Symbol to encode. - */ - static void encodeCharacter(std::ostream& ostr, std::string::value_type val); - - /** - * @brief Escape the string passed except for unreserved - * - * ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz - * 0123456789 - * -._~ - * - * @see http://www.ietf.org/rfc/rfc1738.txt - * - * @param str The raw URI to escape. - * @return Returns the rfc 1738 escaped uri or an empty string. - */ - static std::string escape(const std::string& str); - - /** - * @brief Escape a string with a specified set of allowed characters. - * - * Escape a string by urlencoding all the characters that aren't - * in the allowed string. - * @param str The raw URI to escape. - * @param allowed Character array of allowed characters - * @param is_allowed_sorted Optimization hint if allowed array is sorted. - * @return Returns the escaped uri or an empty string. - */ - static std::string escape( - const std::string& str, - const std::string& allowed, - bool is_allowed_sorted = false); - - /** - * @brief Break string into data part and path or sheme - * and escape path (if present) and data. - * Data part is not allowed to have path related symbols - * @param str The raw URI to escape. - */ - static std::string escapePathAndData(const std::string &str); - - /** - * @brief unescape an escaped URI string. - * - * @param str The escped URI to unescape. - * @return Returns the unescaped uri or an empty string. - */ - static std::string unescape(const std::string& str); - //@} + /** + * @brief given a name value map, return a serialized query string. + * + + * @param query_map a map of name value. every value must be + * representable as a string. + * @return Returns an url query string of '?n1=v1&n2=v2&...' + */ + static std::string mapToQueryString(const LLSD& query_map); + + /** @name Escaping Utilities */ + //@{ + /** + * @brief 'Escape' symbol into stream + * + * @param ostr Output stream. + * @param val Symbol to encode. + */ + static void encodeCharacter(std::ostream& ostr, std::string::value_type val); + + /** + * @brief Escape the string passed except for unreserved + * + * ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz + * 0123456789 + * -._~ + * + * @see http://www.ietf.org/rfc/rfc1738.txt + * + * @param str The raw URI to escape. + * @return Returns the rfc 1738 escaped uri or an empty string. + */ + static std::string escape(const std::string& str); + + /** + * @brief Escape a string with a specified set of allowed characters. + * + * Escape a string by urlencoding all the characters that aren't + * in the allowed string. + * @param str The raw URI to escape. + * @param allowed Character array of allowed characters + * @param is_allowed_sorted Optimization hint if allowed array is sorted. + * @return Returns the escaped uri or an empty string. + */ + static std::string escape( + const std::string& str, + const std::string& allowed, + bool is_allowed_sorted = false); + + /** + * @brief Break string into data part and path or sheme + * and escape path (if present) and data. + * Data part is not allowed to have path related symbols + * @param str The raw URI to escape. + */ + static std::string escapePathAndData(const std::string &str); + + /** + * @brief unescape an escaped URI string. + * + * @param str The escped URI to unescape. + * @return Returns the unescaped uri or an empty string. + */ + static std::string unescape(const std::string& str); + //@} private: - // only "http", "https", "ftp", and "secondlife" schemes are parsed - // secondlife scheme parses authority as "" and includes it as part of - // the path. See lluri_tut.cpp - // i.e. secondlife://app/login has mAuthority = "" and mPath = "/app/login" - void parseAuthorityAndPathUsingOpaque(); - std::string mScheme; - std::string mEscapedOpaque; - std::string mEscapedAuthority; - std::string mEscapedPath; - std::string mEscapedQuery; + // only "http", "https", "ftp", and "secondlife" schemes are parsed + // secondlife scheme parses authority as "" and includes it as part of + // the path. See lluri_tut.cpp + // i.e. secondlife://app/login has mAuthority = "" and mPath = "/app/login" + void parseAuthorityAndPathUsingOpaque(); + std::string mScheme; + std::string mEscapedOpaque; + std::string mEscapedAuthority; + std::string mEscapedPath; + std::string mEscapedQuery; }; // this operator required for tut diff --git a/indra/llcommon/lluriparser.cpp b/indra/llcommon/lluriparser.cpp index f79a98a56d..2ebb7fc742 100644 --- a/indra/llcommon/lluriparser.cpp +++ b/indra/llcommon/lluriparser.cpp @@ -1,4 +1,4 @@ -/** +/** * @file lluriparser.cpp * @author Protey * @date 2014-10-07 @@ -7,21 +7,21 @@ * $LicenseInfo:firstyear=2014&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2014, 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$ */ @@ -36,129 +36,129 @@ LLUriParser::LLUriParser(const std::string& u) : mTmpScheme(false), mNormalizedTmp(false), mRes(0) { - if (u.find("://") == std::string::npos) - { - mNormalizedUri = "http://"; - mTmpScheme = true; - } + if (u.find("://") == std::string::npos) + { + mNormalizedUri = "http://"; + mTmpScheme = true; + } - mNormalizedUri += u.c_str(); + mNormalizedUri += u.c_str(); - mRes = parse(); + mRes = parse(); } LLUriParser::~LLUriParser() { - uriFreeUriMembersA(&mUri); + uriFreeUriMembersA(&mUri); } S32 LLUriParser::parse() { - mRes = uriParseSingleUriA(&mUri, mNormalizedUri.c_str(), NULL); - return mRes; + mRes = uriParseSingleUriA(&mUri, mNormalizedUri.c_str(), NULL); + return mRes; } const char * LLUriParser::scheme() const { - return mScheme.c_str(); + return mScheme.c_str(); } void LLUriParser::sheme(const std::string& s) { - mTmpScheme = !s.size(); - mScheme = s; + mTmpScheme = !s.size(); + mScheme = s; } const char * LLUriParser::port() const { - return mPort.c_str(); + return mPort.c_str(); } void LLUriParser::port(const std::string& s) { - mPort = s; + mPort = s; } const char * LLUriParser::host() const { - return mHost.c_str(); + return mHost.c_str(); } void LLUriParser::host(const std::string& s) { - mHost = s; + mHost = s; } const char * LLUriParser::path() const { - return mPath.c_str(); + return mPath.c_str(); } void LLUriParser::path(const std::string& s) { - mPath = s; + mPath = s; } const char * LLUriParser::query() const { - return mQuery.c_str(); + return mQuery.c_str(); } void LLUriParser::query(const std::string& s) { - mQuery = s; + mQuery = s; } const char * LLUriParser::fragment() const { - return mFragment.c_str(); + return mFragment.c_str(); } void LLUriParser::fragment(const std::string& s) { - mFragment = s; + mFragment = s; } void LLUriParser::textRangeToString(UriTextRangeA& textRange, std::string& str) { - if (textRange.first != NULL && textRange.afterLast != NULL && textRange.first < textRange.afterLast) - { - const ptrdiff_t len = textRange.afterLast - textRange.first; - str.assign(textRange.first, static_cast(len)); - } - else - { - str = LLStringUtil::null; - } + if (textRange.first != NULL && textRange.afterLast != NULL && textRange.first < textRange.afterLast) + { + const ptrdiff_t len = textRange.afterLast - textRange.first; + str.assign(textRange.first, static_cast(len)); + } + else + { + str = LLStringUtil::null; + } } void LLUriParser::extractParts() { - if (mTmpScheme || mNormalizedTmp) - { - mScheme.clear(); - } - else - { - textRangeToString(mUri.scheme, mScheme); - } - - textRangeToString(mUri.hostText, mHost); - textRangeToString(mUri.portText, mPort); - textRangeToString(mUri.query, mQuery); - textRangeToString(mUri.fragment, mFragment); - - UriPathSegmentA * pathHead = mUri.pathHead; - while (pathHead) - { - std::string partOfPath; - textRangeToString(pathHead->text, partOfPath); - - mPath += '/'; - mPath += partOfPath; - - pathHead = pathHead->next; - } + if (mTmpScheme || mNormalizedTmp) + { + mScheme.clear(); + } + else + { + textRangeToString(mUri.scheme, mScheme); + } + + textRangeToString(mUri.hostText, mHost); + textRangeToString(mUri.portText, mPort); + textRangeToString(mUri.query, mQuery); + textRangeToString(mUri.fragment, mFragment); + + UriPathSegmentA * pathHead = mUri.pathHead; + while (pathHead) + { + std::string partOfPath; + textRangeToString(pathHead->text, partOfPath); + + mPath += '/'; + mPath += partOfPath; + + pathHead = pathHead->next; + } } #if LL_DARWIN @@ -177,14 +177,14 @@ void uri_signal_handler(int signal) S32 LLUriParser::normalize() { - mNormalizedTmp = mTmpScheme; - if (!mRes) - { + mNormalizedTmp = mTmpScheme; + if (!mRes) + { #if LL_DARWIN sighandler_t last_sigill_handler, last_sigbus_handler; - last_sigill_handler = signal(SIGILL, &uri_signal_handler); // illegal instruction + last_sigill_handler = signal(SIGILL, &uri_signal_handler); // illegal instruction last_sigbus_handler = signal(SIGBUS, &uri_signal_handler); - + if (setjmp(return_to_normalize)) { // Issue: external library crashed via signal @@ -230,79 +230,79 @@ S32 LLUriParser::normalize() } } } - } + } - if(mTmpScheme && mNormalizedUri.size() > 7) - { - mNormalizedUri = mNormalizedUri.substr(7); - mTmpScheme = false; - } + if(mTmpScheme && mNormalizedUri.size() > 7) + { + mNormalizedUri = mNormalizedUri.substr(7); + mTmpScheme = false; + } - return mRes; + return mRes; } void LLUriParser::glue(std::string& uri) const { - std::string first_part; - glueFirst(first_part); + std::string first_part; + glueFirst(first_part); - std::string second_part; - glueSecond(second_part); + std::string second_part; + glueSecond(second_part); - uri = first_part + second_part; + uri = first_part + second_part; } void LLUriParser::glueFirst(std::string& uri, bool use_scheme) const { - if (use_scheme && mScheme.size()) - { - uri = mScheme; - uri += "://"; - } - else - { - uri.clear(); - } - - uri += mHost; + if (use_scheme && mScheme.size()) + { + uri = mScheme; + uri += "://"; + } + else + { + uri.clear(); + } + + uri += mHost; } void LLUriParser::glueSecond(std::string& uri) const { - if (mPort.size()) - { - uri = ':'; - uri += mPort; - } - else - { - uri.clear(); - } - - uri += mPath; - - if (mQuery.size()) - { - uri += '?'; - uri += mQuery; - } - - if (mFragment.size()) - { - uri += '#'; - uri += mFragment; - } + if (mPort.size()) + { + uri = ':'; + uri += mPort; + } + else + { + uri.clear(); + } + + uri += mPath; + + if (mQuery.size()) + { + uri += '?'; + uri += mQuery; + } + + if (mFragment.size()) + { + uri += '#'; + uri += mFragment; + } } bool LLUriParser::test() const { - std::string uri; - glue(uri); + std::string uri; + glue(uri); - return uri == mNormalizedUri; + return uri == mNormalizedUri; } const char * LLUriParser::normalizedUri() const { - return mNormalizedUri.c_str(); + return mNormalizedUri.c_str(); } diff --git a/indra/llcommon/lluriparser.h b/indra/llcommon/lluriparser.h index 92626b9054..77eb4031d5 100644 --- a/indra/llcommon/lluriparser.h +++ b/indra/llcommon/lluriparser.h @@ -1,4 +1,4 @@ -/** +/** * @file lluriparser.h * @author Protey * @date 20146-10-07 @@ -7,21 +7,21 @@ * $LicenseInfo:firstyear=2014&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2014, 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$ */ @@ -35,52 +35,52 @@ class LL_COMMON_API LLUriParser { public: - LLUriParser(const std::string& u); - ~LLUriParser(); + LLUriParser(const std::string& u); + ~LLUriParser(); - const char * scheme() const; - void sheme (const std::string& s); + const char * scheme() const; + void sheme (const std::string& s); - const char * port() const; - void port (const std::string& s); + const char * port() const; + void port (const std::string& s); - const char * host() const; - void host (const std::string& s); + const char * host() const; + void host (const std::string& s); - const char * path() const; - void path (const std::string& s); + const char * path() const; + void path (const std::string& s); - const char * query() const; - void query (const std::string& s); + const char * query() const; + void query (const std::string& s); - const char * fragment() const; - void fragment (const std::string& s); + const char * fragment() const; + void fragment (const std::string& s); - const char * normalizedUri() const; + const char * normalizedUri() const; - void extractParts(); - void glue(std::string& uri) const; - void glueFirst(std::string& uri, bool use_scheme = true) const; - void glueSecond(std::string& uri) const; - bool test() const; - S32 normalize(); + void extractParts(); + void glue(std::string& uri) const; + void glueFirst(std::string& uri, bool use_scheme = true) const; + void glueSecond(std::string& uri) const; + bool test() const; + S32 normalize(); private: - S32 parse(); - void textRangeToString(UriTextRangeA& textRange, std::string& str); - std::string mScheme; - std::string mHost; - std::string mPort; - std::string mPath; - std::string mQuery; - std::string mFragment; - std::string mNormalizedUri; + S32 parse(); + void textRangeToString(UriTextRangeA& textRange, std::string& str); + std::string mScheme; + std::string mHost; + std::string mPort; + std::string mPath; + std::string mQuery; + std::string mFragment; + std::string mNormalizedUri; - UriUriA mUri; + UriUriA mUri; - S32 mRes; - bool mTmpScheme; - bool mNormalizedTmp; + S32 mRes; + bool mTmpScheme; + bool mNormalizedTmp; }; #endif // LL_LLURIPARSER_H diff --git a/indra/llcommon/lluuid.cpp b/indra/llcommon/lluuid.cpp index 200add404f..ab66fa6ddc 100644 --- a/indra/llcommon/lluuid.cpp +++ b/indra/llcommon/lluuid.cpp @@ -50,7 +50,7 @@ const LLUUID LLUUID::null; const LLTransactionID LLTransactionID::tnull; -// static +// static LLMutex* LLUUID::mMutex = NULL; @@ -187,7 +187,7 @@ void LLUUID::toString(char* out) const void LLUUID::toCompressedString(std::string& out) const { char bytes[UUID_BYTES + 1]; - memcpy(bytes, mData, UUID_BYTES); /* Flawfinder: ignore */ + memcpy(bytes, mData, UUID_BYTES); /* Flawfinder: ignore */ bytes[UUID_BYTES] = '\0'; out.assign(bytes, UUID_BYTES); } @@ -195,7 +195,7 @@ void LLUUID::toCompressedString(std::string& out) const // *TODO: deprecate void LLUUID::toCompressedString(char* out) const { - memcpy(out, mData, UUID_BYTES); /* Flawfinder: ignore */ + memcpy(out, mData, UUID_BYTES); /* Flawfinder: ignore */ out[UUID_BYTES] = '\0'; } @@ -227,11 +227,11 @@ BOOL LLUUID::set(const std::string& in_string, BOOL emit) return TRUE; } - if (in_string.length() != (UUID_STR_LENGTH - 1)) /* Flawfinder: ignore */ + if (in_string.length() != (UUID_STR_LENGTH - 1)) /* Flawfinder: ignore */ { // I'm a moron. First implementation didn't have the right UUID format. // Shouldn't see any of these any more - if (in_string.length() == (UUID_STR_LENGTH - 2)) /* Flawfinder: ignore */ + if (in_string.length() == (UUID_STR_LENGTH - 2)) /* Flawfinder: ignore */ { if (emit) { @@ -323,10 +323,10 @@ BOOL LLUUID::set(const std::string& in_string, BOOL emit) BOOL LLUUID::validate(const std::string& in_string) { BOOL broken_format = FALSE; - if (in_string.length() != (UUID_STR_LENGTH - 1)) /* Flawfinder: ignore */ + if (in_string.length() != (UUID_STR_LENGTH - 1)) /* Flawfinder: ignore */ { // I'm a moron. First implementation didn't have the right UUID format. - if (in_string.length() == (UUID_STR_LENGTH - 2)) /* Flawfinder: ignore */ + if (in_string.length() == (UUID_STR_LENGTH - 2)) /* Flawfinder: ignore */ { broken_format = TRUE; } @@ -431,7 +431,7 @@ std::ostream& operator<<(std::ostream& s, const LLUUID& uuid) std::istream& operator>>(std::istream& s, LLUUID& uuid) { U32 i; - char uuid_str[UUID_STR_LENGTH]; /* Flawfinder: ignore */ + char uuid_str[UUID_STR_LENGTH]; /* Flawfinder: ignore */ for (i = 0; i < UUID_STR_LENGTH - 1; i++) { s >> uuid_str[i]; @@ -459,7 +459,7 @@ static void get_random_bytes(void* buf, int nbytes) return; } -#if LL_WINDOWS +#if LL_WINDOWS typedef struct _ASTAT_ { @@ -468,7 +468,7 @@ typedef struct _ASTAT_ }ASTAT, * PASTAT; // static -S32 LLUUID::getNodeID(unsigned char* node_id) +S32 LLUUID::getNodeID(unsigned char* node_id) { ASTAT Adapter; NCB Ncb; @@ -495,14 +495,14 @@ S32 LLUUID::getNodeID(unsigned char* node_id) Ncb.ncb_command = NCBASTAT; Ncb.ncb_lana_num = lenum.lana[i]; - strcpy((char*)Ncb.ncb_callname, "* "); /* Flawfinder: ignore */ + strcpy((char*)Ncb.ncb_callname, "* "); /* Flawfinder: ignore */ Ncb.ncb_buffer = (unsigned char*)&Adapter; Ncb.ncb_length = sizeof(Adapter); uRetCode = Netbios(&Ncb); if (uRetCode == 0) { - memcpy(node_id, Adapter.adapt.adapter_address, 6); /* Flawfinder: ignore */ + memcpy(node_id, Adapter.adapt.adapter_address, 6); /* Flawfinder: ignore */ retval = 1; } } @@ -545,19 +545,19 @@ S32 LLUUID::getNodeID(unsigned char* node_id) for (ifa = ifap; ifa != NULL; ifa = ifa->ifa_next) { - // printf("Interface %s, address family %d, ", ifa->ifa_name, ifa->ifa_addr->sa_family); + // printf("Interface %s, address family %d, ", ifa->ifa_name, ifa->ifa_addr->sa_family); for (i = 0; i < ifa->ifa_addr->sa_len; i++) { - // printf("%02X ", (unsigned char)ifa->ifa_addr->sa_data[i]); + // printf("%02X ", (unsigned char)ifa->ifa_addr->sa_data[i]); } - // printf("\n"); + // printf("\n"); if (ifa->ifa_addr->sa_family == AF_LINK) { // This is a link-level address struct sockaddr_dl* lla = (struct sockaddr_dl*)ifa->ifa_addr; - // printf("\tLink level address, type %02X\n", lla->sdl_type); + // printf("\tLink level address, type %02X\n", lla->sdl_type); if (lla->sdl_type == IFT_ETHER) { @@ -614,11 +614,11 @@ S32 LLUUID::getNodeID(unsigned char* node_id) // static S32 LLUUID::getNodeID(unsigned char* node_id) { - int sd; - struct ifreq ifr, * ifrp; - struct ifconf ifc; + int sd; + struct ifreq ifr, * ifrp; + struct ifconf ifc; char buf[1024]; - int n, i; + int n, i; unsigned char* a; /* @@ -651,7 +651,7 @@ S32 LLUUID::getNodeID(unsigned char* node_id) n = ifc.ifc_len; for (i = 0; i < n; i += ifreq_size(*ifr)) { ifrp = (struct ifreq*)((char*)ifc.ifc_buf + i); - strncpy(ifr.ifr_name, ifrp->ifr_name, IFNAMSIZ); /* Flawfinder: ignore */ + strncpy(ifr.ifr_name, ifrp->ifr_name, IFNAMSIZ); /* Flawfinder: ignore */ #ifdef SIOCGIFHWADDR if (ioctl(sd, SIOCGIFHWADDR, &ifr) < 0) continue; @@ -673,7 +673,7 @@ S32 LLUUID::getNodeID(unsigned char* node_id) if (!a[0] && !a[1] && !a[2] && !a[3] && !a[4] && !a[5]) continue; if (node_id) { - memcpy(node_id, a, 6); /* Flawfinder: ignore */ + memcpy(node_id, a, 6); /* Flawfinder: ignore */ close(sd); return 1; } @@ -784,7 +784,7 @@ void LLUUID::generate() // Create a UUID. uuid_time_t timestamp; - static unsigned char node_id[6]; /* Flawfinder: ignore */ + static unsigned char node_id[6]; /* Flawfinder: ignore */ static int has_init = 0; // Create a UUID. @@ -826,16 +826,16 @@ void LLUUID::generate() // if clock hasn't changed or went backward, change clockseq if (cmpTime(×tamp, &time_last) != 1) { - LLMutexLock lock(mMutex); + LLMutexLock lock(mMutex); clock_seq = (clock_seq + 1) & 0x3FFF; if (clock_seq == 0) clock_seq++; - our_clock_seq = clock_seq; // Ensure we're using a different clock_seq value from previous time + our_clock_seq = clock_seq; // Ensure we're using a different clock_seq value from previous time } time_last = timestamp; - memcpy(mData + 10, node_id, 6); /* Flawfinder: ignore */ + memcpy(mData + 10, node_id, 6); /* Flawfinder: ignore */ U32 tmp; tmp = timestamp.low; mData[3] = (unsigned char)tmp; @@ -872,7 +872,7 @@ void LLUUID::generate(const std::string& hash_string) U32 LLUUID::getRandomSeed() { - static unsigned char seed[16]; /* Flawfinder: ignore */ + static unsigned char seed[16]; /* Flawfinder: ignore */ getNodeID(&seed[0]); diff --git a/indra/llcommon/lluuid.h b/indra/llcommon/lluuid.h index 80597fa186..eea5e39c61 100644 --- a/indra/llcommon/lluuid.h +++ b/indra/llcommon/lluuid.h @@ -1,24 +1,24 @@ -/** +/** * @file lluuid.h * * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -37,104 +37,104 @@ class LLMutex; const S32 UUID_BYTES = 16; const S32 UUID_WORDS = 4; -const S32 UUID_STR_LENGTH = 37; // actually wrong, should be 36 and use size below +const S32 UUID_STR_LENGTH = 37; // actually wrong, should be 36 and use size below const S32 UUID_STR_SIZE = 37; const S32 UUID_BASE85_LENGTH = 21; // including the trailing NULL. struct uuid_time_t { - U32 high; - U32 low; - }; + U32 high; + U32 low; + }; class LL_COMMON_API LLUUID { public: - // - // CREATORS - // - LLUUID(); - explicit LLUUID(const char *in_string); // Convert from string. - explicit LLUUID(const std::string& in_string); // Convert from string. - ~LLUUID() = default; - - // - // MANIPULATORS - // - void generate(); // Generate a new UUID - void generate(const std::string& stream); //Generate a new UUID based on hash of input stream - - static LLUUID generateNewID(std::string stream = ""); //static version of above for use in initializer expressions such as constructor params, etc. - - BOOL set(const char *in_string, BOOL emit = TRUE); // Convert from string, if emit is FALSE, do not emit warnings - BOOL set(const std::string& in_string, BOOL emit = TRUE); // Convert from string, if emit is FALSE, do not emit warnings - void setNull(); // Faster than setting to LLUUID::null. + // + // CREATORS + // + LLUUID(); + explicit LLUUID(const char *in_string); // Convert from string. + explicit LLUUID(const std::string& in_string); // Convert from string. + ~LLUUID() = default; + + // + // MANIPULATORS + // + void generate(); // Generate a new UUID + void generate(const std::string& stream); //Generate a new UUID based on hash of input stream + + static LLUUID generateNewID(std::string stream = ""); //static version of above for use in initializer expressions such as constructor params, etc. + + BOOL set(const char *in_string, BOOL emit = TRUE); // Convert from string, if emit is FALSE, do not emit warnings + BOOL set(const std::string& in_string, BOOL emit = TRUE); // Convert from string, if emit is FALSE, do not emit warnings + void setNull(); // Faster than setting to LLUUID::null. S32 cmpTime(uuid_time_t *t1, uuid_time_t *t2); - static void getSystemTime(uuid_time_t *timestamp); - void getCurrentTime(uuid_time_t *timestamp); - - // - // ACCESSORS - // - BOOL isNull() const; // Faster than comparing to LLUUID::null. - BOOL notNull() const; // Faster than comparing to LLUUID::null. - // JC: This is dangerous. It allows UUIDs to be cast automatically - // to integers, among other things. Use isNull() or notNull(). - // operator bool() const; - - // JC: These must return real bool's (not BOOLs) or else use of the STL - // will generate bool-to-int performance warnings. - bool operator==(const LLUUID &rhs) const; - bool operator!=(const LLUUID &rhs) const; - bool operator<(const LLUUID &rhs) const; - bool operator>(const LLUUID &rhs) const; - - // xor functions. Useful since any two random uuids xored together - // will yield a determinate third random unique id that can be - // used as a key in a single uuid that represents 2. - const LLUUID& operator^=(const LLUUID& rhs); - LLUUID operator^(const LLUUID& rhs) const; - - // similar to functions above, but not invertible - // yields a third random UUID that can be reproduced from the two inputs - // but which, given the result and one of the inputs can't be used to - // deduce the other input - LLUUID combine(const LLUUID& other) const; - void combine(const LLUUID& other, LLUUID& result) const; - - friend LL_COMMON_API std::ostream& operator<<(std::ostream& s, const LLUUID &uuid); - friend LL_COMMON_API std::istream& operator>>(std::istream& s, LLUUID &uuid); - - void toString(char *out) const; // Does not allocate memory, needs 36 characters (including \0) - void toString(std::string& out) const; - void toCompressedString(char *out) const; // Does not allocate memory, needs 17 characters (including \0) - void toCompressedString(std::string& out) const; - - std::string asString() const; - std::string getString() const; - - U16 getCRC16() const; - U32 getCRC32() const; - - // Returns a 64 bits digest of the UUID, by XORing its two 64 bits long - // words. HB - inline U64 getDigest64() const - { - U64* tmp = (U64*)mData; - return tmp[0] ^ tmp[1]; - } - - static BOOL validate(const std::string& in_string); // Validate that the UUID string is legal. - - static const LLUUID null; - static LLMutex * mMutex; - - static U32 getRandomSeed(); - static S32 getNodeID(unsigned char * node_id); - - static BOOL parseUUID(const std::string& buf, LLUUID* value); - - U8 mData[UUID_BYTES]; + static void getSystemTime(uuid_time_t *timestamp); + void getCurrentTime(uuid_time_t *timestamp); + + // + // ACCESSORS + // + BOOL isNull() const; // Faster than comparing to LLUUID::null. + BOOL notNull() const; // Faster than comparing to LLUUID::null. + // JC: This is dangerous. It allows UUIDs to be cast automatically + // to integers, among other things. Use isNull() or notNull(). + // operator bool() const; + + // JC: These must return real bool's (not BOOLs) or else use of the STL + // will generate bool-to-int performance warnings. + bool operator==(const LLUUID &rhs) const; + bool operator!=(const LLUUID &rhs) const; + bool operator<(const LLUUID &rhs) const; + bool operator>(const LLUUID &rhs) const; + + // xor functions. Useful since any two random uuids xored together + // will yield a determinate third random unique id that can be + // used as a key in a single uuid that represents 2. + const LLUUID& operator^=(const LLUUID& rhs); + LLUUID operator^(const LLUUID& rhs) const; + + // similar to functions above, but not invertible + // yields a third random UUID that can be reproduced from the two inputs + // but which, given the result and one of the inputs can't be used to + // deduce the other input + LLUUID combine(const LLUUID& other) const; + void combine(const LLUUID& other, LLUUID& result) const; + + friend LL_COMMON_API std::ostream& operator<<(std::ostream& s, const LLUUID &uuid); + friend LL_COMMON_API std::istream& operator>>(std::istream& s, LLUUID &uuid); + + void toString(char *out) const; // Does not allocate memory, needs 36 characters (including \0) + void toString(std::string& out) const; + void toCompressedString(char *out) const; // Does not allocate memory, needs 17 characters (including \0) + void toCompressedString(std::string& out) const; + + std::string asString() const; + std::string getString() const; + + U16 getCRC16() const; + U32 getCRC32() const; + + // Returns a 64 bits digest of the UUID, by XORing its two 64 bits long + // words. HB + inline U64 getDigest64() const + { + U64* tmp = (U64*)mData; + return tmp[0] ^ tmp[1]; + } + + static BOOL validate(const std::string& in_string); // Validate that the UUID string is legal. + + static const LLUUID null; + static LLMutex * mMutex; + + static U32 getRandomSeed(); + static S32 getNodeID(unsigned char * node_id); + + static BOOL parseUUID(const std::string& buf, LLUUID* value); + + U8 mData[UUID_BYTES]; }; static_assert(std::is_trivially_copyable::value, "LLUUID must be trivial copy"); static_assert(std::is_trivially_move_assignable::value, "LLUUID must be trivial move"); @@ -151,10 +151,10 @@ typedef std::set uuid_set_t; // verify.) struct lluuid_less { - bool operator()(const LLUUID& lhs, const LLUUID& rhs) const - { - return (lhs < rhs) ? true : false; - } + bool operator()(const LLUUID& lhs, const LLUUID& rhs) const + { + return (lhs < rhs) ? true : false; + } }; typedef std::set uuid_list_t; @@ -167,28 +167,28 @@ typedef LLUUID LLAssetID; class LL_COMMON_API LLTransactionID : public LLUUID { public: - LLTransactionID() : LLUUID() { } - - static const LLTransactionID tnull; - LLAssetID makeAssetID(const LLUUID& session) const; + LLTransactionID() : LLUUID() { } + + static const LLTransactionID tnull; + LLAssetID makeAssetID(const LLUUID& session) const; }; // std::hash implementation for LLUUID namespace std { - template<> struct hash - { - inline size_t operator()(const LLUUID& id) const noexcept - { - return (size_t)id.getDigest64(); - } - }; + template<> struct hash + { + inline size_t operator()(const LLUUID& id) const noexcept + { + return (size_t)id.getDigest64(); + } + }; } // For use with boost containers. inline size_t hash_value(const LLUUID& id) noexcept { - return (size_t)id.getDigest64(); + return (size_t)id.getDigest64(); } #endif // LL_LLUUID_H diff --git a/indra/llcommon/llwin32headers.h b/indra/llcommon/llwin32headers.h index 8cfa40ada8..f679adc200 100644 --- a/indra/llcommon/llwin32headers.h +++ b/indra/llcommon/llwin32headers.h @@ -1,25 +1,25 @@ -/** +/** * @file llwin32headers.h * @brief sanitized include of windows header files * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcommon/llwin32headerslean.h b/indra/llcommon/llwin32headerslean.h index 314e7a85d1..97c8edb8cf 100644 --- a/indra/llcommon/llwin32headerslean.h +++ b/indra/llcommon/llwin32headerslean.h @@ -1,25 +1,25 @@ -/** +/** * @file llwin32headerslean.h * @brief sanitized include of windows header files * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcommon/llworkerthread.cpp b/indra/llcommon/llworkerthread.cpp index 06c74bdba0..67df2b5840 100644 --- a/indra/llcommon/llworkerthread.cpp +++ b/indra/llcommon/llworkerthread.cpp @@ -1,24 +1,24 @@ -/** +/** * @file llworkerthread.cpp * * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -35,134 +35,134 @@ // Run on MAIN thread LLWorkerThread::LLWorkerThread(const std::string& name, bool threaded, bool should_pause) : - LLQueuedThread(name, threaded, should_pause) + LLQueuedThread(name, threaded, should_pause) { - mDeleteMutex = new LLMutex(); + mDeleteMutex = new LLMutex(); - if(!mLocalAPRFilePoolp) - { - mLocalAPRFilePoolp = new LLVolatileAPRPool() ; - } + if(!mLocalAPRFilePoolp) + { + mLocalAPRFilePoolp = new LLVolatileAPRPool() ; + } } LLWorkerThread::~LLWorkerThread() { - // Delete any workers in the delete queue (should be safe - had better be!) - if (!mDeleteList.empty()) - { - LL_WARNS() << "Worker Thread: " << mName << " destroyed with " << mDeleteList.size() - << " entries in delete list." << LL_ENDL; - } - - delete mDeleteMutex; - - // ~LLQueuedThread() will be called here + // Delete any workers in the delete queue (should be safe - had better be!) + if (!mDeleteList.empty()) + { + LL_WARNS() << "Worker Thread: " << mName << " destroyed with " << mDeleteList.size() + << " entries in delete list." << LL_ENDL; + } + + delete mDeleteMutex; + + // ~LLQueuedThread() will be called here } //called only in destructor. void LLWorkerThread::clearDeleteList() { - // Delete any workers in the delete queue (should be safe - had better be!) - if (!mDeleteList.empty()) - { - LL_WARNS() << "Worker Thread: " << mName << " destroyed with " << mDeleteList.size() - << " entries in delete list." << LL_ENDL; - - mDeleteMutex->lock(); - for (LLWorkerClass* worker : mDeleteList) - { - worker->mRequestHandle = LLWorkerThread::nullHandle(); - worker->clearFlags(LLWorkerClass::WCF_HAVE_WORK); - worker->clearFlags(LLWorkerClass::WCF_WORKING); - delete worker; - } - mDeleteList.clear() ; - mDeleteMutex->unlock() ; - } + // Delete any workers in the delete queue (should be safe - had better be!) + if (!mDeleteList.empty()) + { + LL_WARNS() << "Worker Thread: " << mName << " destroyed with " << mDeleteList.size() + << " entries in delete list." << LL_ENDL; + + mDeleteMutex->lock(); + for (LLWorkerClass* worker : mDeleteList) + { + worker->mRequestHandle = LLWorkerThread::nullHandle(); + worker->clearFlags(LLWorkerClass::WCF_HAVE_WORK); + worker->clearFlags(LLWorkerClass::WCF_WORKING); + delete worker; + } + mDeleteList.clear() ; + mDeleteMutex->unlock() ; + } } // virtual size_t LLWorkerThread::update(F32 max_time_ms) { - auto res = LLQueuedThread::update(max_time_ms); - // Delete scheduled workers - std::vector delete_list; - std::vector abort_list; - mDeleteMutex->lock(); - for (delete_list_t::iterator iter = mDeleteList.begin(); - iter != mDeleteList.end(); ) - { - delete_list_t::iterator curiter = iter++; - LLWorkerClass* worker = *curiter; - if (worker->deleteOK()) - { - if (worker->getFlags(LLWorkerClass::WCF_WORK_FINISHED)) - { + auto res = LLQueuedThread::update(max_time_ms); + // Delete scheduled workers + std::vector delete_list; + std::vector abort_list; + mDeleteMutex->lock(); + for (delete_list_t::iterator iter = mDeleteList.begin(); + iter != mDeleteList.end(); ) + { + delete_list_t::iterator curiter = iter++; + LLWorkerClass* worker = *curiter; + if (worker->deleteOK()) + { + if (worker->getFlags(LLWorkerClass::WCF_WORK_FINISHED)) + { worker->setFlags(LLWorkerClass::WCF_DELETE_REQUESTED); - delete_list.push_back(worker); - mDeleteList.erase(curiter); - } - else if (!worker->getFlags(LLWorkerClass::WCF_ABORT_REQUESTED)) - { - abort_list.push_back(worker); - } - } - } - mDeleteMutex->unlock(); - // abort and delete after releasing mutex - for (LLWorkerClass* worker : abort_list) - { - worker->abortWork(false); - } - for (LLWorkerClass* worker : delete_list) - { - if (worker->mRequestHandle) - { - // Finished but not completed - completeRequest(worker->mRequestHandle); - worker->mRequestHandle = LLWorkerThread::nullHandle(); - worker->clearFlags(LLWorkerClass::WCF_HAVE_WORK); - } - delete worker; - } - // delete and aborted entries mean there's still work to do - res += delete_list.size() + abort_list.size(); - return res; + delete_list.push_back(worker); + mDeleteList.erase(curiter); + } + else if (!worker->getFlags(LLWorkerClass::WCF_ABORT_REQUESTED)) + { + abort_list.push_back(worker); + } + } + } + mDeleteMutex->unlock(); + // abort and delete after releasing mutex + for (LLWorkerClass* worker : abort_list) + { + worker->abortWork(false); + } + for (LLWorkerClass* worker : delete_list) + { + if (worker->mRequestHandle) + { + // Finished but not completed + completeRequest(worker->mRequestHandle); + worker->mRequestHandle = LLWorkerThread::nullHandle(); + worker->clearFlags(LLWorkerClass::WCF_HAVE_WORK); + } + delete worker; + } + // delete and aborted entries mean there's still work to do + res += delete_list.size() + abort_list.size(); + return res; } //---------------------------------------------------------------------------- LLWorkerThread::handle_t LLWorkerThread::addWorkRequest(LLWorkerClass* workerclass, S32 param) { - handle_t handle = generateHandle(); - - WorkRequest* req = new WorkRequest(handle, workerclass, param); - - bool res = addRequest(req); - if (!res) - { - LL_ERRS() << "add called after LLWorkerThread::cleanupClass()" << LL_ENDL; - req->deleteRequest(); - handle = nullHandle(); - } - - return handle; + handle_t handle = generateHandle(); + + WorkRequest* req = new WorkRequest(handle, workerclass, param); + + bool res = addRequest(req); + if (!res) + { + LL_ERRS() << "add called after LLWorkerThread::cleanupClass()" << LL_ENDL; + req->deleteRequest(); + handle = nullHandle(); + } + + return handle; } void LLWorkerThread::deleteWorker(LLWorkerClass* workerclass) { - mDeleteMutex->lock(); - mDeleteList.push_back(workerclass); - mDeleteMutex->unlock(); + mDeleteMutex->lock(); + mDeleteList.push_back(workerclass); + mDeleteMutex->unlock(); } //============================================================================ // Runs on its OWN thread LLWorkerThread::WorkRequest::WorkRequest(handle_t handle, LLWorkerClass* workerclass, S32 param) : - LLQueuedThread::QueuedRequest(handle), - mWorkerClass(workerclass), - mParam(param) + LLQueuedThread::QueuedRequest(handle), + mWorkerClass(workerclass), + mParam(param) { } @@ -173,75 +173,75 @@ LLWorkerThread::WorkRequest::~WorkRequest() // virtual (required for access by LLWorkerThread) void LLWorkerThread::WorkRequest::deleteRequest() { - LLQueuedThread::QueuedRequest::deleteRequest(); -} + LLQueuedThread::QueuedRequest::deleteRequest(); +} // virtual bool LLWorkerThread::WorkRequest::processRequest() { LL_PROFILE_ZONE_SCOPED; - LLWorkerClass* workerclass = getWorkerClass(); - workerclass->setWorking(true); - bool complete = workerclass->doWork(getParam()); - workerclass->setWorking(false); - return complete; + LLWorkerClass* workerclass = getWorkerClass(); + workerclass->setWorking(true); + bool complete = workerclass->doWork(getParam()); + workerclass->setWorking(false); + return complete; } // virtual void LLWorkerThread::WorkRequest::finishRequest(bool completed) { LL_PROFILE_ZONE_SCOPED; - LLWorkerClass* workerclass = getWorkerClass(); - workerclass->finishWork(getParam(), completed); - U32 flags = LLWorkerClass::WCF_WORK_FINISHED | (completed ? 0 : LLWorkerClass::WCF_WORK_ABORTED); - workerclass->setFlags(flags); + LLWorkerClass* workerclass = getWorkerClass(); + workerclass->finishWork(getParam(), completed); + U32 flags = LLWorkerClass::WCF_WORK_FINISHED | (completed ? 0 : LLWorkerClass::WCF_WORK_ABORTED); + workerclass->setFlags(flags); } //============================================================================ // LLWorkerClass:: operates in main thread LLWorkerClass::LLWorkerClass(LLWorkerThread* workerthread, const std::string& name) - : mWorkerThread(workerthread), - mWorkerClassName(name), - mRequestHandle(LLWorkerThread::nullHandle()), - mMutex(), - mWorkFlags(0) + : mWorkerThread(workerthread), + mWorkerClassName(name), + mRequestHandle(LLWorkerThread::nullHandle()), + mMutex(), + mWorkFlags(0) { - if (!mWorkerThread) - { - LL_ERRS() << "LLWorkerClass() called with NULL workerthread: " << name << LL_ENDL; - } + if (!mWorkerThread) + { + LL_ERRS() << "LLWorkerClass() called with NULL workerthread: " << name << LL_ENDL; + } } LLWorkerClass::~LLWorkerClass() { - llassert_always(!(mWorkFlags & WCF_WORKING)); - llassert_always(mWorkFlags & WCF_DELETE_REQUESTED); - llassert_always(!mMutex.isLocked()); - if (mRequestHandle != LLWorkerThread::nullHandle()) - { - LLWorkerThread::WorkRequest* workreq = (LLWorkerThread::WorkRequest*)mWorkerThread->getRequest(mRequestHandle); - if (!workreq) - { - LL_ERRS() << "LLWorkerClass destroyed with stale work handle" << LL_ENDL; - } - if (workreq->getStatus() != LLWorkerThread::STATUS_ABORTED && - workreq->getStatus() != LLWorkerThread::STATUS_COMPLETE) - { - LL_ERRS() << "LLWorkerClass destroyed with active worker! Worker Status: " << workreq->getStatus() << LL_ENDL; - } - } + llassert_always(!(mWorkFlags & WCF_WORKING)); + llassert_always(mWorkFlags & WCF_DELETE_REQUESTED); + llassert_always(!mMutex.isLocked()); + if (mRequestHandle != LLWorkerThread::nullHandle()) + { + LLWorkerThread::WorkRequest* workreq = (LLWorkerThread::WorkRequest*)mWorkerThread->getRequest(mRequestHandle); + if (!workreq) + { + LL_ERRS() << "LLWorkerClass destroyed with stale work handle" << LL_ENDL; + } + if (workreq->getStatus() != LLWorkerThread::STATUS_ABORTED && + workreq->getStatus() != LLWorkerThread::STATUS_COMPLETE) + { + LL_ERRS() << "LLWorkerClass destroyed with active worker! Worker Status: " << workreq->getStatus() << LL_ENDL; + } + } } void LLWorkerClass::setWorkerThread(LLWorkerThread* workerthread) { - mMutex.lock(); - if (mRequestHandle != LLWorkerThread::nullHandle()) - { - LL_ERRS() << "LLWorkerClass attempt to change WorkerThread with active worker!" << LL_ENDL; - } - mWorkerThread = workerthread; - mMutex.unlock(); + mMutex.lock(); + if (mRequestHandle != LLWorkerThread::nullHandle()) + { + LL_ERRS() << "LLWorkerClass attempt to change WorkerThread with active worker!" << LL_ENDL; + } + mWorkerThread = workerthread; + mMutex.unlock(); } //---------------------------------------------------------------------------- @@ -254,7 +254,7 @@ void LLWorkerClass::finishWork(S32 param, bool success) //virtual bool LLWorkerClass::deleteOK() { - return true; // default always OK + return true; // default always OK } //---------------------------------------------------------------------------- @@ -262,31 +262,31 @@ bool LLWorkerClass::deleteOK() // Called from worker thread void LLWorkerClass::setWorking(bool working) { - mMutex.lock(); - if (working) - { - llassert_always(!(mWorkFlags & WCF_WORKING)); - setFlags(WCF_WORKING); - } - else - { - llassert_always((mWorkFlags & WCF_WORKING)); - clearFlags(WCF_WORKING); - } - mMutex.unlock(); + mMutex.lock(); + if (working) + { + llassert_always(!(mWorkFlags & WCF_WORKING)); + setFlags(WCF_WORKING); + } + else + { + llassert_always((mWorkFlags & WCF_WORKING)); + clearFlags(WCF_WORKING); + } + mMutex.unlock(); } //---------------------------------------------------------------------------- bool LLWorkerClass::yield() { - LLThread::yield(); - mWorkerThread->checkPause(); - bool res; - mMutex.lock(); - res = (getFlags() & WCF_ABORT_REQUESTED) ? true : false; - mMutex.unlock(); - return res; + LLThread::yield(); + mWorkerThread->checkPause(); + bool res; + mMutex.lock(); + res = (getFlags() & WCF_ABORT_REQUESTED) ? true : false; + mMutex.unlock(); + return res; } //---------------------------------------------------------------------------- @@ -294,104 +294,104 @@ bool LLWorkerClass::yield() // calls startWork, adds doWork() to queue void LLWorkerClass::addWork(S32 param) { - mMutex.lock(); - llassert_always(!(mWorkFlags & (WCF_WORKING|WCF_HAVE_WORK))); - if (mRequestHandle != LLWorkerThread::nullHandle()) - { - LL_ERRS() << "LLWorkerClass attempt to add work with active worker!" << LL_ENDL; - } + mMutex.lock(); + llassert_always(!(mWorkFlags & (WCF_WORKING|WCF_HAVE_WORK))); + if (mRequestHandle != LLWorkerThread::nullHandle()) + { + LL_ERRS() << "LLWorkerClass attempt to add work with active worker!" << LL_ENDL; + } #if _DEBUG -// LL_INFOS() << "addWork: " << mWorkerClassName << " Param: " << param << LL_ENDL; +// LL_INFOS() << "addWork: " << mWorkerClassName << " Param: " << param << LL_ENDL; #endif - startWork(param); - clearFlags(WCF_WORK_FINISHED|WCF_WORK_ABORTED); - setFlags(WCF_HAVE_WORK); - mRequestHandle = mWorkerThread->addWorkRequest(this, param); - mMutex.unlock(); + startWork(param); + clearFlags(WCF_WORK_FINISHED|WCF_WORK_ABORTED); + setFlags(WCF_HAVE_WORK); + mRequestHandle = mWorkerThread->addWorkRequest(this, param); + mMutex.unlock(); } void LLWorkerClass::abortWork(bool autocomplete) { - mMutex.lock(); + mMutex.lock(); #if _DEBUG -// LLWorkerThread::WorkRequest* workreq = mWorkerThread->getRequest(mRequestHandle); -// if (workreq) -// LL_INFOS() << "abortWork: " << mWorkerClassName << " Param: " << workreq->getParam() << LL_ENDL; +// LLWorkerThread::WorkRequest* workreq = mWorkerThread->getRequest(mRequestHandle); +// if (workreq) +// LL_INFOS() << "abortWork: " << mWorkerClassName << " Param: " << workreq->getParam() << LL_ENDL; #endif - if (mRequestHandle != LLWorkerThread::nullHandle()) - { - mWorkerThread->abortRequest(mRequestHandle, autocomplete); - setFlags(WCF_ABORT_REQUESTED); - } - mMutex.unlock(); + if (mRequestHandle != LLWorkerThread::nullHandle()) + { + mWorkerThread->abortRequest(mRequestHandle, autocomplete); + setFlags(WCF_ABORT_REQUESTED); + } + mMutex.unlock(); } // if doWork is complete or aborted, call endWork() and return true bool LLWorkerClass::checkWork(bool aborting) { - LLMutexLock lock(&mMutex); - bool complete = false, abort = false; - if (mRequestHandle != LLWorkerThread::nullHandle()) - { - LLWorkerThread::WorkRequest* workreq = (LLWorkerThread::WorkRequest*)mWorkerThread->getRequest(mRequestHandle); - if(!workreq) - { - if(mWorkerThread->isQuitting() || mWorkerThread->isStopped()) //the mWorkerThread is not running - { - mRequestHandle = LLWorkerThread::nullHandle(); - clearFlags(WCF_HAVE_WORK); - } - else - { - llassert_always(workreq); - } - return true ; - } - - LLQueuedThread::status_t status = workreq->getStatus(); - if (status == LLWorkerThread::STATUS_ABORTED) - { - complete = true; - abort = true; - } - else if (status == LLWorkerThread::STATUS_COMPLETE) - { - complete = true; - } - else - { - llassert_always(!aborting || (workreq->getFlags() & LLQueuedThread::FLAG_ABORT)); - } - if (complete) - { - llassert_always(!(getFlags(WCF_WORKING))); - endWork(workreq->getParam(), abort); - mWorkerThread->completeRequest(mRequestHandle); - mRequestHandle = LLWorkerThread::nullHandle(); - clearFlags(WCF_HAVE_WORK); - } - } - else - { - complete = true; - } - return complete; + LLMutexLock lock(&mMutex); + bool complete = false, abort = false; + if (mRequestHandle != LLWorkerThread::nullHandle()) + { + LLWorkerThread::WorkRequest* workreq = (LLWorkerThread::WorkRequest*)mWorkerThread->getRequest(mRequestHandle); + if(!workreq) + { + if(mWorkerThread->isQuitting() || mWorkerThread->isStopped()) //the mWorkerThread is not running + { + mRequestHandle = LLWorkerThread::nullHandle(); + clearFlags(WCF_HAVE_WORK); + } + else + { + llassert_always(workreq); + } + return true ; + } + + LLQueuedThread::status_t status = workreq->getStatus(); + if (status == LLWorkerThread::STATUS_ABORTED) + { + complete = true; + abort = true; + } + else if (status == LLWorkerThread::STATUS_COMPLETE) + { + complete = true; + } + else + { + llassert_always(!aborting || (workreq->getFlags() & LLQueuedThread::FLAG_ABORT)); + } + if (complete) + { + llassert_always(!(getFlags(WCF_WORKING))); + endWork(workreq->getParam(), abort); + mWorkerThread->completeRequest(mRequestHandle); + mRequestHandle = LLWorkerThread::nullHandle(); + clearFlags(WCF_HAVE_WORK); + } + } + else + { + complete = true; + } + return complete; } void LLWorkerClass::scheduleDelete() { - bool do_delete = false; - mMutex.lock(); - if (!(getFlags(WCF_DELETE_REQUESTED))) - { - setFlags(WCF_DELETE_REQUESTED); - do_delete = true; - } - mMutex.unlock(); - if (do_delete) - { - mWorkerThread->deleteWorker(this); - } + bool do_delete = false; + mMutex.lock(); + if (!(getFlags(WCF_DELETE_REQUESTED))) + { + setFlags(WCF_DELETE_REQUESTED); + do_delete = true; + } + mMutex.unlock(); + if (do_delete) + { + mWorkerThread->deleteWorker(this); + } } //============================================================================ diff --git a/indra/llcommon/llworkerthread.h b/indra/llcommon/llworkerthread.h index bf94c84090..01c96852d3 100644 --- a/indra/llcommon/llworkerthread.h +++ b/indra/llcommon/llworkerthread.h @@ -1,24 +1,24 @@ -/** +/** * @file llworkerthread.h * * $LicenseInfo:firstyear=2004&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -48,55 +48,55 @@ class LLWorkerClass; class LL_COMMON_API LLWorkerThread : public LLQueuedThread { - friend class LLWorkerClass; + friend class LLWorkerClass; public: - class WorkRequest : public LLQueuedThread::QueuedRequest - { - protected: - virtual ~WorkRequest(); // use deleteRequest() - - public: - WorkRequest(handle_t handle, LLWorkerClass* workerclass, S32 param); - - S32 getParam() - { - return mParam; - } - LLWorkerClass* getWorkerClass() - { - return mWorkerClass; - } - - /*virtual*/ bool processRequest(); - /*virtual*/ void finishRequest(bool completed); - /*virtual*/ void deleteRequest(); - - private: - LLWorkerClass* mWorkerClass; - S32 mParam; - }; + class WorkRequest : public LLQueuedThread::QueuedRequest + { + protected: + virtual ~WorkRequest(); // use deleteRequest() + + public: + WorkRequest(handle_t handle, LLWorkerClass* workerclass, S32 param); + + S32 getParam() + { + return mParam; + } + LLWorkerClass* getWorkerClass() + { + return mWorkerClass; + } + + /*virtual*/ bool processRequest(); + /*virtual*/ void finishRequest(bool completed); + /*virtual*/ void deleteRequest(); + + private: + LLWorkerClass* mWorkerClass; + S32 mParam; + }; protected: - void clearDeleteList() ; + void clearDeleteList() ; private: - typedef std::list delete_list_t; - delete_list_t mDeleteList; - LLMutex* mDeleteMutex; - + typedef std::list delete_list_t; + delete_list_t mDeleteList; + LLMutex* mDeleteMutex; + public: - LLWorkerThread(const std::string& name, bool threaded = true, bool should_pause = false); - ~LLWorkerThread(); + LLWorkerThread(const std::string& name, bool threaded = true, bool should_pause = false); + ~LLWorkerThread(); - /*virtual*/ size_t update(F32 max_time_ms); - - handle_t addWorkRequest(LLWorkerClass* workerclass, S32 param); - - S32 getNumDeletes() { return (S32)mDeleteList.size(); } // debug + /*virtual*/ size_t update(F32 max_time_ms); + + handle_t addWorkRequest(LLWorkerClass* workerclass, S32 param); + + S32 getNumDeletes() { return (S32)mDeleteList.size(); } // debug private: - void deleteWorker(LLWorkerClass* workerclass); // schedule for deletion - + void deleteWorker(LLWorkerClass* workerclass); // schedule for deletion + }; //============================================================================ @@ -118,81 +118,81 @@ private: class LL_COMMON_API LLWorkerClass { - friend class LLWorkerThread; - friend class LLWorkerThread::WorkRequest; + friend class LLWorkerThread; + friend class LLWorkerThread::WorkRequest; public: - typedef LLWorkerThread::handle_t handle_t; - enum FLAGS - { - WCF_HAVE_WORK = 0x01, - WCF_WORKING = 0x02, - WCF_WORK_FINISHED = 0x10, - WCF_WORK_ABORTED = 0x20, - WCF_DELETE_REQUESTED = 0x40, - WCF_ABORT_REQUESTED = 0x80 - }; - + typedef LLWorkerThread::handle_t handle_t; + enum FLAGS + { + WCF_HAVE_WORK = 0x01, + WCF_WORKING = 0x02, + WCF_WORK_FINISHED = 0x10, + WCF_WORK_ABORTED = 0x20, + WCF_DELETE_REQUESTED = 0x40, + WCF_ABORT_REQUESTED = 0x80 + }; + public: - LLWorkerClass(LLWorkerThread* workerthread, const std::string& name); - virtual ~LLWorkerClass(); - - // pure virtual, called from WORKER THREAD, returns TRUE if done - virtual bool doWork(S32 param)=0; // Called from WorkRequest::processRequest() - // virtual, called from finishRequest() after completed or aborted - virtual void finishWork(S32 param, bool completed); // called from finishRequest() (WORK THREAD) - // virtual, returns true if safe to delete the worker - virtual bool deleteOK(); // called from update() (WORK THREAD) - - // schedlueDelete(): schedules deletion once aborted or completed - void scheduleDelete(); - - bool haveWork() { return getFlags(WCF_HAVE_WORK); } // may still be true if aborted - bool isWorking() { return getFlags(WCF_WORKING); } - bool wasAborted() { return getFlags(WCF_ABORT_REQUESTED); } - - const std::string& getName() const { return mWorkerClassName; } + LLWorkerClass(LLWorkerThread* workerthread, const std::string& name); + virtual ~LLWorkerClass(); + + // pure virtual, called from WORKER THREAD, returns TRUE if done + virtual bool doWork(S32 param)=0; // Called from WorkRequest::processRequest() + // virtual, called from finishRequest() after completed or aborted + virtual void finishWork(S32 param, bool completed); // called from finishRequest() (WORK THREAD) + // virtual, returns true if safe to delete the worker + virtual bool deleteOK(); // called from update() (WORK THREAD) + + // schedlueDelete(): schedules deletion once aborted or completed + void scheduleDelete(); + + bool haveWork() { return getFlags(WCF_HAVE_WORK); } // may still be true if aborted + bool isWorking() { return getFlags(WCF_WORKING); } + bool wasAborted() { return getFlags(WCF_ABORT_REQUESTED); } + + const std::string& getName() const { return mWorkerClassName; } protected: - // called from WORKER THREAD - void setWorking(bool working); - - // Call from doWork only to avoid eating up cpu time. - // Returns true if work has been aborted - // yields the current thread and calls mWorkerThread->checkPause() - bool yield(); - - void setWorkerThread(LLWorkerThread* workerthread); - - // addWork(): calls startWork, adds doWork() to queue - void addWork(S32 param); - - // abortWork(): requests that work be aborted - void abortWork(bool autocomplete); - - // checkWork(): if doWork is complete or aborted, call endWork() and return true - bool checkWork(bool aborting = false); + // called from WORKER THREAD + void setWorking(bool working); + + // Call from doWork only to avoid eating up cpu time. + // Returns true if work has been aborted + // yields the current thread and calls mWorkerThread->checkPause() + bool yield(); + + void setWorkerThread(LLWorkerThread* workerthread); + + // addWork(): calls startWork, adds doWork() to queue + void addWork(S32 param); + + // abortWork(): requests that work be aborted + void abortWork(bool autocomplete); + + // checkWork(): if doWork is complete or aborted, call endWork() and return true + bool checkWork(bool aborting = false); private: - void setFlags(U32 flags) { mWorkFlags = mWorkFlags | flags; } - void clearFlags(U32 flags) { mWorkFlags = mWorkFlags & ~flags; } - U32 getFlags() { return mWorkFlags; } + void setFlags(U32 flags) { mWorkFlags = mWorkFlags | flags; } + void clearFlags(U32 flags) { mWorkFlags = mWorkFlags & ~flags; } + U32 getFlags() { return mWorkFlags; } public: - bool getFlags(U32 flags) { return mWorkFlags & flags ? true : false; } - + bool getFlags(U32 flags) { return mWorkFlags & flags ? true : false; } + private: - // pure virtuals - virtual void startWork(S32 param)=0; // called from addWork() (MAIN THREAD) - virtual void endWork(S32 param, bool aborted)=0; // called from doWork() (MAIN THREAD) - + // pure virtuals + virtual void startWork(S32 param)=0; // called from addWork() (MAIN THREAD) + virtual void endWork(S32 param, bool aborted)=0; // called from doWork() (MAIN THREAD) + protected: - LLWorkerThread* mWorkerThread; - std::string mWorkerClassName; - handle_t mRequestHandle; + LLWorkerThread* mWorkerThread; + std::string mWorkerClassName; + handle_t mRequestHandle; private: - LLMutex mMutex; - LLAtomicU32 mWorkFlags; + LLMutex mMutex; + LLAtomicU32 mWorkFlags; }; //============================================================================ diff --git a/indra/llcommon/lockstatic.h b/indra/llcommon/lockstatic.h index 96c53c6473..7cc9b7eec0 100644 --- a/indra/llcommon/lockstatic.h +++ b/indra/llcommon/lockstatic.h @@ -4,7 +4,7 @@ * @date 2019-12-03 * @brief LockStatic class provides mutex-guarded access to the specified * static data. - * + * * $LicenseInfo:firstyear=2019&license=viewerlgpl$ * Copyright (c) 2019, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/mutex.h b/indra/llcommon/mutex.h index 90d0942270..82e46315e2 100644 --- a/indra/llcommon/mutex.h +++ b/indra/llcommon/mutex.h @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2019-12-03 * @brief Wrap in odious boilerplate - * + * * $LicenseInfo:firstyear=2019&license=viewerlgpl$ * Copyright (c) 2019, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/stdtypes.h b/indra/llcommon/stdtypes.h index 3aba9dda00..28e50b3d21 100644 --- a/indra/llcommon/stdtypes.h +++ b/indra/llcommon/stdtypes.h @@ -1,25 +1,25 @@ -/** +/** * @file stdtypes.h * @brief Basic type declarations for cross platform compatibility. * * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -32,12 +32,12 @@ #include #include -typedef signed char S8; -typedef unsigned char U8; -typedef signed short S16; -typedef unsigned short U16; -typedef signed int S32; -typedef unsigned int U32; +typedef signed char S8; +typedef unsigned char U8; +typedef signed short S16; +typedef unsigned short U16; +typedef signed int S32; +typedef unsigned int U32; // to express an index that might go negative // (ssize_t is provided by SOME compilers, don't collide) @@ -52,9 +52,9 @@ typedef typename std::make_signed::type llssize; // The version of clang available with VS 2019 also defines wchar_t as __wchar_t // which is also 16 bits. // In any case, llwchar should be a UTF-32 type. -typedef U32 llwchar; +typedef U32 llwchar; #else -typedef wchar_t llwchar; +typedef wchar_t llwchar; // What we'd actually want is a simple module-scope 'if constexpr' to test // std::is_same::value and use that to define, or not // define, string conversion specializations. Since we don't have that, we'll @@ -63,63 +63,63 @@ typedef wchar_t llwchar; #endif #if LL_WINDOWS -typedef signed __int64 S64; +typedef signed __int64 S64; // probably should be 'hyper' or similiar -#define S64L(a) (a) -typedef unsigned __int64 U64; -#define U64L(a) (a) +#define S64L(a) (a) +typedef unsigned __int64 U64; +#define U64L(a) (a) #else -typedef long long int S64; -typedef long long unsigned int U64; +typedef long long int S64; +typedef long long unsigned int U64; #if LL_DARWIN || LL_LINUX -#define S64L(a) (a##LL) -#define U64L(a) (a##ULL) +#define S64L(a) (a##LL) +#define U64L(a) (a##ULL) #endif #endif -typedef float F32; -typedef double F64; +typedef float F32; +typedef double F64; -typedef S32 BOOL; -typedef U8 KEY; -typedef U32 MASK; -typedef U32 TPACKETID; +typedef S32 BOOL; +typedef U8 KEY; +typedef U32 MASK; +typedef U32 TPACKETID; // Use #define instead of consts to avoid conversion headaches -#define S8_MAX (SCHAR_MAX) -#define U8_MAX (UCHAR_MAX) -#define S16_MAX (SHRT_MAX) -#define U16_MAX (USHRT_MAX) -#define S32_MAX (INT_MAX) -#define U32_MAX (UINT_MAX) -#define F32_MAX (FLT_MAX) -#define F64_MAX (DBL_MAX) - -#define S8_MIN (SCHAR_MIN) -#define U8_MIN (0) -#define S16_MIN (SHRT_MIN) -#define U16_MIN (0) -#define S32_MIN (INT_MIN) -#define U32_MIN (0) -#define F32_MIN (FLT_MIN) -#define F64_MIN (DBL_MIN) +#define S8_MAX (SCHAR_MAX) +#define U8_MAX (UCHAR_MAX) +#define S16_MAX (SHRT_MAX) +#define U16_MAX (USHRT_MAX) +#define S32_MAX (INT_MAX) +#define U32_MAX (UINT_MAX) +#define F32_MAX (FLT_MAX) +#define F64_MAX (DBL_MAX) + +#define S8_MIN (SCHAR_MIN) +#define U8_MIN (0) +#define S16_MIN (SHRT_MIN) +#define U16_MIN (0) +#define S32_MIN (INT_MIN) +#define U32_MIN (0) +#define F32_MIN (FLT_MIN) +#define F64_MIN (DBL_MIN) #ifndef TRUE -#define TRUE (1) +#define TRUE (1) #endif #ifndef FALSE -#define FALSE (0) +#define FALSE (0) #endif #ifndef NULL -#define NULL (0) +#define NULL (0) #endif typedef U8 LLPCode; -#define LL_ARRAY_SIZE( _kArray ) ( sizeof( (_kArray) ) / sizeof( _kArray[0] ) ) +#define LL_ARRAY_SIZE( _kArray ) ( sizeof( (_kArray) ) / sizeof( _kArray[0] ) ) #if LL_LINUX && __GNUC__ <= 2 typedef int intptr_t; diff --git a/indra/llcommon/string_table.h b/indra/llcommon/string_table.h index fe6416fb50..bb525f884b 100644 --- a/indra/llcommon/string_table.h +++ b/indra/llcommon/string_table.h @@ -1,25 +1,25 @@ -/** +/** * @file string_table.h * @brief Legacy wrapper header. * * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcommon/stringize.h b/indra/llcommon/stringize.h index c0b13135f9..536a18abc1 100644 --- a/indra/llcommon/stringize.h +++ b/indra/llcommon/stringize.h @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2008-12-17 * @brief stringize(item) template function and STRINGIZE(expression) macro - * + * * $LicenseInfo:firstyear=2008&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcommon/tests/StringVec.h b/indra/llcommon/tests/StringVec.h index a380b00a05..4311cba992 100644 --- a/indra/llcommon/tests/StringVec.h +++ b/indra/llcommon/tests/StringVec.h @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2012-02-24 * @brief Extend TUT ensure_equals() to handle std::vector - * + * * $LicenseInfo:firstyear=2012&license=viewerlgpl$ * Copyright (c) 2012, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/tests/apply_test.cpp b/indra/llcommon/tests/apply_test.cpp index 56b497e0c8..6d213c2db9 100644 --- a/indra/llcommon/tests/apply_test.cpp +++ b/indra/llcommon/tests/apply_test.cpp @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2022-12-19 * @brief Test for apply. - * + * * $LicenseInfo:firstyear=2022&license=viewerlgpl$ * Copyright (c) 2022, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/tests/bitpack_test.cpp b/indra/llcommon/tests/bitpack_test.cpp index 9bfd567068..2810f926af 100644 --- a/indra/llcommon/tests/bitpack_test.cpp +++ b/indra/llcommon/tests/bitpack_test.cpp @@ -7,25 +7,25 @@ * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ - + #include "linden_common.h" #include "../llbitpack.h" @@ -35,84 +35,84 @@ namespace tut { - struct bit_pack - { - }; - typedef test_group bit_pack_t; - typedef bit_pack_t::object bit_pack_object_t; - tut::bit_pack_t tut_bit_pack("LLBitPack"); - - // pack -> unpack - template<> template<> - void bit_pack_object_t::test<1>() - { - U8 packbuffer[255]; - U8 unpackbuffer[255]; - int pack_bufsize = 0; - int unpack_bufsize = 0; - - LLBitPack bitpack(packbuffer, 255); - - char str[] = "SecondLife is a 3D virtual world"; - int len = sizeof(str); - pack_bufsize = bitpack.bitPack((U8*) str, len*8); - pack_bufsize = bitpack.flushBitPack(); - - LLBitPack bitunpack(packbuffer, pack_bufsize*8); - unpack_bufsize = bitunpack.bitUnpack(unpackbuffer, len*8); - ensure("bitPack: unpack size should be same as string size prior to pack", len == unpack_bufsize); - ensure_memory_matches("str->bitPack->bitUnpack should be equal to string", str, len, unpackbuffer, unpack_bufsize); - } - - // pack large, unpack in individual bytes - template<> template<> - void bit_pack_object_t::test<2>() - { - U8 packbuffer[255]; - U8 unpackbuffer[255]; - int pack_bufsize = 0; - - LLBitPack bitpack(packbuffer, 255); - - char str[] = "SecondLife"; - int len = sizeof(str); - pack_bufsize = bitpack.bitPack((U8*) str, len*8); - pack_bufsize = bitpack.flushBitPack(); - - LLBitPack bitunpack(packbuffer, pack_bufsize*8); - bitunpack.bitUnpack(&unpackbuffer[0], 8); - ensure("bitPack: individual unpack: 0", unpackbuffer[0] == (U8) str[0]); - bitunpack.bitUnpack(&unpackbuffer[0], 8); - ensure("bitPack: individual unpack: 1", unpackbuffer[0] == (U8) str[1]); - bitunpack.bitUnpack(&unpackbuffer[0], 8); - ensure("bitPack: individual unpack: 2", unpackbuffer[0] == (U8) str[2]); - bitunpack.bitUnpack(&unpackbuffer[0], 8); - ensure("bitPack: individual unpack: 3", unpackbuffer[0] == (U8) str[3]); - bitunpack.bitUnpack(&unpackbuffer[0], 8); - ensure("bitPack: individual unpack: 4", unpackbuffer[0] == (U8) str[4]); - bitunpack.bitUnpack(&unpackbuffer[0], 8); - ensure("bitPack: individual unpack: 5", unpackbuffer[0] == (U8) str[5]); - bitunpack.bitUnpack(unpackbuffer, 8*4); // Life - ensure_memory_matches("bitPack: 4 bytes unpack:", unpackbuffer, 4, str+6, 4); - } - - // U32 packing - template<> template<> - void bit_pack_object_t::test<3>() - { - U8 packbuffer[255]; - int pack_bufsize = 0; - - LLBitPack bitpack(packbuffer, 255); - U32 num = 0x41fab67a; - pack_bufsize = bitpack.bitPack((U8*)&num, 8*sizeof(U32)); - pack_bufsize = bitpack.flushBitPack(); - - LLBitPack bitunpack(packbuffer, pack_bufsize*8); - U32 res = 0; - // since packing and unpacking is done on same machine in the unit test run, - // endianness should not matter - bitunpack.bitUnpack((U8*) &res, sizeof(res)*8); - ensure("U32->bitPack->bitUnpack->U32 should be equal", num == res); - } + struct bit_pack + { + }; + typedef test_group bit_pack_t; + typedef bit_pack_t::object bit_pack_object_t; + tut::bit_pack_t tut_bit_pack("LLBitPack"); + + // pack -> unpack + template<> template<> + void bit_pack_object_t::test<1>() + { + U8 packbuffer[255]; + U8 unpackbuffer[255]; + int pack_bufsize = 0; + int unpack_bufsize = 0; + + LLBitPack bitpack(packbuffer, 255); + + char str[] = "SecondLife is a 3D virtual world"; + int len = sizeof(str); + pack_bufsize = bitpack.bitPack((U8*) str, len*8); + pack_bufsize = bitpack.flushBitPack(); + + LLBitPack bitunpack(packbuffer, pack_bufsize*8); + unpack_bufsize = bitunpack.bitUnpack(unpackbuffer, len*8); + ensure("bitPack: unpack size should be same as string size prior to pack", len == unpack_bufsize); + ensure_memory_matches("str->bitPack->bitUnpack should be equal to string", str, len, unpackbuffer, unpack_bufsize); + } + + // pack large, unpack in individual bytes + template<> template<> + void bit_pack_object_t::test<2>() + { + U8 packbuffer[255]; + U8 unpackbuffer[255]; + int pack_bufsize = 0; + + LLBitPack bitpack(packbuffer, 255); + + char str[] = "SecondLife"; + int len = sizeof(str); + pack_bufsize = bitpack.bitPack((U8*) str, len*8); + pack_bufsize = bitpack.flushBitPack(); + + LLBitPack bitunpack(packbuffer, pack_bufsize*8); + bitunpack.bitUnpack(&unpackbuffer[0], 8); + ensure("bitPack: individual unpack: 0", unpackbuffer[0] == (U8) str[0]); + bitunpack.bitUnpack(&unpackbuffer[0], 8); + ensure("bitPack: individual unpack: 1", unpackbuffer[0] == (U8) str[1]); + bitunpack.bitUnpack(&unpackbuffer[0], 8); + ensure("bitPack: individual unpack: 2", unpackbuffer[0] == (U8) str[2]); + bitunpack.bitUnpack(&unpackbuffer[0], 8); + ensure("bitPack: individual unpack: 3", unpackbuffer[0] == (U8) str[3]); + bitunpack.bitUnpack(&unpackbuffer[0], 8); + ensure("bitPack: individual unpack: 4", unpackbuffer[0] == (U8) str[4]); + bitunpack.bitUnpack(&unpackbuffer[0], 8); + ensure("bitPack: individual unpack: 5", unpackbuffer[0] == (U8) str[5]); + bitunpack.bitUnpack(unpackbuffer, 8*4); // Life + ensure_memory_matches("bitPack: 4 bytes unpack:", unpackbuffer, 4, str+6, 4); + } + + // U32 packing + template<> template<> + void bit_pack_object_t::test<3>() + { + U8 packbuffer[255]; + int pack_bufsize = 0; + + LLBitPack bitpack(packbuffer, 255); + U32 num = 0x41fab67a; + pack_bufsize = bitpack.bitPack((U8*)&num, 8*sizeof(U32)); + pack_bufsize = bitpack.flushBitPack(); + + LLBitPack bitunpack(packbuffer, pack_bufsize*8); + U32 res = 0; + // since packing and unpacking is done on same machine in the unit test run, + // endianness should not matter + bitunpack.bitUnpack((U8*) &res, sizeof(res)*8); + ensure("U32->bitPack->bitUnpack->U32 should be equal", num == res); + } } diff --git a/indra/llcommon/tests/classic_callback_test.cpp b/indra/llcommon/tests/classic_callback_test.cpp index c060775c24..fe79179ce6 100644 --- a/indra/llcommon/tests/classic_callback_test.cpp +++ b/indra/llcommon/tests/classic_callback_test.cpp @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2021-09-22 * @brief Test ClassicCallback and HeapClassicCallback. - * + * * $LicenseInfo:firstyear=2021&license=viewerlgpl$ * Copyright (c) 2021, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/tests/commonmisc_test.cpp b/indra/llcommon/tests/commonmisc_test.cpp index 4b3e07fa75..3deb864c0c 100644 --- a/indra/llcommon/tests/commonmisc_test.cpp +++ b/indra/llcommon/tests/commonmisc_test.cpp @@ -1,4 +1,4 @@ -/** +/** * @file common.cpp * @author Phoenix * @date 2005-10-12 @@ -7,27 +7,27 @@ * $LicenseInfo:firstyear=2005&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ -/** - * +/** + * * THOROUGH_DESCRIPTION of common.cpp * */ @@ -54,388 +54,388 @@ namespace tut { - struct sd_data - { - }; - typedef test_group sd_test; - typedef sd_test::object sd_object; - tut::sd_test sd("LLSD"); - - template<> template<> - void sd_object::test<1>() - { - std::ostringstream resp; - resp << "{'connect':true, 'position':[r128,r128,r128], 'look_at':[r0,r1,r0], 'agent_access':'M', 'region_x':i8192, 'region_y':i8192}"; - std::string str = resp.str(); - LLMemoryStream mstr((U8*)str.c_str(), str.size()); - LLSD response; - S32 count = LLSDSerialize::fromNotation(response, mstr, str.size()); - ensure("stream parsed", response.isDefined()); - ensure_equals("stream parse count", count, 13); - ensure_equals("sd type", response.type(), LLSD::TypeMap); - ensure_equals("map element count", response.size(), 6); - ensure_equals("value connect", response["connect"].asBoolean(), true); - ensure_equals("value region_x", response["region_x"].asInteger(),8192); - ensure_equals("value region_y", response["region_y"].asInteger(),8192); - } - - template<> template<> - void sd_object::test<2>() - { - const std::string decoded("random"); - //const std::string encoded("cmFuZG9t\n"); - const std::string streamed("b(6)\"random\""); - typedef std::vector buf_t; - buf_t buf; - std::copy( - decoded.begin(), - decoded.end(), - std::back_insert_iterator(buf)); - LLSD sd; - sd = buf; - std::stringstream str; - S32 count = LLSDSerialize::toNotation(sd, str); - ensure_equals("output count", count, 1); - std::string actual(str.str()); - ensure_equals("formatted binary encoding", actual, streamed); - sd.clear(); - LLSDSerialize::fromNotation(sd, str, str.str().size()); - std::vector after; - after = sd.asBinary(); - ensure_equals("binary decoded size", after.size(), decoded.size()); - ensure("binary decoding", (0 == memcmp( - &after[0], - decoded.c_str(), - decoded.size()))); - } - - template<> template<> - void sd_object::test<3>() - { - for(S32 i = 0; i < 100; ++i) - { - // gen up a starting point - typedef std::vector buf_t; - buf_t source; - srand(i); /* Flawfinder: ignore */ - S32 size = rand() % 1000 + 10; - std::generate_n( - std::back_insert_iterator(source), - size, - rand); - LLSD sd(source); - std::stringstream str; - S32 count = LLSDSerialize::toNotation(sd, str); - sd.clear(); - ensure_equals("format count", count, 1); - LLSD sd2; - count = LLSDSerialize::fromNotation(sd2, str, str.str().size()); - ensure_equals("parse count", count, 1); - buf_t dest = sd2.asBinary(); - str.str(""); - str << "binary encoding size " << i; - ensure_equals(str.str().c_str(), dest.size(), source.size()); - str.str(""); - str << "binary encoding " << i; - ensure(str.str().c_str(), (source == dest)); - } - } - - template<> template<> - void sd_object::test<4>() - { - std::ostringstream ostr; - ostr << "{'task_id':u1fd77b79-a8e7-25a5-9454-02a4d948ba1c}\n" - << "{\n\tname\tObject|\n}\n"; - std::string expected = ostr.str(); - std::stringstream serialized; - serialized << "'" << LLSDNotationFormatter::escapeString(expected) - << "'"; - LLSD sd; - S32 count = LLSDSerialize::fromNotation( - sd, - serialized, - serialized.str().size()); - ensure_equals("parse count", count, 1); - ensure_equals("String streaming", sd.asString(), expected); - } - - template<> template<> - void sd_object::test<5>() - { - for(S32 i = 0; i < 100; ++i) - { - // gen up a starting point - typedef std::vector buf_t; - buf_t source; - srand(666 + i); /* Flawfinder: ignore */ - S32 size = rand() % 1000 + 10; - std::generate_n( - std::back_insert_iterator(source), - size, - rand); - std::stringstream str; - str << "b(" << size << ")\""; - str.write((const char*)&source[0], size); - str << "\""; - LLSD sd; - S32 count = LLSDSerialize::fromNotation(sd, str, str.str().size()); - ensure_equals("binary parse", count, 1); - buf_t actual = sd.asBinary(); - ensure_equals("binary size", actual.size(), (size_t)size); - ensure("binary data", (0 == memcmp(&source[0], &actual[0], size))); - } - } - - template<> template<> - void sd_object::test<6>() - { - std::string expected("'{\"task_id\":u1fd77b79-a8e7-25a5-9454-02a4d948ba1c}'\t\n\t\t"); - std::stringstream str; - str << "s(" << expected.size() << ")'"; - str.write(expected.c_str(), expected.size()); - str << "'"; - LLSD sd; - S32 count = LLSDSerialize::fromNotation(sd, str, str.str().size()); - ensure_equals("parse count", count, 1); - std::string actual = sd.asString(); - ensure_equals("string sizes", actual.size(), expected.size()); - ensure_equals("string content", actual, expected); - } - - template<> template<> - void sd_object::test<7>() - { - std::string msg("come on in"); - std::stringstream stream; - stream << "{'connect':1, 'message':'" << msg << "'," - << " 'position':[r45.65,r100.1,r25.5]," - << " 'look_at':[r0,r1,r0]," - << " 'agent_access':'PG'}"; - LLSD sd; - S32 count = LLSDSerialize::fromNotation( - sd, - stream, - stream.str().size()); - ensure_equals("parse count", count, 12); - ensure_equals("bool value", sd["connect"].asBoolean(), true); - ensure_equals("message value", sd["message"].asString(), msg); - ensure_equals("pos x", sd["position"][0].asReal(), 45.65); - ensure_equals("pos y", sd["position"][1].asReal(), 100.1); - ensure_equals("pos z", sd["position"][2].asReal(), 25.5); - ensure_equals("look x", sd["look_at"][0].asReal(), 0.0); - ensure_equals("look y", sd["look_at"][1].asReal(), 1.0); - ensure_equals("look z", sd["look_at"][2].asReal(), 0.0); - } - - template<> template<> - void sd_object::test<8>() - { - std::stringstream resp; - resp << "{'label':'short string test', 'singlechar':'a', 'empty':'', 'endoftest':'end' }"; - LLSD response; - S32 count = LLSDSerialize::fromNotation( - response, - resp, - resp.str().size()); - ensure_equals("parse count", count, 5); - ensure_equals("sd type", response.type(), LLSD::TypeMap); - ensure_equals("map element count", response.size(), 4); - ensure_equals("singlechar", response["singlechar"].asString(), "a"); - ensure_equals("empty", response["empty"].asString(), ""); - } - - template<> template<> - void sd_object::test<9>() - { - std::ostringstream resp; - resp << "{'label':'short binary test', 'singlebinary':b(1)\"A\", 'singlerawstring':s(1)\"A\", 'endoftest':'end' }"; - std::string str = resp.str(); - LLSD sd; - LLMemoryStream mstr((U8*)str.c_str(), str.size()); - S32 count = LLSDSerialize::fromNotation(sd, mstr, str.size()); - ensure_equals("parse count", count, 5); - ensure("sd created", sd.isDefined()); - ensure_equals("sd type", sd.type(), LLSD::TypeMap); - ensure_equals("map element count", sd.size(), 4); - ensure_equals( - "label", - sd["label"].asString(), - "short binary test"); - std::vector bin = sd["singlebinary"].asBinary(); - std::vector expected; - expected.resize(1); - expected[0] = 'A'; - ensure("single binary", (0 == memcmp(&bin[0], &expected[0], 1))); - ensure_equals( - "single string", - sd["singlerawstring"].asString(), - std::string("A")); - ensure_equals("end", sd["endoftest"].asString(), "end"); - } - - template<> template<> - void sd_object::test<10>() - { - - std::string message("parcel '' is naughty."); - std::stringstream str; - str << "{'message':'" << LLSDNotationFormatter::escapeString(message) - << "'}"; - std::string expected_str("{'message':'parcel \\'\\' is naughty.'}"); - std::string actual_str = str.str(); - ensure_equals("stream contents", actual_str, expected_str); - LLSD sd; - S32 count = LLSDSerialize::fromNotation(sd, str, actual_str.size()); - ensure_equals("parse count", count, 2); - ensure("valid parse", sd.isDefined()); - std::string actual = sd["message"].asString(); - ensure_equals("message contents", actual, message); - } - - template<> template<> - void sd_object::test<11>() - { - std::string expected("\"\"\"\"''''''\""); - std::stringstream str; - str << "'" << LLSDNotationFormatter::escapeString(expected) << "'"; - LLSD sd; - S32 count = LLSDSerialize::fromNotation(sd, str, str.str().size()); - ensure_equals("parse count", count, 1); - ensure_equals("string value", sd.asString(), expected); - } - - template<> template<> - void sd_object::test<12>() - { - std::string expected("mytest\\"); - std::stringstream str; - str << "'" << LLSDNotationFormatter::escapeString(expected) << "'"; - LLSD sd; - S32 count = LLSDSerialize::fromNotation(sd, str, str.str().size()); - ensure_equals("parse count", count, 1); - ensure_equals("string value", sd.asString(), expected); - } - - template<> template<> - void sd_object::test<13>() - { - for(S32 i = 0; i < 1000; ++i) - { - // gen up a starting point - std::string expected; - srand(1337 + i); /* Flawfinder: ignore */ - S32 size = rand() % 30 + 5; - std::generate_n( - std::back_insert_iterator(expected), - size, - rand); - std::stringstream str; - str << "'" << LLSDNotationFormatter::escapeString(expected) << "'"; - LLSD sd; - S32 count = LLSDSerialize::fromNotation(sd, str, expected.size()); - ensure_equals("parse count", count, 1); - std::string actual = sd.asString(); + struct sd_data + { + }; + typedef test_group sd_test; + typedef sd_test::object sd_object; + tut::sd_test sd("LLSD"); + + template<> template<> + void sd_object::test<1>() + { + std::ostringstream resp; + resp << "{'connect':true, 'position':[r128,r128,r128], 'look_at':[r0,r1,r0], 'agent_access':'M', 'region_x':i8192, 'region_y':i8192}"; + std::string str = resp.str(); + LLMemoryStream mstr((U8*)str.c_str(), str.size()); + LLSD response; + S32 count = LLSDSerialize::fromNotation(response, mstr, str.size()); + ensure("stream parsed", response.isDefined()); + ensure_equals("stream parse count", count, 13); + ensure_equals("sd type", response.type(), LLSD::TypeMap); + ensure_equals("map element count", response.size(), 6); + ensure_equals("value connect", response["connect"].asBoolean(), true); + ensure_equals("value region_x", response["region_x"].asInteger(),8192); + ensure_equals("value region_y", response["region_y"].asInteger(),8192); + } + + template<> template<> + void sd_object::test<2>() + { + const std::string decoded("random"); + //const std::string encoded("cmFuZG9t\n"); + const std::string streamed("b(6)\"random\""); + typedef std::vector buf_t; + buf_t buf; + std::copy( + decoded.begin(), + decoded.end(), + std::back_insert_iterator(buf)); + LLSD sd; + sd = buf; + std::stringstream str; + S32 count = LLSDSerialize::toNotation(sd, str); + ensure_equals("output count", count, 1); + std::string actual(str.str()); + ensure_equals("formatted binary encoding", actual, streamed); + sd.clear(); + LLSDSerialize::fromNotation(sd, str, str.str().size()); + std::vector after; + after = sd.asBinary(); + ensure_equals("binary decoded size", after.size(), decoded.size()); + ensure("binary decoding", (0 == memcmp( + &after[0], + decoded.c_str(), + decoded.size()))); + } + + template<> template<> + void sd_object::test<3>() + { + for(S32 i = 0; i < 100; ++i) + { + // gen up a starting point + typedef std::vector buf_t; + buf_t source; + srand(i); /* Flawfinder: ignore */ + S32 size = rand() % 1000 + 10; + std::generate_n( + std::back_insert_iterator(source), + size, + rand); + LLSD sd(source); + std::stringstream str; + S32 count = LLSDSerialize::toNotation(sd, str); + sd.clear(); + ensure_equals("format count", count, 1); + LLSD sd2; + count = LLSDSerialize::fromNotation(sd2, str, str.str().size()); + ensure_equals("parse count", count, 1); + buf_t dest = sd2.asBinary(); + str.str(""); + str << "binary encoding size " << i; + ensure_equals(str.str().c_str(), dest.size(), source.size()); + str.str(""); + str << "binary encoding " << i; + ensure(str.str().c_str(), (source == dest)); + } + } + + template<> template<> + void sd_object::test<4>() + { + std::ostringstream ostr; + ostr << "{'task_id':u1fd77b79-a8e7-25a5-9454-02a4d948ba1c}\n" + << "{\n\tname\tObject|\n}\n"; + std::string expected = ostr.str(); + std::stringstream serialized; + serialized << "'" << LLSDNotationFormatter::escapeString(expected) + << "'"; + LLSD sd; + S32 count = LLSDSerialize::fromNotation( + sd, + serialized, + serialized.str().size()); + ensure_equals("parse count", count, 1); + ensure_equals("String streaming", sd.asString(), expected); + } + + template<> template<> + void sd_object::test<5>() + { + for(S32 i = 0; i < 100; ++i) + { + // gen up a starting point + typedef std::vector buf_t; + buf_t source; + srand(666 + i); /* Flawfinder: ignore */ + S32 size = rand() % 1000 + 10; + std::generate_n( + std::back_insert_iterator(source), + size, + rand); + std::stringstream str; + str << "b(" << size << ")\""; + str.write((const char*)&source[0], size); + str << "\""; + LLSD sd; + S32 count = LLSDSerialize::fromNotation(sd, str, str.str().size()); + ensure_equals("binary parse", count, 1); + buf_t actual = sd.asBinary(); + ensure_equals("binary size", actual.size(), (size_t)size); + ensure("binary data", (0 == memcmp(&source[0], &actual[0], size))); + } + } + + template<> template<> + void sd_object::test<6>() + { + std::string expected("'{\"task_id\":u1fd77b79-a8e7-25a5-9454-02a4d948ba1c}'\t\n\t\t"); + std::stringstream str; + str << "s(" << expected.size() << ")'"; + str.write(expected.c_str(), expected.size()); + str << "'"; + LLSD sd; + S32 count = LLSDSerialize::fromNotation(sd, str, str.str().size()); + ensure_equals("parse count", count, 1); + std::string actual = sd.asString(); + ensure_equals("string sizes", actual.size(), expected.size()); + ensure_equals("string content", actual, expected); + } + + template<> template<> + void sd_object::test<7>() + { + std::string msg("come on in"); + std::stringstream stream; + stream << "{'connect':1, 'message':'" << msg << "'," + << " 'position':[r45.65,r100.1,r25.5]," + << " 'look_at':[r0,r1,r0]," + << " 'agent_access':'PG'}"; + LLSD sd; + S32 count = LLSDSerialize::fromNotation( + sd, + stream, + stream.str().size()); + ensure_equals("parse count", count, 12); + ensure_equals("bool value", sd["connect"].asBoolean(), true); + ensure_equals("message value", sd["message"].asString(), msg); + ensure_equals("pos x", sd["position"][0].asReal(), 45.65); + ensure_equals("pos y", sd["position"][1].asReal(), 100.1); + ensure_equals("pos z", sd["position"][2].asReal(), 25.5); + ensure_equals("look x", sd["look_at"][0].asReal(), 0.0); + ensure_equals("look y", sd["look_at"][1].asReal(), 1.0); + ensure_equals("look z", sd["look_at"][2].asReal(), 0.0); + } + + template<> template<> + void sd_object::test<8>() + { + std::stringstream resp; + resp << "{'label':'short string test', 'singlechar':'a', 'empty':'', 'endoftest':'end' }"; + LLSD response; + S32 count = LLSDSerialize::fromNotation( + response, + resp, + resp.str().size()); + ensure_equals("parse count", count, 5); + ensure_equals("sd type", response.type(), LLSD::TypeMap); + ensure_equals("map element count", response.size(), 4); + ensure_equals("singlechar", response["singlechar"].asString(), "a"); + ensure_equals("empty", response["empty"].asString(), ""); + } + + template<> template<> + void sd_object::test<9>() + { + std::ostringstream resp; + resp << "{'label':'short binary test', 'singlebinary':b(1)\"A\", 'singlerawstring':s(1)\"A\", 'endoftest':'end' }"; + std::string str = resp.str(); + LLSD sd; + LLMemoryStream mstr((U8*)str.c_str(), str.size()); + S32 count = LLSDSerialize::fromNotation(sd, mstr, str.size()); + ensure_equals("parse count", count, 5); + ensure("sd created", sd.isDefined()); + ensure_equals("sd type", sd.type(), LLSD::TypeMap); + ensure_equals("map element count", sd.size(), 4); + ensure_equals( + "label", + sd["label"].asString(), + "short binary test"); + std::vector bin = sd["singlebinary"].asBinary(); + std::vector expected; + expected.resize(1); + expected[0] = 'A'; + ensure("single binary", (0 == memcmp(&bin[0], &expected[0], 1))); + ensure_equals( + "single string", + sd["singlerawstring"].asString(), + std::string("A")); + ensure_equals("end", sd["endoftest"].asString(), "end"); + } + + template<> template<> + void sd_object::test<10>() + { + + std::string message("parcel '' is naughty."); + std::stringstream str; + str << "{'message':'" << LLSDNotationFormatter::escapeString(message) + << "'}"; + std::string expected_str("{'message':'parcel \\'\\' is naughty.'}"); + std::string actual_str = str.str(); + ensure_equals("stream contents", actual_str, expected_str); + LLSD sd; + S32 count = LLSDSerialize::fromNotation(sd, str, actual_str.size()); + ensure_equals("parse count", count, 2); + ensure("valid parse", sd.isDefined()); + std::string actual = sd["message"].asString(); + ensure_equals("message contents", actual, message); + } + + template<> template<> + void sd_object::test<11>() + { + std::string expected("\"\"\"\"''''''\""); + std::stringstream str; + str << "'" << LLSDNotationFormatter::escapeString(expected) << "'"; + LLSD sd; + S32 count = LLSDSerialize::fromNotation(sd, str, str.str().size()); + ensure_equals("parse count", count, 1); + ensure_equals("string value", sd.asString(), expected); + } + + template<> template<> + void sd_object::test<12>() + { + std::string expected("mytest\\"); + std::stringstream str; + str << "'" << LLSDNotationFormatter::escapeString(expected) << "'"; + LLSD sd; + S32 count = LLSDSerialize::fromNotation(sd, str, str.str().size()); + ensure_equals("parse count", count, 1); + ensure_equals("string value", sd.asString(), expected); + } + + template<> template<> + void sd_object::test<13>() + { + for(S32 i = 0; i < 1000; ++i) + { + // gen up a starting point + std::string expected; + srand(1337 + i); /* Flawfinder: ignore */ + S32 size = rand() % 30 + 5; + std::generate_n( + std::back_insert_iterator(expected), + size, + rand); + std::stringstream str; + str << "'" << LLSDNotationFormatter::escapeString(expected) << "'"; + LLSD sd; + S32 count = LLSDSerialize::fromNotation(sd, str, expected.size()); + ensure_equals("parse count", count, 1); + std::string actual = sd.asString(); /* - if(actual != expected) - { - LL_WARNS() << "iteration " << i << LL_ENDL; - std::ostringstream e_str; - std::string::iterator iter = expected.begin(); - std::string::iterator end = expected.end(); - for(; iter != end; ++iter) - { - e_str << (S32)((U8)(*iter)) << " "; - } - e_str << std::endl; - llsd_serialize_string(e_str, expected); - LL_WARNS() << "expected size: " << expected.size() << LL_ENDL; - LL_WARNS() << "expected: " << e_str.str() << LL_ENDL; - - std::ostringstream a_str; - iter = actual.begin(); - end = actual.end(); - for(; iter != end; ++iter) - { - a_str << (S32)((U8)(*iter)) << " "; - } - a_str << std::endl; - llsd_serialize_string(a_str, actual); - LL_WARNS() << "actual size: " << actual.size() << LL_ENDL; - LL_WARNS() << "actual: " << a_str.str() << LL_ENDL; - } + if(actual != expected) + { + LL_WARNS() << "iteration " << i << LL_ENDL; + std::ostringstream e_str; + std::string::iterator iter = expected.begin(); + std::string::iterator end = expected.end(); + for(; iter != end; ++iter) + { + e_str << (S32)((U8)(*iter)) << " "; + } + e_str << std::endl; + llsd_serialize_string(e_str, expected); + LL_WARNS() << "expected size: " << expected.size() << LL_ENDL; + LL_WARNS() << "expected: " << e_str.str() << LL_ENDL; + + std::ostringstream a_str; + iter = actual.begin(); + end = actual.end(); + for(; iter != end; ++iter) + { + a_str << (S32)((U8)(*iter)) << " "; + } + a_str << std::endl; + llsd_serialize_string(a_str, actual); + LL_WARNS() << "actual size: " << actual.size() << LL_ENDL; + LL_WARNS() << "actual: " << a_str.str() << LL_ENDL; + } */ - ensure_equals("string value", actual, expected); - } - } + ensure_equals("string value", actual, expected); + } + } - template<> template<> - void sd_object::test<14>() - { + template<> template<> + void sd_object::test<14>() + { //#if LL_WINDOWS && _MSC_VER >= 1400 // skip_fail("Fails on VS2005 due to broken LLSDSerialize::fromNotation() parser."); //#endif - std::string param = "[{'version':i1},{'data':{'binary_bucket':b(0)\"\"},'from_id':u3c115e51-04f4-523c-9fa6-98aff1034730,'from_name':'Phoenix Linden','id':u004e45e5-5576-277a-fba7-859d6a4cb5c8,'message':'hey','offline':i0,'timestamp':i0,'to_id':u3c5f1bb4-5182-7546-6401-1d329b4ff2f8,'type':i0},{'agent_id':u3c115e51-04f4-523c-9fa6-98aff1034730,'god_level':i0,'limited_to_estate':i1}]"; - std::istringstream istr; - istr.str(param); - LLSD param_sd; - LLSDSerialize::fromNotation(param_sd, istr, param.size()); - ensure_equals("parsed type", param_sd.type(), LLSD::TypeArray); - LLSD version_sd = param_sd[0]; - ensure_equals("version type", version_sd.type(), LLSD::TypeMap); - ensure("has version", version_sd.has("version")); - ensure_equals("version number", version_sd["version"].asInteger(), 1); - LLSD src_sd = param_sd[1]; - ensure_equals("src type", src_sd.type(), LLSD::TypeMap); - LLSD dst_sd = param_sd[2]; - ensure_equals("dst type", dst_sd.type(), LLSD::TypeMap); - } - - template<> template<> - void sd_object::test<15>() - { - std::string val = "[{'failures':!,'successfuls':[u3c115e51-04f4-523c-9fa6-98aff1034730]}]"; - std::istringstream istr; - istr.str(val); - LLSD sd; - LLSDSerialize::fromNotation(sd, istr, val.size()); - ensure_equals("parsed type", sd.type(), LLSD::TypeArray); - ensure_equals("parsed size", sd.size(), 1); - LLSD failures = sd[0]["failures"]; - ensure("no failures.", failures.isUndefined()); - LLSD success = sd[0]["successfuls"]; - ensure_equals("success type", success.type(), LLSD::TypeArray); - ensure_equals("success size", success.size(), 1); - ensure_equals("success instance type", success[0].type(), LLSD::TypeUUID); - } - - template<> template<> - void sd_object::test<16>() - { - std::string val = "[f,t,0,1,{'foo':t,'bar':f}]"; - std::istringstream istr; - istr.str(val); - LLSD sd; - LLSDSerialize::fromNotation(sd, istr, val.size()); - ensure_equals("parsed type", sd.type(), LLSD::TypeArray); - ensure_equals("parsed size", sd.size(), 5); - ensure_equals("element 0 false", sd[0].asBoolean(), false); - ensure_equals("element 1 true", sd[1].asBoolean(), true); - ensure_equals("element 2 false", sd[2].asBoolean(), false); - ensure_equals("element 3 true", sd[3].asBoolean(), true); - LLSD map = sd[4]; - ensure_equals("element 4 type", map.type(), LLSD::TypeMap); - ensure_equals("map foo type", map["foo"].type(), LLSD::TypeBoolean); - ensure_equals("map foo value", map["foo"].asBoolean(), true); - ensure_equals("map bar type", map["bar"].type(), LLSD::TypeBoolean); - ensure_equals("map bar value", map["bar"].asBoolean(), false); - } + std::string param = "[{'version':i1},{'data':{'binary_bucket':b(0)\"\"},'from_id':u3c115e51-04f4-523c-9fa6-98aff1034730,'from_name':'Phoenix Linden','id':u004e45e5-5576-277a-fba7-859d6a4cb5c8,'message':'hey','offline':i0,'timestamp':i0,'to_id':u3c5f1bb4-5182-7546-6401-1d329b4ff2f8,'type':i0},{'agent_id':u3c115e51-04f4-523c-9fa6-98aff1034730,'god_level':i0,'limited_to_estate':i1}]"; + std::istringstream istr; + istr.str(param); + LLSD param_sd; + LLSDSerialize::fromNotation(param_sd, istr, param.size()); + ensure_equals("parsed type", param_sd.type(), LLSD::TypeArray); + LLSD version_sd = param_sd[0]; + ensure_equals("version type", version_sd.type(), LLSD::TypeMap); + ensure("has version", version_sd.has("version")); + ensure_equals("version number", version_sd["version"].asInteger(), 1); + LLSD src_sd = param_sd[1]; + ensure_equals("src type", src_sd.type(), LLSD::TypeMap); + LLSD dst_sd = param_sd[2]; + ensure_equals("dst type", dst_sd.type(), LLSD::TypeMap); + } + + template<> template<> + void sd_object::test<15>() + { + std::string val = "[{'failures':!,'successfuls':[u3c115e51-04f4-523c-9fa6-98aff1034730]}]"; + std::istringstream istr; + istr.str(val); + LLSD sd; + LLSDSerialize::fromNotation(sd, istr, val.size()); + ensure_equals("parsed type", sd.type(), LLSD::TypeArray); + ensure_equals("parsed size", sd.size(), 1); + LLSD failures = sd[0]["failures"]; + ensure("no failures.", failures.isUndefined()); + LLSD success = sd[0]["successfuls"]; + ensure_equals("success type", success.type(), LLSD::TypeArray); + ensure_equals("success size", success.size(), 1); + ensure_equals("success instance type", success[0].type(), LLSD::TypeUUID); + } + + template<> template<> + void sd_object::test<16>() + { + std::string val = "[f,t,0,1,{'foo':t,'bar':f}]"; + std::istringstream istr; + istr.str(val); + LLSD sd; + LLSDSerialize::fromNotation(sd, istr, val.size()); + ensure_equals("parsed type", sd.type(), LLSD::TypeArray); + ensure_equals("parsed size", sd.size(), 5); + ensure_equals("element 0 false", sd[0].asBoolean(), false); + ensure_equals("element 1 true", sd[1].asBoolean(), true); + ensure_equals("element 2 false", sd[2].asBoolean(), false); + ensure_equals("element 3 true", sd[3].asBoolean(), true); + LLSD map = sd[4]; + ensure_equals("element 4 type", map.type(), LLSD::TypeMap); + ensure_equals("map foo type", map["foo"].type(), LLSD::TypeBoolean); + ensure_equals("map foo value", map["foo"].asBoolean(), true); + ensure_equals("map bar type", map["bar"].type(), LLSD::TypeBoolean); + ensure_equals("map bar value", map["bar"].asBoolean(), false); + } /* - template<> template<> - void sd_object::test<16>() - { - } + template<> template<> + void sd_object::test<16>() + { + } */ } @@ -445,227 +445,227 @@ namespace tut namespace tut { - struct mem_data - { - }; - typedef test_group mem_test; - typedef mem_test::object mem_object; - tut::mem_test mem_stream("LLMemoryStream"); - - template<> template<> - void mem_object::test<1>() - { - const char HELLO_WORLD[] = "hello world"; - LLMemoryStream mem((U8*)&HELLO_WORLD[0], strlen(HELLO_WORLD)); /* Flawfinder: ignore */ - std::string hello; - std::string world; - mem >> hello >> world; - ensure_equals("first word", hello, std::string("hello")); - ensure_equals("second word", world, std::string("world")); - } + struct mem_data + { + }; + typedef test_group mem_test; + typedef mem_test::object mem_object; + tut::mem_test mem_stream("LLMemoryStream"); + + template<> template<> + void mem_object::test<1>() + { + const char HELLO_WORLD[] = "hello world"; + LLMemoryStream mem((U8*)&HELLO_WORLD[0], strlen(HELLO_WORLD)); /* Flawfinder: ignore */ + std::string hello; + std::string world; + mem >> hello >> world; + ensure_equals("first word", hello, std::string("hello")); + ensure_equals("second word", world, std::string("world")); + } } namespace tut { - struct U64_data - { - }; - typedef test_group U64_test; - typedef U64_test::object U64_object; - tut::U64_test U64_testcase("U64_conversion"); - - // U64_to_str - template<> template<> - void U64_object::test<1>() - { - U64 val; - std::string val_str; - char result[256]; - std::string result_str; - - val = U64L(18446744073709551610); // slightly less than MAX_U64 - val_str = "18446744073709551610"; - - U64_to_str(val, result, sizeof(result)); - result_str = (const char*) result; - ensure_equals("U64_to_str converted 1.1", val_str, result_str); - - val = 0; - val_str = "0"; - U64_to_str(val, result, sizeof(result)); - result_str = (const char*) result; - ensure_equals("U64_to_str converted 1.2", val_str, result_str); - - val = U64L(18446744073709551615); // 0xFFFFFFFFFFFFFFFF - val_str = "18446744073709551615"; - U64_to_str(val, result, sizeof(result)); - result_str = (const char*) result; - ensure_equals("U64_to_str converted 1.3", val_str, result_str); - - // overflow - will result in warning at compile time - val = U64L(18446744073709551615) + 1; // overflow 0xFFFFFFFFFFFFFFFF + 1 == 0 - val_str = "0"; - U64_to_str(val, result, sizeof(result)); - result_str = (const char*) result; - ensure_equals("U64_to_str converted 1.4", val_str, result_str); - - val = U64L(-1); // 0xFFFFFFFFFFFFFFFF == 18446744073709551615 - val_str = "18446744073709551615"; - U64_to_str(val, result, sizeof(result)); - result_str = (const char*) result; - ensure_equals("U64_to_str converted 1.5", val_str, result_str); - - val = U64L(10000000000000000000); // testing preserving of 0s - val_str = "10000000000000000000"; - U64_to_str(val, result, sizeof(result)); - result_str = (const char*) result; - ensure_equals("U64_to_str converted 1.6", val_str, result_str); - - val = 1; // testing no leading 0s - val_str = "1"; - U64_to_str(val, result, sizeof(result)); - result_str = (const char*) result; - ensure_equals("U64_to_str converted 1.7", val_str, result_str); - - val = U64L(18446744073709551615); // testing exact sized buffer for result - val_str = "18446744073709551615"; - memset(result, 'A', sizeof(result)); // initialize buffer with all 'A' - U64_to_str(val, result, sizeof("18446744073709551615")); //pass in the exact size - result_str = (const char*) result; - ensure_equals("U64_to_str converted 1.8", val_str, result_str); - - val = U64L(18446744073709551615); // testing smaller sized buffer for result - val_str = "1844"; - memset(result, 'A', sizeof(result)); // initialize buffer with all 'A' - U64_to_str(val, result, 5); //pass in a size of 5. should only copy first 4 integers and add a null terminator - result_str = (const char*) result; - ensure_equals("U64_to_str converted 1.9", val_str, result_str); - } - - // str_to_U64 - template<> template<> - void U64_object::test<2>() - { - U64 val; - U64 result; - - val = U64L(18446744073709551610); // slightly less than MAX_U64 - result = str_to_U64("18446744073709551610"); - ensure_equals("str_to_U64 converted 2.1", val, result); - - val = U64L(0); // empty string - result = str_to_U64(LLStringUtil::null); - ensure_equals("str_to_U64 converted 2.2", val, result); - - val = U64L(0); // 0 - result = str_to_U64("0"); - ensure_equals("str_to_U64 converted 2.3", val, result); - - val = U64L(18446744073709551615); // 0xFFFFFFFFFFFFFFFF - result = str_to_U64("18446744073709551615"); - ensure_equals("str_to_U64 converted 2.4", val, result); - - // overflow - will result in warning at compile time - val = U64L(18446744073709551615) + 1; // overflow 0xFFFFFFFFFFFFFFFF + 1 == 0 - result = str_to_U64("18446744073709551616"); - ensure_equals("str_to_U64 converted 2.5", val, result); - - val = U64L(1234); // process till first non-integral character - result = str_to_U64("1234A5678"); - ensure_equals("str_to_U64 converted 2.6", val, result); - - val = U64L(5678); // skip all non-integral characters - result = str_to_U64("ABCD5678"); - ensure_equals("str_to_U64 converted 2.7", val, result); - - // should it skip negative sign and process - // rest of string or return 0 - val = U64L(1234); // skip initial negative sign - result = str_to_U64("-1234"); - ensure_equals("str_to_U64 converted 2.8", val, result); - - val = U64L(5678); // stop at negative sign in the middle - result = str_to_U64("5678-1234"); - ensure_equals("str_to_U64 converted 2.9", val, result); - - val = U64L(0); // no integers - result = str_to_U64("AaCD"); - ensure_equals("str_to_U64 converted 2.10", val, result); - } - - // U64_to_F64 - template<> template<> - void U64_object::test<3>() - { - F64 val; - F64 result; - - result = 18446744073709551610.0; - val = U64_to_F64(U64L(18446744073709551610)); - ensure_equals("U64_to_F64 converted 3.1", val, result); - - result = 18446744073709551615.0; // 0xFFFFFFFFFFFFFFFF - val = U64_to_F64(U64L(18446744073709551615)); - ensure_equals("U64_to_F64 converted 3.2", val, result); - - result = 0.0; // overflow 0xFFFFFFFFFFFFFFFF + 1 == 0 - // overflow - will result in warning at compile time - val = U64_to_F64(U64L(18446744073709551615)+1); - ensure_equals("U64_to_F64 converted 3.3", val, result); - - result = 0.0; // 0 - val = U64_to_F64(U64L(0)); - ensure_equals("U64_to_F64 converted 3.4", val, result); - - result = 1.0; // odd - val = U64_to_F64(U64L(1)); - ensure_equals("U64_to_F64 converted 3.5", val, result); - - result = 2.0; // even - val = U64_to_F64(U64L(2)); - ensure_equals("U64_to_F64 converted 3.6", val, result); - - result = U64L(0x7FFFFFFFFFFFFFFF) * 1.0L; // 0x7FFFFFFFFFFFFFFF - val = U64_to_F64(U64L(0x7FFFFFFFFFFFFFFF)); - ensure_equals("U64_to_F64 converted 3.7", val, result); - } - - // llstrtou64 - // seems to be deprecated - could not find it being used - // anywhere in the tarball - skipping unit tests for now + struct U64_data + { + }; + typedef test_group U64_test; + typedef U64_test::object U64_object; + tut::U64_test U64_testcase("U64_conversion"); + + // U64_to_str + template<> template<> + void U64_object::test<1>() + { + U64 val; + std::string val_str; + char result[256]; + std::string result_str; + + val = U64L(18446744073709551610); // slightly less than MAX_U64 + val_str = "18446744073709551610"; + + U64_to_str(val, result, sizeof(result)); + result_str = (const char*) result; + ensure_equals("U64_to_str converted 1.1", val_str, result_str); + + val = 0; + val_str = "0"; + U64_to_str(val, result, sizeof(result)); + result_str = (const char*) result; + ensure_equals("U64_to_str converted 1.2", val_str, result_str); + + val = U64L(18446744073709551615); // 0xFFFFFFFFFFFFFFFF + val_str = "18446744073709551615"; + U64_to_str(val, result, sizeof(result)); + result_str = (const char*) result; + ensure_equals("U64_to_str converted 1.3", val_str, result_str); + + // overflow - will result in warning at compile time + val = U64L(18446744073709551615) + 1; // overflow 0xFFFFFFFFFFFFFFFF + 1 == 0 + val_str = "0"; + U64_to_str(val, result, sizeof(result)); + result_str = (const char*) result; + ensure_equals("U64_to_str converted 1.4", val_str, result_str); + + val = U64L(-1); // 0xFFFFFFFFFFFFFFFF == 18446744073709551615 + val_str = "18446744073709551615"; + U64_to_str(val, result, sizeof(result)); + result_str = (const char*) result; + ensure_equals("U64_to_str converted 1.5", val_str, result_str); + + val = U64L(10000000000000000000); // testing preserving of 0s + val_str = "10000000000000000000"; + U64_to_str(val, result, sizeof(result)); + result_str = (const char*) result; + ensure_equals("U64_to_str converted 1.6", val_str, result_str); + + val = 1; // testing no leading 0s + val_str = "1"; + U64_to_str(val, result, sizeof(result)); + result_str = (const char*) result; + ensure_equals("U64_to_str converted 1.7", val_str, result_str); + + val = U64L(18446744073709551615); // testing exact sized buffer for result + val_str = "18446744073709551615"; + memset(result, 'A', sizeof(result)); // initialize buffer with all 'A' + U64_to_str(val, result, sizeof("18446744073709551615")); //pass in the exact size + result_str = (const char*) result; + ensure_equals("U64_to_str converted 1.8", val_str, result_str); + + val = U64L(18446744073709551615); // testing smaller sized buffer for result + val_str = "1844"; + memset(result, 'A', sizeof(result)); // initialize buffer with all 'A' + U64_to_str(val, result, 5); //pass in a size of 5. should only copy first 4 integers and add a null terminator + result_str = (const char*) result; + ensure_equals("U64_to_str converted 1.9", val_str, result_str); + } + + // str_to_U64 + template<> template<> + void U64_object::test<2>() + { + U64 val; + U64 result; + + val = U64L(18446744073709551610); // slightly less than MAX_U64 + result = str_to_U64("18446744073709551610"); + ensure_equals("str_to_U64 converted 2.1", val, result); + + val = U64L(0); // empty string + result = str_to_U64(LLStringUtil::null); + ensure_equals("str_to_U64 converted 2.2", val, result); + + val = U64L(0); // 0 + result = str_to_U64("0"); + ensure_equals("str_to_U64 converted 2.3", val, result); + + val = U64L(18446744073709551615); // 0xFFFFFFFFFFFFFFFF + result = str_to_U64("18446744073709551615"); + ensure_equals("str_to_U64 converted 2.4", val, result); + + // overflow - will result in warning at compile time + val = U64L(18446744073709551615) + 1; // overflow 0xFFFFFFFFFFFFFFFF + 1 == 0 + result = str_to_U64("18446744073709551616"); + ensure_equals("str_to_U64 converted 2.5", val, result); + + val = U64L(1234); // process till first non-integral character + result = str_to_U64("1234A5678"); + ensure_equals("str_to_U64 converted 2.6", val, result); + + val = U64L(5678); // skip all non-integral characters + result = str_to_U64("ABCD5678"); + ensure_equals("str_to_U64 converted 2.7", val, result); + + // should it skip negative sign and process + // rest of string or return 0 + val = U64L(1234); // skip initial negative sign + result = str_to_U64("-1234"); + ensure_equals("str_to_U64 converted 2.8", val, result); + + val = U64L(5678); // stop at negative sign in the middle + result = str_to_U64("5678-1234"); + ensure_equals("str_to_U64 converted 2.9", val, result); + + val = U64L(0); // no integers + result = str_to_U64("AaCD"); + ensure_equals("str_to_U64 converted 2.10", val, result); + } + + // U64_to_F64 + template<> template<> + void U64_object::test<3>() + { + F64 val; + F64 result; + + result = 18446744073709551610.0; + val = U64_to_F64(U64L(18446744073709551610)); + ensure_equals("U64_to_F64 converted 3.1", val, result); + + result = 18446744073709551615.0; // 0xFFFFFFFFFFFFFFFF + val = U64_to_F64(U64L(18446744073709551615)); + ensure_equals("U64_to_F64 converted 3.2", val, result); + + result = 0.0; // overflow 0xFFFFFFFFFFFFFFFF + 1 == 0 + // overflow - will result in warning at compile time + val = U64_to_F64(U64L(18446744073709551615)+1); + ensure_equals("U64_to_F64 converted 3.3", val, result); + + result = 0.0; // 0 + val = U64_to_F64(U64L(0)); + ensure_equals("U64_to_F64 converted 3.4", val, result); + + result = 1.0; // odd + val = U64_to_F64(U64L(1)); + ensure_equals("U64_to_F64 converted 3.5", val, result); + + result = 2.0; // even + val = U64_to_F64(U64L(2)); + ensure_equals("U64_to_F64 converted 3.6", val, result); + + result = U64L(0x7FFFFFFFFFFFFFFF) * 1.0L; // 0x7FFFFFFFFFFFFFFF + val = U64_to_F64(U64L(0x7FFFFFFFFFFFFFFF)); + ensure_equals("U64_to_F64 converted 3.7", val, result); + } + + // llstrtou64 + // seems to be deprecated - could not find it being used + // anywhere in the tarball - skipping unit tests for now } namespace tut { - struct hash_data - { - }; - typedef test_group hash_test; - typedef hash_test::object hash_object; - tut::hash_test hash_tester("LLHash"); + struct hash_data + { + }; + typedef test_group hash_test; + typedef hash_test::object hash_object; + tut::hash_test hash_tester("LLHash"); + + template<> template<> + void hash_object::test<1>() + { + const char * str1 = "test string one"; + const char * same_as_str1 = "test string one"; + + size_t hash1 = llhash(str1); + size_t same_as_hash1 = llhash(same_as_str1); - template<> template<> - void hash_object::test<1>() - { - const char * str1 = "test string one"; - const char * same_as_str1 = "test string one"; - size_t hash1 = llhash(str1); - size_t same_as_hash1 = llhash(same_as_str1); + ensure("Hashes from identical strings should be equal", hash1 == same_as_hash1); + char str[100]; + strcpy( str, "Another test" ); - ensure("Hashes from identical strings should be equal", hash1 == same_as_hash1); - - char str[100]; - strcpy( str, "Another test" ); + size_t hash2 = llhash(str); - size_t hash2 = llhash(str); - - strcpy( str, "Different string, same pointer" ); + strcpy( str, "Different string, same pointer" ); - size_t hash3 = llhash(str); + size_t hash3 = llhash(str); - ensure("Hashes from same pointer but different string should not be equal", hash2 != hash3); - } + ensure("Hashes from same pointer but different string should not be equal", hash2 != hash3); + } } diff --git a/indra/llcommon/tests/lazyeventapi_test.cpp b/indra/llcommon/tests/lazyeventapi_test.cpp index 31b2d6d17f..f3fcf84e49 100644 --- a/indra/llcommon/tests/lazyeventapi_test.cpp +++ b/indra/llcommon/tests/lazyeventapi_test.cpp @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2022-06-18 * @brief Test for lazyeventapi. - * + * * $LicenseInfo:firstyear=2022&license=viewerlgpl$ * Copyright (c) 2022, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/tests/listener.h b/indra/llcommon/tests/listener.h index 6072060bb6..887a2c9082 100644 --- a/indra/llcommon/tests/listener.h +++ b/indra/llcommon/tests/listener.h @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2009-03-06 * @brief Useful for tests of the LLEventPump family of classes - * + * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcommon/tests/llallocator_heap_profile_test.cpp b/indra/llcommon/tests/llallocator_heap_profile_test.cpp index 44a9705803..da8b54ffc0 100644 --- a/indra/llcommon/tests/llallocator_heap_profile_test.cpp +++ b/indra/llcommon/tests/llallocator_heap_profile_test.cpp @@ -3,25 +3,25 @@ * @author Brad Kittenbrink * @date 2008-02- * @brief Test for llallocator_heap_profile.cpp. - * + * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcommon/tests/llallocator_test.cpp b/indra/llcommon/tests/llallocator_test.cpp index 4e62eaee67..a7573641c7 100644 --- a/indra/llcommon/tests/llallocator_test.cpp +++ b/indra/llcommon/tests/llallocator_test.cpp @@ -3,25 +3,25 @@ * @author Brad Kittenbrink * @date 2008-02- * @brief Test for llallocator.cpp. - * + * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -71,7 +71,7 @@ namespace tut delete [] test_alloc; - llallocator.getProfile(); + llallocator.getProfile(); // *NOTE - this test isn't ensuring anything right now other than no // exceptions are thrown. diff --git a/indra/llcommon/tests/llbase64_test.cpp b/indra/llcommon/tests/llbase64_test.cpp index d0394150fa..69b062fc0c 100644 --- a/indra/llcommon/tests/llbase64_test.cpp +++ b/indra/llcommon/tests/llbase64_test.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llbase64_test.cpp * @author James Cook * @date 2007-02-04 @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -36,42 +36,42 @@ namespace tut { - struct base64_data - { - }; - typedef test_group base64_test; - typedef base64_test::object base64_object; - tut::base64_test base64("LLBase64"); + struct base64_data + { + }; + typedef test_group base64_test; + typedef base64_test::object base64_object; + tut::base64_test base64("LLBase64"); - template<> template<> - void base64_object::test<1>() - { - std::string result; + template<> template<> + void base64_object::test<1>() + { + std::string result; - result = LLBase64::encode(NULL, 0); - ensure("encode nothing", (result == "") ); + result = LLBase64::encode(NULL, 0); + ensure("encode nothing", (result == "") ); - LLUUID nothing; - result = LLBase64::encode(¬hing.mData[0], UUID_BYTES); - ensure("encode blank uuid", - (result == "AAAAAAAAAAAAAAAAAAAAAA==") ); + LLUUID nothing; + result = LLBase64::encode(¬hing.mData[0], UUID_BYTES); + ensure("encode blank uuid", + (result == "AAAAAAAAAAAAAAAAAAAAAA==") ); - LLUUID id("526a1e07-a19d-baed-84c4-ff08a488d15e"); - result = LLBase64::encode(&id.mData[0], UUID_BYTES); - ensure("encode random uuid", - (result == "UmoeB6Gduu2ExP8IpIjRXg==") ); + LLUUID id("526a1e07-a19d-baed-84c4-ff08a488d15e"); + result = LLBase64::encode(&id.mData[0], UUID_BYTES); + ensure("encode random uuid", + (result == "UmoeB6Gduu2ExP8IpIjRXg==") ); - } + } - template<> template<> - void base64_object::test<2>() - { - std::string result; + template<> template<> + void base64_object::test<2>() + { + std::string result; - U8 blob[40] = { 115, 223, 172, 255, 140, 70, 49, 125, 236, 155, 45, 199, 101, 17, 164, 131, 230, 19, 80, 64, 112, 53, 135, 98, 237, 12, 26, 72, 126, 14, 145, 143, 118, 196, 11, 177, 132, 169, 195, 134 }; - result = LLBase64::encode(&blob[0], 40); - ensure("encode 40 bytes", - (result == "c9+s/4xGMX3smy3HZRGkg+YTUEBwNYdi7QwaSH4OkY92xAuxhKnDhg==") ); - } + U8 blob[40] = { 115, 223, 172, 255, 140, 70, 49, 125, 236, 155, 45, 199, 101, 17, 164, 131, 230, 19, 80, 64, 112, 53, 135, 98, 237, 12, 26, 72, 126, 14, 145, 143, 118, 196, 11, 177, 132, 169, 195, 134 }; + result = LLBase64::encode(&blob[0], 40); + ensure("encode 40 bytes", + (result == "c9+s/4xGMX3smy3HZRGkg+YTUEBwNYdi7QwaSH4OkY92xAuxhKnDhg==") ); + } } diff --git a/indra/llcommon/tests/llcond_test.cpp b/indra/llcommon/tests/llcond_test.cpp index 478149eacf..f2a302ed13 100644 --- a/indra/llcommon/tests/llcond_test.cpp +++ b/indra/llcommon/tests/llcond_test.cpp @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2019-07-18 * @brief Test for llcond. - * + * * $LicenseInfo:firstyear=2019&license=viewerlgpl$ * Copyright (c) 2019, Linden Research, Inc. * $/LicenseInfo$ @@ -38,7 +38,7 @@ namespace tut { set_test_name("Immediate gratification"); cond.set_one(1); - ensure("wait_for_equal() failed", + ensure("wait_for_equal() failed", cond.wait_for_equal(F32Milliseconds(1), 1)); ensure("wait_for_unequal() should have failed", ! cond.wait_for_unequal(F32Milliseconds(1), 1)); diff --git a/indra/llcommon/tests/lldate_test.cpp b/indra/llcommon/tests/lldate_test.cpp index 7c95ccb91f..6d38b71649 100644 --- a/indra/llcommon/tests/lldate_test.cpp +++ b/indra/llcommon/tests/lldate_test.cpp @@ -7,21 +7,21 @@ * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -34,180 +34,180 @@ #include "../test/lltut.h" -#define VALID_DATE "2003-04-30T04:00:00Z" -#define VALID_DATE_LEAP "2004-02-29T04:00:00Z" -#define VALID_DATE_HOUR_BOUNDARY "2003-04-30T23:59:59Z" -#define VALID_DATE_FRACTIONAL_SECS "2007-09-26T20:31:33.70Z" +#define VALID_DATE "2003-04-30T04:00:00Z" +#define VALID_DATE_LEAP "2004-02-29T04:00:00Z" +#define VALID_DATE_HOUR_BOUNDARY "2003-04-30T23:59:59Z" +#define VALID_DATE_FRACTIONAL_SECS "2007-09-26T20:31:33.70Z" // invalid format -#define INVALID_DATE_MISSING_YEAR "-04-30T22:59:59Z" -#define INVALID_DATE_MISSING_MONTH "1900-0430T22:59:59Z" -#define INVALID_DATE_MISSING_DATE "1900-0430-T22:59:59Z" -#define INVALID_DATE_MISSING_T "1900-04-30-22:59:59Z" -#define INVALID_DATE_MISSING_HOUR "1900-04-30T:59:59Z" -#define INVALID_DATE_MISSING_MIN "1900-04-30T01::59Z" -#define INVALID_DATE_MISSING_SEC "1900-04-30T01:59Z" -#define INVALID_DATE_MISSING_Z "1900-04-30T01:59:23" -#define INVALID_DATE_EMPTY "" +#define INVALID_DATE_MISSING_YEAR "-04-30T22:59:59Z" +#define INVALID_DATE_MISSING_MONTH "1900-0430T22:59:59Z" +#define INVALID_DATE_MISSING_DATE "1900-0430-T22:59:59Z" +#define INVALID_DATE_MISSING_T "1900-04-30-22:59:59Z" +#define INVALID_DATE_MISSING_HOUR "1900-04-30T:59:59Z" +#define INVALID_DATE_MISSING_MIN "1900-04-30T01::59Z" +#define INVALID_DATE_MISSING_SEC "1900-04-30T01:59Z" +#define INVALID_DATE_MISSING_Z "1900-04-30T01:59:23" +#define INVALID_DATE_EMPTY "" // invalid values // apr 1.1.1 seems to not care about constraining the date to valid // dates. Put these back when the parser checks. #define LL_DATE_PARSER_CHECKS_BOUNDARY 0 -//#define INVALID_DATE_24HOUR_BOUNDARY "2003-04-30T24:00:00Z" -//#define INVALID_DATE_LEAP "2003-04-29T04:00:00Z" -//#define INVALID_DATE_HOUR "2003-04-30T24:59:59Z" -//#define INVALID_DATE_MIN "2003-04-30T22:69:59Z" -//#define INVALID_DATE_SEC "2003-04-30T22:59:69Z" -//#define INVALID_DATE_YEAR "0-04-30T22:59:59Z" -//#define INVALID_DATE_MONTH "2003-13-30T22:59:59Z" -//#define INVALID_DATE_DAY "2003-04-35T22:59:59Z" +//#define INVALID_DATE_24HOUR_BOUNDARY "2003-04-30T24:00:00Z" +//#define INVALID_DATE_LEAP "2003-04-29T04:00:00Z" +//#define INVALID_DATE_HOUR "2003-04-30T24:59:59Z" +//#define INVALID_DATE_MIN "2003-04-30T22:69:59Z" +//#define INVALID_DATE_SEC "2003-04-30T22:59:69Z" +//#define INVALID_DATE_YEAR "0-04-30T22:59:59Z" +//#define INVALID_DATE_MONTH "2003-13-30T22:59:59Z" +//#define INVALID_DATE_DAY "2003-04-35T22:59:59Z" namespace tut { - struct date_test - { + struct date_test + { - }; - typedef test_group date_test_t; - typedef date_test_t::object date_test_object_t; - tut::date_test_t tut_date_test("LLDate"); + }; + typedef test_group date_test_t; + typedef date_test_t::object date_test_object_t; + tut::date_test_t tut_date_test("LLDate"); - /* format validation */ - template<> template<> - void date_test_object_t::test<1>() - { - LLDate date(VALID_DATE); - std::string expected_string; - bool result; - expected_string = VALID_DATE; - ensure_equals("Valid Date failed" , expected_string, date.asString()); + /* format validation */ + template<> template<> + void date_test_object_t::test<1>() + { + LLDate date(VALID_DATE); + std::string expected_string; + bool result; + expected_string = VALID_DATE; + ensure_equals("Valid Date failed" , expected_string, date.asString()); - result = date.fromString(VALID_DATE_LEAP); - expected_string = VALID_DATE_LEAP; - ensure_equals("VALID_DATE_LEAP failed" , expected_string, date.asString()); + result = date.fromString(VALID_DATE_LEAP); + expected_string = VALID_DATE_LEAP; + ensure_equals("VALID_DATE_LEAP failed" , expected_string, date.asString()); - result = date.fromString(VALID_DATE_HOUR_BOUNDARY); - expected_string = VALID_DATE_HOUR_BOUNDARY; - ensure_equals("VALID_DATE_HOUR_BOUNDARY failed" , expected_string, date.asString()); + result = date.fromString(VALID_DATE_HOUR_BOUNDARY); + expected_string = VALID_DATE_HOUR_BOUNDARY; + ensure_equals("VALID_DATE_HOUR_BOUNDARY failed" , expected_string, date.asString()); - result = date.fromString(VALID_DATE_FRACTIONAL_SECS); - expected_string = VALID_DATE_FRACTIONAL_SECS; - ensure_equals("VALID_DATE_FRACTIONAL_SECS failed" , expected_string, date.asString()); + result = date.fromString(VALID_DATE_FRACTIONAL_SECS); + expected_string = VALID_DATE_FRACTIONAL_SECS; + ensure_equals("VALID_DATE_FRACTIONAL_SECS failed" , expected_string, date.asString()); - result = date.fromString(INVALID_DATE_MISSING_YEAR); - ensure_equals("INVALID_DATE_MISSING_YEAR should have failed" , result, false); + result = date.fromString(INVALID_DATE_MISSING_YEAR); + ensure_equals("INVALID_DATE_MISSING_YEAR should have failed" , result, false); - result = date.fromString(INVALID_DATE_MISSING_MONTH); - ensure_equals("INVALID_DATE_MISSING_MONTH should have failed" , result, false); + result = date.fromString(INVALID_DATE_MISSING_MONTH); + ensure_equals("INVALID_DATE_MISSING_MONTH should have failed" , result, false); - result = date.fromString(INVALID_DATE_MISSING_DATE); - ensure_equals("INVALID_DATE_MISSING_DATE should have failed" , result, false); + result = date.fromString(INVALID_DATE_MISSING_DATE); + ensure_equals("INVALID_DATE_MISSING_DATE should have failed" , result, false); - result = date.fromString(INVALID_DATE_MISSING_T); - ensure_equals("INVALID_DATE_MISSING_T should have failed" , result, false); + result = date.fromString(INVALID_DATE_MISSING_T); + ensure_equals("INVALID_DATE_MISSING_T should have failed" , result, false); - result = date.fromString(INVALID_DATE_MISSING_HOUR); - ensure_equals("INVALID_DATE_MISSING_HOUR should have failed" , result, false); + result = date.fromString(INVALID_DATE_MISSING_HOUR); + ensure_equals("INVALID_DATE_MISSING_HOUR should have failed" , result, false); - result = date.fromString(INVALID_DATE_MISSING_MIN); - ensure_equals("INVALID_DATE_MISSING_MIN should have failed" , result, false); + result = date.fromString(INVALID_DATE_MISSING_MIN); + ensure_equals("INVALID_DATE_MISSING_MIN should have failed" , result, false); - result = date.fromString(INVALID_DATE_MISSING_SEC); - ensure_equals("INVALID_DATE_MISSING_SEC should have failed" , result, false); + result = date.fromString(INVALID_DATE_MISSING_SEC); + ensure_equals("INVALID_DATE_MISSING_SEC should have failed" , result, false); - result = date.fromString(INVALID_DATE_MISSING_Z); - ensure_equals("INVALID_DATE_MISSING_Z should have failed" , result, false); + result = date.fromString(INVALID_DATE_MISSING_Z); + ensure_equals("INVALID_DATE_MISSING_Z should have failed" , result, false); - result = date.fromString(INVALID_DATE_EMPTY); - ensure_equals("INVALID_DATE_EMPTY should have failed" , result, false); - } + result = date.fromString(INVALID_DATE_EMPTY); + ensure_equals("INVALID_DATE_EMPTY should have failed" , result, false); + } - /* Invalid Value Handling */ - template<> template<> - void date_test_object_t::test<2>() - { + /* Invalid Value Handling */ + template<> template<> + void date_test_object_t::test<2>() + { #if LL_DATE_PARSER_CHECKS_BOUNDARY - LLDate date; - std::string expected_string; - bool result; + LLDate date; + std::string expected_string; + bool result; - result = date.fromString(INVALID_DATE_24HOUR_BOUNDARY); - ensure_equals("INVALID_DATE_24HOUR_BOUNDARY should have failed" , result, false); - ensure_equals("INVALID_DATE_24HOUR_BOUNDARY date still set to old value on failure!" , date.secondsSinceEpoch(), 0); + result = date.fromString(INVALID_DATE_24HOUR_BOUNDARY); + ensure_equals("INVALID_DATE_24HOUR_BOUNDARY should have failed" , result, false); + ensure_equals("INVALID_DATE_24HOUR_BOUNDARY date still set to old value on failure!" , date.secondsSinceEpoch(), 0); - result = date.fromString(INVALID_DATE_LEAP); - ensure_equals("INVALID_DATE_LEAP should have failed" , result, false); + result = date.fromString(INVALID_DATE_LEAP); + ensure_equals("INVALID_DATE_LEAP should have failed" , result, false); - result = date.fromString(INVALID_DATE_HOUR); - ensure_equals("INVALID_DATE_HOUR should have failed" , result, false); + result = date.fromString(INVALID_DATE_HOUR); + ensure_equals("INVALID_DATE_HOUR should have failed" , result, false); - result = date.fromString(INVALID_DATE_MIN); - ensure_equals("INVALID_DATE_MIN should have failed" , result, false); + result = date.fromString(INVALID_DATE_MIN); + ensure_equals("INVALID_DATE_MIN should have failed" , result, false); - result = date.fromString(INVALID_DATE_SEC); - ensure_equals("INVALID_DATE_SEC should have failed" , result, false); + result = date.fromString(INVALID_DATE_SEC); + ensure_equals("INVALID_DATE_SEC should have failed" , result, false); - result = date.fromString(INVALID_DATE_YEAR); - ensure_equals("INVALID_DATE_YEAR should have failed" , result, false); + result = date.fromString(INVALID_DATE_YEAR); + ensure_equals("INVALID_DATE_YEAR should have failed" , result, false); - result = date.fromString(INVALID_DATE_MONTH); - ensure_equals("INVALID_DATE_MONTH should have failed" , result, false); + result = date.fromString(INVALID_DATE_MONTH); + ensure_equals("INVALID_DATE_MONTH should have failed" , result, false); - result = date.fromString(INVALID_DATE_DAY); - ensure_equals("INVALID_DATE_DAY should have failed" , result, false); + result = date.fromString(INVALID_DATE_DAY); + ensure_equals("INVALID_DATE_DAY should have failed" , result, false); #endif - } - - /* API checks */ - template<> template<> - void date_test_object_t::test<3>() - { - LLDate date; - std::istringstream stream(VALID_DATE); - std::string expected_string = VALID_DATE; - date.fromStream(stream); - ensure_equals("fromStream failed", date.asString(), expected_string); - } - - template<> template<> - void date_test_object_t::test<4>() - { - LLDate date1(VALID_DATE); - LLDate date2(date1); - ensure_equals("LLDate(const LLDate& date) constructor failed", date1.asString(), date2.asString()); - } - - template<> template<> - void date_test_object_t::test<5>() - { - LLDate date1(VALID_DATE); - LLDate date2(date1.secondsSinceEpoch()); - ensure_equals("secondsSinceEpoch not equal",date1.secondsSinceEpoch(), date2.secondsSinceEpoch()); - ensure_equals("LLDate created using secondsSinceEpoch not equal", date1.asString(), date2.asString()); - } - - template<> template<> - void date_test_object_t::test<6>() - { - LLDate date(VALID_DATE); - std::ostringstream stream; - stream << date; - std::string expected_str = VALID_DATE; - ensure_equals("ostringstream failed", expected_str, stream.str()); - } - - template<> template<> - void date_test_object_t::test<7>() - { - LLDate date; - std::istringstream stream(VALID_DATE); - stream >> date; - std::string expected_str = VALID_DATE; - std::ostringstream out_stream; + } + + /* API checks */ + template<> template<> + void date_test_object_t::test<3>() + { + LLDate date; + std::istringstream stream(VALID_DATE); + std::string expected_string = VALID_DATE; + date.fromStream(stream); + ensure_equals("fromStream failed", date.asString(), expected_string); + } + + template<> template<> + void date_test_object_t::test<4>() + { + LLDate date1(VALID_DATE); + LLDate date2(date1); + ensure_equals("LLDate(const LLDate& date) constructor failed", date1.asString(), date2.asString()); + } + + template<> template<> + void date_test_object_t::test<5>() + { + LLDate date1(VALID_DATE); + LLDate date2(date1.secondsSinceEpoch()); + ensure_equals("secondsSinceEpoch not equal",date1.secondsSinceEpoch(), date2.secondsSinceEpoch()); + ensure_equals("LLDate created using secondsSinceEpoch not equal", date1.asString(), date2.asString()); + } + + template<> template<> + void date_test_object_t::test<6>() + { + LLDate date(VALID_DATE); + std::ostringstream stream; + stream << date; + std::string expected_str = VALID_DATE; + ensure_equals("ostringstream failed", expected_str, stream.str()); + } + + template<> template<> + void date_test_object_t::test<7>() + { + LLDate date; + std::istringstream stream(VALID_DATE); + stream >> date; + std::string expected_str = VALID_DATE; + std::ostringstream out_stream; out_stream << date; - ensure_equals("<< failed", date.asString(),expected_str); - ensure_equals("<< to >> failed", stream.str(),out_stream.str()); - } + ensure_equals("<< failed", date.asString(),expected_str); + ensure_equals("<< to >> failed", stream.str(),out_stream.str()); + } } diff --git a/indra/llcommon/tests/lldeadmantimer_test.cpp b/indra/llcommon/tests/lldeadmantimer_test.cpp index 23167762c3..01e6e8e2f7 100644 --- a/indra/llcommon/tests/lldeadmantimer_test.cpp +++ b/indra/llcommon/tests/lldeadmantimer_test.cpp @@ -1,25 +1,25 @@ -/** +/** * @file lldeadmantimer_test.cpp * @brief Tests for the LLDeadmanTimer class. * * $LicenseInfo:firstyear=2013&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2013, 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$ */ @@ -37,12 +37,12 @@ static LLDeadmanTimer::time_type float_time_to_u64(F64 delta) { - return LLDeadmanTimer::time_type(delta * get_timer_info().mClockFrequency); + return LLDeadmanTimer::time_type(delta * get_timer_info().mClockFrequency); } static F64 u64_time_to_float(LLDeadmanTimer::time_type delta) { - return delta * get_timer_info().mClockFrequencyInv; + return delta * get_timer_info().mClockFrequencyInv; } @@ -51,11 +51,11 @@ namespace tut struct deadmantimer_test { - deadmantimer_test() - { - // LLTimer internals updating - get_timer_info().update(); - } + deadmantimer_test() + { + // LLTimer internals updating + get_timer_info().update(); + } }; typedef test_group deadmantimer_group_t; @@ -66,31 +66,31 @@ tut::deadmantimer_group_t deadmantimer_instance("LLDeadmanTimer"); template<> template<> void deadmantimer_object_t::test<1>() { - { - // Without cpu metrics - F64 started(42.0), stopped(97.0); - U64 count(U64L(8)); - LLDeadmanTimer timer(10.0, false); - - ensure_equals("WOCM isExpired() returns false after ctor()", timer.isExpired(0, started, stopped, count), false); - ensure_approximately_equals("WOCM t1 - isExpired() does not modify started", started, F64(42.0), 2); - ensure_approximately_equals("WOCM t1 - isExpired() does not modify stopped", stopped, F64(97.0), 2); - ensure_equals("WOCM t1 - isExpired() does not modify count", count, U64L(8)); - } - - { - // With cpu metrics - F64 started(42.0), stopped(97.0); - U64 count(U64L(8)), user_cpu(29000), sys_cpu(57000); - LLDeadmanTimer timer(10.0, true); - - ensure_equals("WCM isExpired() returns false after ctor()", timer.isExpired(0, started, stopped, count, user_cpu, sys_cpu), false); - ensure_approximately_equals("WCM t1 - isExpired() does not modify started", started, F64(42.0), 2); - ensure_approximately_equals("WCM t1 - isExpired() does not modify stopped", stopped, F64(97.0), 2); - ensure_equals("WCM t1 - isExpired() does not modify count", count, U64L(8)); - ensure_equals("WCM t1 - isExpired() does not modify user_cpu", user_cpu, U64L(29000)); - ensure_equals("WCM t1 - isExpired() does not modify sys_cpu", sys_cpu, U64L(57000)); - } + { + // Without cpu metrics + F64 started(42.0), stopped(97.0); + U64 count(U64L(8)); + LLDeadmanTimer timer(10.0, false); + + ensure_equals("WOCM isExpired() returns false after ctor()", timer.isExpired(0, started, stopped, count), false); + ensure_approximately_equals("WOCM t1 - isExpired() does not modify started", started, F64(42.0), 2); + ensure_approximately_equals("WOCM t1 - isExpired() does not modify stopped", stopped, F64(97.0), 2); + ensure_equals("WOCM t1 - isExpired() does not modify count", count, U64L(8)); + } + + { + // With cpu metrics + F64 started(42.0), stopped(97.0); + U64 count(U64L(8)), user_cpu(29000), sys_cpu(57000); + LLDeadmanTimer timer(10.0, true); + + ensure_equals("WCM isExpired() returns false after ctor()", timer.isExpired(0, started, stopped, count, user_cpu, sys_cpu), false); + ensure_approximately_equals("WCM t1 - isExpired() does not modify started", started, F64(42.0), 2); + ensure_approximately_equals("WCM t1 - isExpired() does not modify stopped", stopped, F64(97.0), 2); + ensure_equals("WCM t1 - isExpired() does not modify count", count, U64L(8)); + ensure_equals("WCM t1 - isExpired() does not modify user_cpu", user_cpu, U64L(29000)); + ensure_equals("WCM t1 - isExpired() does not modify sys_cpu", sys_cpu, U64L(57000)); + } } @@ -98,25 +98,25 @@ void deadmantimer_object_t::test<1>() template<> template<> void deadmantimer_object_t::test<2>() { - { - // Without cpu metrics - F64 started(42.0), stopped(97.0); - U64 count(U64L(8)); - LLDeadmanTimer timer(0.0, false); // Zero is pre-expired - - ensure_equals("WOCM isExpired() still returns false with 0.0 time ctor()", - timer.isExpired(0, started, stopped, count), false); - } - - { - // With cpu metrics - F64 started(42.0), stopped(97.0); - U64 count(U64L(8)), user_cpu(29000), sys_cpu(57000); - LLDeadmanTimer timer(0.0, true); // Zero is pre-expired - - ensure_equals("WCM isExpired() still returns false with 0.0 time ctor()", - timer.isExpired(0, started, stopped, count, user_cpu, sys_cpu), false); - } + { + // Without cpu metrics + F64 started(42.0), stopped(97.0); + U64 count(U64L(8)); + LLDeadmanTimer timer(0.0, false); // Zero is pre-expired + + ensure_equals("WOCM isExpired() still returns false with 0.0 time ctor()", + timer.isExpired(0, started, stopped, count), false); + } + + { + // With cpu metrics + F64 started(42.0), stopped(97.0); + U64 count(U64L(8)), user_cpu(29000), sys_cpu(57000); + LLDeadmanTimer timer(0.0, true); // Zero is pre-expired + + ensure_equals("WCM isExpired() still returns false with 0.0 time ctor()", + timer.isExpired(0, started, stopped, count, user_cpu, sys_cpu), false); + } } @@ -125,28 +125,28 @@ void deadmantimer_object_t::test<2>() template<> template<> void deadmantimer_object_t::test<3>() { - { - // Without cpu metrics - F64 started(42.0), stopped(97.0); - U64 count(U64L(8)); - LLDeadmanTimer timer(0.0, false); - - timer.start(0); - ensure_equals("WOCM isExpired() returns true with 0.0 horizon time", - timer.isExpired(0, started, stopped, count), true); - ensure_approximately_equals("WOCM expired timer with no bell ringing has stopped == started", started, stopped, 8); - } - { - // With cpu metrics - F64 started(42.0), stopped(97.0); - U64 count(U64L(8)), user_cpu(29000), sys_cpu(57000); - LLDeadmanTimer timer(0.0, true); - - timer.start(0); - ensure_equals("WCM isExpired() returns true with 0.0 horizon time", - timer.isExpired(0, started, stopped, count, user_cpu, sys_cpu), true); - ensure_approximately_equals("WCM expired timer with no bell ringing has stopped == started", started, stopped, 8); - } + { + // Without cpu metrics + F64 started(42.0), stopped(97.0); + U64 count(U64L(8)); + LLDeadmanTimer timer(0.0, false); + + timer.start(0); + ensure_equals("WOCM isExpired() returns true with 0.0 horizon time", + timer.isExpired(0, started, stopped, count), true); + ensure_approximately_equals("WOCM expired timer with no bell ringing has stopped == started", started, stopped, 8); + } + { + // With cpu metrics + F64 started(42.0), stopped(97.0); + U64 count(U64L(8)), user_cpu(29000), sys_cpu(57000); + LLDeadmanTimer timer(0.0, true); + + timer.start(0); + ensure_equals("WCM isExpired() returns true with 0.0 horizon time", + timer.isExpired(0, started, stopped, count, user_cpu, sys_cpu), true); + ensure_approximately_equals("WCM expired timer with no bell ringing has stopped == started", started, stopped, 8); + } } @@ -154,30 +154,30 @@ void deadmantimer_object_t::test<3>() template<> template<> void deadmantimer_object_t::test<4>() { - { - // Without cpu metrics - F64 started(42.0), stopped(97.0); - U64 count(U64L(8)); - LLDeadmanTimer timer(0.0, false); - - timer.start(0); - timer.ringBell(LLDeadmanTimer::getNow() + float_time_to_u64(1000.0), 1); - ensure_equals("WOCM isExpired() returns true with 0.0 horizon time after bell ring", - timer.isExpired(0, started, stopped, count), true); - ensure_approximately_equals("WOCM ringBell has no impact on expired timer leaving stopped == started", started, stopped, 8); - } - { - // With cpu metrics - F64 started(42.0), stopped(97.0); - U64 count(U64L(8)), user_cpu(29000), sys_cpu(57000); - LLDeadmanTimer timer(0.0, true); - - timer.start(0); - timer.ringBell(LLDeadmanTimer::getNow() + float_time_to_u64(1000.0), 1); - ensure_equals("WCM isExpired() returns true with 0.0 horizon time after bell ring", - timer.isExpired(0, started, stopped, count, user_cpu, sys_cpu), true); - ensure_approximately_equals("WCM ringBell has no impact on expired timer leaving stopped == started", started, stopped, 8); - } + { + // Without cpu metrics + F64 started(42.0), stopped(97.0); + U64 count(U64L(8)); + LLDeadmanTimer timer(0.0, false); + + timer.start(0); + timer.ringBell(LLDeadmanTimer::getNow() + float_time_to_u64(1000.0), 1); + ensure_equals("WOCM isExpired() returns true with 0.0 horizon time after bell ring", + timer.isExpired(0, started, stopped, count), true); + ensure_approximately_equals("WOCM ringBell has no impact on expired timer leaving stopped == started", started, stopped, 8); + } + { + // With cpu metrics + F64 started(42.0), stopped(97.0); + U64 count(U64L(8)), user_cpu(29000), sys_cpu(57000); + LLDeadmanTimer timer(0.0, true); + + timer.start(0); + timer.ringBell(LLDeadmanTimer::getNow() + float_time_to_u64(1000.0), 1); + ensure_equals("WCM isExpired() returns true with 0.0 horizon time after bell ring", + timer.isExpired(0, started, stopped, count, user_cpu, sys_cpu), true); + ensure_approximately_equals("WCM ringBell has no impact on expired timer leaving stopped == started", started, stopped, 8); + } } @@ -185,34 +185,34 @@ void deadmantimer_object_t::test<4>() template<> template<> void deadmantimer_object_t::test<5>() { - { - // Without cpu metrics - F64 started(42.0), stopped(97.0); - U64 count(U64L(8)); - LLDeadmanTimer timer(10.0, false); - - timer.start(0); - ensure_equals("WOCM isExpired() returns false after starting with 10.0 horizon time", - timer.isExpired(0, started, stopped, count), false); - ensure_approximately_equals("WOCM t5 - isExpired() does not modify started", started, F64(42.0), 2); - ensure_approximately_equals("WOCM t5 - isExpired() does not modify stopped", stopped, F64(97.0), 2); - ensure_equals("WOCM t5 - isExpired() does not modify count", count, U64L(8)); - } - { - // With cpu metrics - F64 started(42.0), stopped(97.0); - U64 count(U64L(8)), user_cpu(29000), sys_cpu(57000); - LLDeadmanTimer timer(10.0, true); - - timer.start(0); - ensure_equals("WCM isExpired() returns false after starting with 10.0 horizon time", - timer.isExpired(0, started, stopped, count, user_cpu, sys_cpu), false); - ensure_approximately_equals("WCM t5 - isExpired() does not modify started", started, F64(42.0), 2); - ensure_approximately_equals("WCM t5 - isExpired() does not modify stopped", stopped, F64(97.0), 2); - ensure_equals("WCM t5 - isExpired() does not modify count", count, U64L(8)); - ensure_equals("WCM t5 - isExpired() does not modify user_cpu", user_cpu, U64L(29000)); - ensure_equals("WCM t5 - isExpired() does not modify sys_cpu", sys_cpu, U64L(57000)); - } + { + // Without cpu metrics + F64 started(42.0), stopped(97.0); + U64 count(U64L(8)); + LLDeadmanTimer timer(10.0, false); + + timer.start(0); + ensure_equals("WOCM isExpired() returns false after starting with 10.0 horizon time", + timer.isExpired(0, started, stopped, count), false); + ensure_approximately_equals("WOCM t5 - isExpired() does not modify started", started, F64(42.0), 2); + ensure_approximately_equals("WOCM t5 - isExpired() does not modify stopped", stopped, F64(97.0), 2); + ensure_equals("WOCM t5 - isExpired() does not modify count", count, U64L(8)); + } + { + // With cpu metrics + F64 started(42.0), stopped(97.0); + U64 count(U64L(8)), user_cpu(29000), sys_cpu(57000); + LLDeadmanTimer timer(10.0, true); + + timer.start(0); + ensure_equals("WCM isExpired() returns false after starting with 10.0 horizon time", + timer.isExpired(0, started, stopped, count, user_cpu, sys_cpu), false); + ensure_approximately_equals("WCM t5 - isExpired() does not modify started", started, F64(42.0), 2); + ensure_approximately_equals("WCM t5 - isExpired() does not modify stopped", stopped, F64(97.0), 2); + ensure_equals("WCM t5 - isExpired() does not modify count", count, U64L(8)); + ensure_equals("WCM t5 - isExpired() does not modify user_cpu", user_cpu, U64L(29000)); + ensure_equals("WCM t5 - isExpired() does not modify sys_cpu", sys_cpu, U64L(57000)); + } } @@ -220,46 +220,46 @@ void deadmantimer_object_t::test<5>() template<> template<> void deadmantimer_object_t::test<6>() { - { - // Without cpu metrics - F64 started(42.0), stopped(97.0); - U64 count(U64L(8)); - LLDeadmanTimer timer(10.0, false); - - // Would like to do subtraction on current time but can't because - // the implementation on Windows is zero-based. We wrap around - // the backside resulting in a large U64 number. - - LLDeadmanTimer::time_type the_past(LLDeadmanTimer::getNow()); - LLDeadmanTimer::time_type now(the_past + float_time_to_u64(5.0)); - timer.start(the_past); - ensure_equals("WOCM t6 - isExpired() returns false with 10.0 horizon time starting 5.0 in past", - timer.isExpired(now, started, stopped, count), false); - ensure_approximately_equals("WOCM t6 - isExpired() does not modify started", started, F64(42.0), 2); - ensure_approximately_equals("WOCM t6 - isExpired() does not modify stopped", stopped, F64(97.0), 2); - ensure_equals("WOCM t6 - isExpired() does not modify count", count, U64L(8)); - } - { - // With cpu metrics - F64 started(42.0), stopped(97.0); - U64 count(U64L(8)), user_cpu(29000), sys_cpu(57000); - LLDeadmanTimer timer(10.0, true); - - // Would like to do subtraction on current time but can't because - // the implementation on Windows is zero-based. We wrap around - // the backside resulting in a large U64 number. - - LLDeadmanTimer::time_type the_past(LLDeadmanTimer::getNow()); - LLDeadmanTimer::time_type now(the_past + float_time_to_u64(5.0)); - timer.start(the_past); - ensure_equals("WCM t6 - isExpired() returns false with 10.0 horizon time starting 5.0 in past", - timer.isExpired(now, started, stopped, count, user_cpu, sys_cpu), false); - ensure_approximately_equals("WCM t6 - isExpired() does not modify started", started, F64(42.0), 2); - ensure_approximately_equals("WCM t6 - isExpired() does not modify stopped", stopped, F64(97.0), 2); - ensure_equals("t6 - isExpired() does not modify count", count, U64L(8)); - ensure_equals("WCM t6 - isExpired() does not modify user_cpu", user_cpu, U64L(29000)); - ensure_equals("WCM t6 - isExpired() does not modify sys_cpu", sys_cpu, U64L(57000)); - } + { + // Without cpu metrics + F64 started(42.0), stopped(97.0); + U64 count(U64L(8)); + LLDeadmanTimer timer(10.0, false); + + // Would like to do subtraction on current time but can't because + // the implementation on Windows is zero-based. We wrap around + // the backside resulting in a large U64 number. + + LLDeadmanTimer::time_type the_past(LLDeadmanTimer::getNow()); + LLDeadmanTimer::time_type now(the_past + float_time_to_u64(5.0)); + timer.start(the_past); + ensure_equals("WOCM t6 - isExpired() returns false with 10.0 horizon time starting 5.0 in past", + timer.isExpired(now, started, stopped, count), false); + ensure_approximately_equals("WOCM t6 - isExpired() does not modify started", started, F64(42.0), 2); + ensure_approximately_equals("WOCM t6 - isExpired() does not modify stopped", stopped, F64(97.0), 2); + ensure_equals("WOCM t6 - isExpired() does not modify count", count, U64L(8)); + } + { + // With cpu metrics + F64 started(42.0), stopped(97.0); + U64 count(U64L(8)), user_cpu(29000), sys_cpu(57000); + LLDeadmanTimer timer(10.0, true); + + // Would like to do subtraction on current time but can't because + // the implementation on Windows is zero-based. We wrap around + // the backside resulting in a large U64 number. + + LLDeadmanTimer::time_type the_past(LLDeadmanTimer::getNow()); + LLDeadmanTimer::time_type now(the_past + float_time_to_u64(5.0)); + timer.start(the_past); + ensure_equals("WCM t6 - isExpired() returns false with 10.0 horizon time starting 5.0 in past", + timer.isExpired(now, started, stopped, count, user_cpu, sys_cpu), false); + ensure_approximately_equals("WCM t6 - isExpired() does not modify started", started, F64(42.0), 2); + ensure_approximately_equals("WCM t6 - isExpired() does not modify stopped", stopped, F64(97.0), 2); + ensure_equals("t6 - isExpired() does not modify count", count, U64L(8)); + ensure_equals("WCM t6 - isExpired() does not modify user_cpu", user_cpu, U64L(29000)); + ensure_equals("WCM t6 - isExpired() does not modify sys_cpu", sys_cpu, U64L(57000)); + } } @@ -267,40 +267,40 @@ void deadmantimer_object_t::test<6>() template<> template<> void deadmantimer_object_t::test<7>() { - { - // Without cpu metrics - F64 started(42.0), stopped(97.0); - U64 count(U64L(8)); - LLDeadmanTimer timer(10.0, false); - - // Would like to do subtraction on current time but can't because - // the implementation on Windows is zero-based. We wrap around - // the backside resulting in a large U64 number. - - LLDeadmanTimer::time_type the_past(LLDeadmanTimer::getNow()); - LLDeadmanTimer::time_type now(the_past + float_time_to_u64(20.0)); - timer.start(the_past); - ensure_equals("WOCM t7 - isExpired() returns true with 10.0 horizon time starting 20.0 in past", - timer.isExpired(now,started, stopped, count), true); - ensure_approximately_equals("WOCM t7 - starting before horizon still gives equal started / stopped", started, stopped, 8); - } - { - // With cpu metrics - F64 started(42.0), stopped(97.0); - U64 count(U64L(8)), user_cpu(29000), sys_cpu(57000); - LLDeadmanTimer timer(10.0, true); - - // Would like to do subtraction on current time but can't because - // the implementation on Windows is zero-based. We wrap around - // the backside resulting in a large U64 number. - - LLDeadmanTimer::time_type the_past(LLDeadmanTimer::getNow()); - LLDeadmanTimer::time_type now(the_past + float_time_to_u64(20.0)); - timer.start(the_past); - ensure_equals("WCM t7 - isExpired() returns true with 10.0 horizon time starting 20.0 in past", - timer.isExpired(now,started, stopped, count, user_cpu, sys_cpu), true); - ensure_approximately_equals("WOCM t7 - starting before horizon still gives equal started / stopped", started, stopped, 8); - } + { + // Without cpu metrics + F64 started(42.0), stopped(97.0); + U64 count(U64L(8)); + LLDeadmanTimer timer(10.0, false); + + // Would like to do subtraction on current time but can't because + // the implementation on Windows is zero-based. We wrap around + // the backside resulting in a large U64 number. + + LLDeadmanTimer::time_type the_past(LLDeadmanTimer::getNow()); + LLDeadmanTimer::time_type now(the_past + float_time_to_u64(20.0)); + timer.start(the_past); + ensure_equals("WOCM t7 - isExpired() returns true with 10.0 horizon time starting 20.0 in past", + timer.isExpired(now,started, stopped, count), true); + ensure_approximately_equals("WOCM t7 - starting before horizon still gives equal started / stopped", started, stopped, 8); + } + { + // With cpu metrics + F64 started(42.0), stopped(97.0); + U64 count(U64L(8)), user_cpu(29000), sys_cpu(57000); + LLDeadmanTimer timer(10.0, true); + + // Would like to do subtraction on current time but can't because + // the implementation on Windows is zero-based. We wrap around + // the backside resulting in a large U64 number. + + LLDeadmanTimer::time_type the_past(LLDeadmanTimer::getNow()); + LLDeadmanTimer::time_type now(the_past + float_time_to_u64(20.0)); + timer.start(the_past); + ensure_equals("WCM t7 - isExpired() returns true with 10.0 horizon time starting 20.0 in past", + timer.isExpired(now,started, stopped, count, user_cpu, sys_cpu), true); + ensure_approximately_equals("WOCM t7 - starting before horizon still gives equal started / stopped", started, stopped, 8); + } } @@ -308,60 +308,60 @@ void deadmantimer_object_t::test<7>() template<> template<> void deadmantimer_object_t::test<8>() { - { - // Without cpu metrics - F64 started(42.0), stopped(97.0); - U64 count(U64L(8)); - LLDeadmanTimer timer(10.0, false); - - // Would like to do subtraction on current time but can't because - // the implementation on Windows is zero-based. We wrap around - // the backside resulting in a large U64 number. - - LLDeadmanTimer::time_type the_past(LLDeadmanTimer::getNow()); - LLDeadmanTimer::time_type now(the_past + float_time_to_u64(20.0)); - timer.start(the_past); - ensure_equals("WOCM t8 - isExpired() returns true with 10.0 horizon time starting 20.0 in past", - timer.isExpired(now, started, stopped, count), true); - - started = 42.0; - stopped = 97.0; - count = U64L(8); - ensure_equals("WOCM t8 - second isExpired() returns false after true", - timer.isExpired(now, started, stopped, count), false); - ensure_approximately_equals("WOCM t8 - 2nd isExpired() does not modify started", started, F64(42.0), 2); - ensure_approximately_equals("WOCM t8 - 2nd isExpired() does not modify stopped", stopped, F64(97.0), 2); - ensure_equals("WOCM t8 - 2nd isExpired() does not modify count", count, U64L(8)); - } - { - // With cpu metrics - F64 started(42.0), stopped(97.0); - U64 count(U64L(8)), user_cpu(29000), sys_cpu(57000); - LLDeadmanTimer timer(10.0, true); - - // Would like to do subtraction on current time but can't because - // the implementation on Windows is zero-based. We wrap around - // the backside resulting in a large U64 number. - - LLDeadmanTimer::time_type the_past(LLDeadmanTimer::getNow()); - LLDeadmanTimer::time_type now(the_past + float_time_to_u64(20.0)); - timer.start(the_past); - ensure_equals("WCM t8 - isExpired() returns true with 10.0 horizon time starting 20.0 in past", - timer.isExpired(now, started, stopped, count, user_cpu, sys_cpu), true); - - started = 42.0; - stopped = 97.0; - count = U64L(8); - user_cpu = 29000; - sys_cpu = 57000; - ensure_equals("WCM t8 - second isExpired() returns false after true", - timer.isExpired(now, started, stopped, count), false); - ensure_approximately_equals("WCM t8 - 2nd isExpired() does not modify started", started, F64(42.0), 2); - ensure_approximately_equals("WCM t8 - 2nd isExpired() does not modify stopped", stopped, F64(97.0), 2); - ensure_equals("WCM t8 - 2nd isExpired() does not modify count", count, U64L(8)); - ensure_equals("WCM t8 - 2nd isExpired() does not modify user_cpu", user_cpu, U64L(29000)); - ensure_equals("WCM t8 - 2nd isExpired() does not modify sys_cpu", sys_cpu, U64L(57000)); - } + { + // Without cpu metrics + F64 started(42.0), stopped(97.0); + U64 count(U64L(8)); + LLDeadmanTimer timer(10.0, false); + + // Would like to do subtraction on current time but can't because + // the implementation on Windows is zero-based. We wrap around + // the backside resulting in a large U64 number. + + LLDeadmanTimer::time_type the_past(LLDeadmanTimer::getNow()); + LLDeadmanTimer::time_type now(the_past + float_time_to_u64(20.0)); + timer.start(the_past); + ensure_equals("WOCM t8 - isExpired() returns true with 10.0 horizon time starting 20.0 in past", + timer.isExpired(now, started, stopped, count), true); + + started = 42.0; + stopped = 97.0; + count = U64L(8); + ensure_equals("WOCM t8 - second isExpired() returns false after true", + timer.isExpired(now, started, stopped, count), false); + ensure_approximately_equals("WOCM t8 - 2nd isExpired() does not modify started", started, F64(42.0), 2); + ensure_approximately_equals("WOCM t8 - 2nd isExpired() does not modify stopped", stopped, F64(97.0), 2); + ensure_equals("WOCM t8 - 2nd isExpired() does not modify count", count, U64L(8)); + } + { + // With cpu metrics + F64 started(42.0), stopped(97.0); + U64 count(U64L(8)), user_cpu(29000), sys_cpu(57000); + LLDeadmanTimer timer(10.0, true); + + // Would like to do subtraction on current time but can't because + // the implementation on Windows is zero-based. We wrap around + // the backside resulting in a large U64 number. + + LLDeadmanTimer::time_type the_past(LLDeadmanTimer::getNow()); + LLDeadmanTimer::time_type now(the_past + float_time_to_u64(20.0)); + timer.start(the_past); + ensure_equals("WCM t8 - isExpired() returns true with 10.0 horizon time starting 20.0 in past", + timer.isExpired(now, started, stopped, count, user_cpu, sys_cpu), true); + + started = 42.0; + stopped = 97.0; + count = U64L(8); + user_cpu = 29000; + sys_cpu = 57000; + ensure_equals("WCM t8 - second isExpired() returns false after true", + timer.isExpired(now, started, stopped, count), false); + ensure_approximately_equals("WCM t8 - 2nd isExpired() does not modify started", started, F64(42.0), 2); + ensure_approximately_equals("WCM t8 - 2nd isExpired() does not modify stopped", stopped, F64(97.0), 2); + ensure_equals("WCM t8 - 2nd isExpired() does not modify count", count, U64L(8)); + ensure_equals("WCM t8 - 2nd isExpired() does not modify user_cpu", user_cpu, U64L(29000)); + ensure_equals("WCM t8 - 2nd isExpired() does not modify sys_cpu", sys_cpu, U64L(57000)); + } } @@ -369,92 +369,92 @@ void deadmantimer_object_t::test<8>() template<> template<> void deadmantimer_object_t::test<9>() { - { - // Without cpu metrics - F64 started(42.0), stopped(97.0); - U64 count(U64L(8)); - LLDeadmanTimer timer(5.0, false); - - LLDeadmanTimer::time_type now(LLDeadmanTimer::getNow()); - F64 real_start(u64_time_to_float(now)); - timer.start(0); - - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - ensure_equals("WOCM t9 - 5.0 horizon timer has not timed out after 10 1-second bell rings", - timer.isExpired(now, started, stopped, count), false); - F64 last_good_ring(u64_time_to_float(now)); - - // Jump forward and expire - now += float_time_to_u64(10.0); - ensure_equals("WOCM t9 - 5.0 horizon timer expires on 10-second jump", - timer.isExpired(now, started, stopped, count), true); - ensure_approximately_equals("WOCM t9 - started matches start() time", started, real_start, 4); - ensure_approximately_equals("WOCM t9 - stopped matches last ringBell() time", stopped, last_good_ring, 4); - ensure_equals("WOCM t9 - 10 good ringBell()s", count, U64L(10)); - ensure_equals("WOCM t9 - single read only", timer.isExpired(now, started, stopped, count), false); - } - { - // With cpu metrics - F64 started(42.0), stopped(97.0); - U64 count(U64L(8)), user_cpu(29000), sys_cpu(57000); - LLDeadmanTimer timer(5.0, true); - - LLDeadmanTimer::time_type now(LLDeadmanTimer::getNow()); - F64 real_start(u64_time_to_float(now)); - timer.start(0); - - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - ensure_equals("WCM t9 - 5.0 horizon timer has not timed out after 10 1-second bell rings", - timer.isExpired(now, started, stopped, count, user_cpu, sys_cpu), false); - F64 last_good_ring(u64_time_to_float(now)); - - // Jump forward and expire - now += float_time_to_u64(10.0); - ensure_equals("WCM t9 - 5.0 horizon timer expires on 10-second jump", - timer.isExpired(now, started, stopped, count, user_cpu, sys_cpu), true); - ensure_approximately_equals("WCM t9 - started matches start() time", started, real_start, 4); - ensure_approximately_equals("WCM t9 - stopped matches last ringBell() time", stopped, last_good_ring, 4); - ensure_equals("WCM t9 - 10 good ringBell()s", count, U64L(10)); - ensure_equals("WCM t9 - single read only", timer.isExpired(now, started, stopped, count, user_cpu, sys_cpu), false); - } + { + // Without cpu metrics + F64 started(42.0), stopped(97.0); + U64 count(U64L(8)); + LLDeadmanTimer timer(5.0, false); + + LLDeadmanTimer::time_type now(LLDeadmanTimer::getNow()); + F64 real_start(u64_time_to_float(now)); + timer.start(0); + + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + ensure_equals("WOCM t9 - 5.0 horizon timer has not timed out after 10 1-second bell rings", + timer.isExpired(now, started, stopped, count), false); + F64 last_good_ring(u64_time_to_float(now)); + + // Jump forward and expire + now += float_time_to_u64(10.0); + ensure_equals("WOCM t9 - 5.0 horizon timer expires on 10-second jump", + timer.isExpired(now, started, stopped, count), true); + ensure_approximately_equals("WOCM t9 - started matches start() time", started, real_start, 4); + ensure_approximately_equals("WOCM t9 - stopped matches last ringBell() time", stopped, last_good_ring, 4); + ensure_equals("WOCM t9 - 10 good ringBell()s", count, U64L(10)); + ensure_equals("WOCM t9 - single read only", timer.isExpired(now, started, stopped, count), false); + } + { + // With cpu metrics + F64 started(42.0), stopped(97.0); + U64 count(U64L(8)), user_cpu(29000), sys_cpu(57000); + LLDeadmanTimer timer(5.0, true); + + LLDeadmanTimer::time_type now(LLDeadmanTimer::getNow()); + F64 real_start(u64_time_to_float(now)); + timer.start(0); + + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + ensure_equals("WCM t9 - 5.0 horizon timer has not timed out after 10 1-second bell rings", + timer.isExpired(now, started, stopped, count, user_cpu, sys_cpu), false); + F64 last_good_ring(u64_time_to_float(now)); + + // Jump forward and expire + now += float_time_to_u64(10.0); + ensure_equals("WCM t9 - 5.0 horizon timer expires on 10-second jump", + timer.isExpired(now, started, stopped, count, user_cpu, sys_cpu), true); + ensure_approximately_equals("WCM t9 - started matches start() time", started, real_start, 4); + ensure_approximately_equals("WCM t9 - stopped matches last ringBell() time", stopped, last_good_ring, 4); + ensure_equals("WCM t9 - 10 good ringBell()s", count, U64L(10)); + ensure_equals("WCM t9 - single read only", timer.isExpired(now, started, stopped, count, user_cpu, sys_cpu), false); + } } @@ -462,165 +462,165 @@ void deadmantimer_object_t::test<9>() template<> template<> void deadmantimer_object_t::test<10>() { - { - // Without cpu metrics - F64 started(42.0), stopped(97.0); - U64 count(U64L(8)); - LLDeadmanTimer timer(5.0, false); - - LLDeadmanTimer::time_type now(LLDeadmanTimer::getNow()); - F64 real_start(u64_time_to_float(now)); - timer.start(0); - - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - ensure_equals("WOCM t10 - 5.0 horizon timer has not timed out after 10 1-second bell rings", - timer.isExpired(now, started, stopped, count), false); - F64 last_good_ring(u64_time_to_float(now)); - - // Jump forward and expire - now += float_time_to_u64(10.0); - ensure_equals("WOCM t10 - 5.0 horizon timer expires on 10-second jump", - timer.isExpired(now, started, stopped, count), true); - ensure_approximately_equals("WOCM t10 - started matches start() time", started, real_start, 4); - ensure_approximately_equals("WOCM t10 - stopped matches last ringBell() time", stopped, last_good_ring, 4); - ensure_equals("WOCM t10 - 10 good ringBell()s", count, U64L(10)); - ensure_equals("WOCM t10 - single read only", timer.isExpired(now, started, stopped, count), false); - - // Jump forward and restart - now += float_time_to_u64(1.0); - real_start = u64_time_to_float(now); - timer.start(now); - - // Run a modified bell ring sequence - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - ensure_equals("WOCM t10 - 5.0 horizon timer has not timed out after 8 1-second bell rings", - timer.isExpired(now, started, stopped, count), false); - last_good_ring = u64_time_to_float(now); - - // Jump forward and expire - now += float_time_to_u64(10.0); - ensure_equals("WOCM t10 - 5.0 horizon timer expires on 8-second jump", - timer.isExpired(now, started, stopped, count), true); - ensure_approximately_equals("WOCM t10 - 2nd started matches start() time", started, real_start, 4); - ensure_approximately_equals("WOCM t10 - 2nd stopped matches last ringBell() time", stopped, last_good_ring, 4); - ensure_equals("WOCM t10 - 8 good ringBell()s", count, U64L(8)); - ensure_equals("WOCM t10 - single read only - 2nd start", - timer.isExpired(now, started, stopped, count), false); - } - { - // With cpu metrics - F64 started(42.0), stopped(97.0); - U64 count(U64L(8)), user_cpu(29000), sys_cpu(57000); - - LLDeadmanTimer timer(5.0, true); - - LLDeadmanTimer::time_type now(LLDeadmanTimer::getNow()); - F64 real_start(u64_time_to_float(now)); - timer.start(0); - - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - ensure_equals("WCM t10 - 5.0 horizon timer has not timed out after 10 1-second bell rings", - timer.isExpired(now, started, stopped, count, user_cpu, sys_cpu), false); - F64 last_good_ring(u64_time_to_float(now)); - - // Jump forward and expire - now += float_time_to_u64(10.0); - ensure_equals("WCM t10 - 5.0 horizon timer expires on 10-second jump", - timer.isExpired(now, started, stopped, count, user_cpu, sys_cpu), true); - ensure_approximately_equals("WCM t10 - started matches start() time", started, real_start, 4); - ensure_approximately_equals("WCM t10 - stopped matches last ringBell() time", stopped, last_good_ring, 4); - ensure_equals("WCM t10 - 10 good ringBell()s", count, U64L(10)); - ensure_equals("WCM t10 - single read only", timer.isExpired(now, started, stopped, count, user_cpu, sys_cpu), false); - - // Jump forward and restart - now += float_time_to_u64(1.0); - real_start = u64_time_to_float(now); - timer.start(now); - - // Run a modified bell ring sequence - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - now += float_time_to_u64(1.0); - timer.ringBell(now, 1); - ensure_equals("WCM t10 - 5.0 horizon timer has not timed out after 8 1-second bell rings", - timer.isExpired(now, started, stopped, count, user_cpu, sys_cpu), false); - last_good_ring = u64_time_to_float(now); - - // Jump forward and expire - now += float_time_to_u64(10.0); - ensure_equals("WCM t10 - 5.0 horizon timer expires on 8-second jump", - timer.isExpired(now, started, stopped, count, user_cpu, sys_cpu), true); - ensure_approximately_equals("WCM t10 - 2nd started matches start() time", started, real_start, 4); - ensure_approximately_equals("WCM t10 - 2nd stopped matches last ringBell() time", stopped, last_good_ring, 4); - ensure_equals("WCM t10 - 8 good ringBell()s", count, U64L(8)); - ensure_equals("WCM t10 - single read only - 2nd start", - timer.isExpired(now, started, stopped, count, user_cpu, sys_cpu), false); - } + { + // Without cpu metrics + F64 started(42.0), stopped(97.0); + U64 count(U64L(8)); + LLDeadmanTimer timer(5.0, false); + + LLDeadmanTimer::time_type now(LLDeadmanTimer::getNow()); + F64 real_start(u64_time_to_float(now)); + timer.start(0); + + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + ensure_equals("WOCM t10 - 5.0 horizon timer has not timed out after 10 1-second bell rings", + timer.isExpired(now, started, stopped, count), false); + F64 last_good_ring(u64_time_to_float(now)); + + // Jump forward and expire + now += float_time_to_u64(10.0); + ensure_equals("WOCM t10 - 5.0 horizon timer expires on 10-second jump", + timer.isExpired(now, started, stopped, count), true); + ensure_approximately_equals("WOCM t10 - started matches start() time", started, real_start, 4); + ensure_approximately_equals("WOCM t10 - stopped matches last ringBell() time", stopped, last_good_ring, 4); + ensure_equals("WOCM t10 - 10 good ringBell()s", count, U64L(10)); + ensure_equals("WOCM t10 - single read only", timer.isExpired(now, started, stopped, count), false); + + // Jump forward and restart + now += float_time_to_u64(1.0); + real_start = u64_time_to_float(now); + timer.start(now); + + // Run a modified bell ring sequence + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + ensure_equals("WOCM t10 - 5.0 horizon timer has not timed out after 8 1-second bell rings", + timer.isExpired(now, started, stopped, count), false); + last_good_ring = u64_time_to_float(now); + + // Jump forward and expire + now += float_time_to_u64(10.0); + ensure_equals("WOCM t10 - 5.0 horizon timer expires on 8-second jump", + timer.isExpired(now, started, stopped, count), true); + ensure_approximately_equals("WOCM t10 - 2nd started matches start() time", started, real_start, 4); + ensure_approximately_equals("WOCM t10 - 2nd stopped matches last ringBell() time", stopped, last_good_ring, 4); + ensure_equals("WOCM t10 - 8 good ringBell()s", count, U64L(8)); + ensure_equals("WOCM t10 - single read only - 2nd start", + timer.isExpired(now, started, stopped, count), false); + } + { + // With cpu metrics + F64 started(42.0), stopped(97.0); + U64 count(U64L(8)), user_cpu(29000), sys_cpu(57000); + + LLDeadmanTimer timer(5.0, true); + + LLDeadmanTimer::time_type now(LLDeadmanTimer::getNow()); + F64 real_start(u64_time_to_float(now)); + timer.start(0); + + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + ensure_equals("WCM t10 - 5.0 horizon timer has not timed out after 10 1-second bell rings", + timer.isExpired(now, started, stopped, count, user_cpu, sys_cpu), false); + F64 last_good_ring(u64_time_to_float(now)); + + // Jump forward and expire + now += float_time_to_u64(10.0); + ensure_equals("WCM t10 - 5.0 horizon timer expires on 10-second jump", + timer.isExpired(now, started, stopped, count, user_cpu, sys_cpu), true); + ensure_approximately_equals("WCM t10 - started matches start() time", started, real_start, 4); + ensure_approximately_equals("WCM t10 - stopped matches last ringBell() time", stopped, last_good_ring, 4); + ensure_equals("WCM t10 - 10 good ringBell()s", count, U64L(10)); + ensure_equals("WCM t10 - single read only", timer.isExpired(now, started, stopped, count, user_cpu, sys_cpu), false); + + // Jump forward and restart + now += float_time_to_u64(1.0); + real_start = u64_time_to_float(now); + timer.start(now); + + // Run a modified bell ring sequence + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + now += float_time_to_u64(1.0); + timer.ringBell(now, 1); + ensure_equals("WCM t10 - 5.0 horizon timer has not timed out after 8 1-second bell rings", + timer.isExpired(now, started, stopped, count, user_cpu, sys_cpu), false); + last_good_ring = u64_time_to_float(now); + + // Jump forward and expire + now += float_time_to_u64(10.0); + ensure_equals("WCM t10 - 5.0 horizon timer expires on 8-second jump", + timer.isExpired(now, started, stopped, count, user_cpu, sys_cpu), true); + ensure_approximately_equals("WCM t10 - 2nd started matches start() time", started, real_start, 4); + ensure_approximately_equals("WCM t10 - 2nd stopped matches last ringBell() time", stopped, last_good_ring, 4); + ensure_equals("WCM t10 - 8 good ringBell()s", count, U64L(8)); + ensure_equals("WCM t10 - single read only - 2nd start", + timer.isExpired(now, started, stopped, count, user_cpu, sys_cpu), false); + } } diff --git a/indra/llcommon/tests/lldependencies_test.cpp b/indra/llcommon/tests/lldependencies_test.cpp index b5e189a465..84eb41b5fe 100644 --- a/indra/llcommon/tests/lldependencies_test.cpp +++ b/indra/llcommon/tests/lldependencies_test.cpp @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2008-09-17 * @brief Test of lldependencies.h - * + * * $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$ */ diff --git a/indra/llcommon/tests/llerror_test.cpp b/indra/llcommon/tests/llerror_test.cpp index b4cdbdc6bf..3ec429530c 100644 --- a/indra/llcommon/tests/llerror_test.cpp +++ b/indra/llcommon/tests/llerror_test.cpp @@ -47,7 +47,7 @@ enum LogFieldIndex MSG_FIELD }; -static const char* FieldName[] = +static const char* FieldName[] = { "TIME", "LEVEL", @@ -62,15 +62,15 @@ namespace #ifdef __clang__ # pragma clang diagnostic ignored "-Wunused-function" #endif - void test_that_error_h_includes_enough_things_to_compile_a_message() - { - LL_INFOS() << "!" << LL_ENDL; - } + void test_that_error_h_includes_enough_things_to_compile_a_message() + { + LL_INFOS() << "!" << LL_ENDL; + } } namespace { - static bool fatalWasCalled = false; + static bool fatalWasCalled = false; struct FatalWasCalled: public std::runtime_error { FatalWasCalled(const std::string& what): std::runtime_error(what) {} @@ -96,95 +96,95 @@ namespace namespace tut { - class TestRecorder : public LLError::Recorder - { - public: - TestRecorder() - { - showTime(false); - } - virtual ~TestRecorder() - {} - - virtual void recordMessage(LLError::ELevel level, - const std::string& message) - { - mMessages.push_back(message); - } - - int countMessages() { return (int) mMessages.size(); } - void clearMessages() { mMessages.clear(); } - - std::string message(int n) - { - std::ostringstream test_name; - test_name << "testing message " << n << ", not enough messages"; - - tut::ensure(test_name.str(), n < countMessages()); - return mMessages[n]; - } - - private: - typedef std::vector MessageVector; - MessageVector mMessages; - }; - - struct ErrorTestData - { - LLError::RecorderPtr mRecorder; - LLError::SettingsStoragePtr mPriorErrorSettings; - - ErrorTestData(): - mRecorder(new TestRecorder()) - { - fatalWasCalled = false; - - mPriorErrorSettings = LLError::saveAndResetSettings(); - LLError::setDefaultLevel(LLError::LEVEL_DEBUG); - LLError::setFatalFunction(fatalCall); - LLError::addRecorder(mRecorder); - } - - ~ErrorTestData() - { - LLError::removeRecorder(mRecorder); - LLError::restoreSettings(mPriorErrorSettings); - } - - int countMessages() - { - return std::dynamic_pointer_cast(mRecorder)->countMessages(); - } - - void clearMessages() - { - std::dynamic_pointer_cast(mRecorder)->clearMessages(); - } - - void setWantsTime(bool t) + class TestRecorder : public LLError::Recorder + { + public: + TestRecorder() + { + showTime(false); + } + virtual ~TestRecorder() + {} + + virtual void recordMessage(LLError::ELevel level, + const std::string& message) + { + mMessages.push_back(message); + } + + int countMessages() { return (int) mMessages.size(); } + void clearMessages() { mMessages.clear(); } + + std::string message(int n) + { + std::ostringstream test_name; + test_name << "testing message " << n << ", not enough messages"; + + tut::ensure(test_name.str(), n < countMessages()); + return mMessages[n]; + } + + private: + typedef std::vector MessageVector; + MessageVector mMessages; + }; + + struct ErrorTestData + { + LLError::RecorderPtr mRecorder; + LLError::SettingsStoragePtr mPriorErrorSettings; + + ErrorTestData(): + mRecorder(new TestRecorder()) + { + fatalWasCalled = false; + + mPriorErrorSettings = LLError::saveAndResetSettings(); + LLError::setDefaultLevel(LLError::LEVEL_DEBUG); + LLError::setFatalFunction(fatalCall); + LLError::addRecorder(mRecorder); + } + + ~ErrorTestData() + { + LLError::removeRecorder(mRecorder); + LLError::restoreSettings(mPriorErrorSettings); + } + + int countMessages() + { + return std::dynamic_pointer_cast(mRecorder)->countMessages(); + } + + void clearMessages() + { + std::dynamic_pointer_cast(mRecorder)->clearMessages(); + } + + void setWantsTime(bool t) { std::dynamic_pointer_cast(mRecorder)->showTime(t); } - void setWantsMultiline(bool t) + void setWantsMultiline(bool t) { std::dynamic_pointer_cast(mRecorder)->showMultiline(t); } - std::string message(int n) - { - return std::dynamic_pointer_cast(mRecorder)->message(n); - } + std::string message(int n) + { + return std::dynamic_pointer_cast(mRecorder)->message(n); + } - void ensure_message_count(int expectedCount) - { - ensure_equals("message count", countMessages(), expectedCount); - } + void ensure_message_count(int expectedCount) + { + ensure_equals("message count", countMessages(), expectedCount); + } std::string message_field(int msgnum, LogFieldIndex fieldnum) { std::ostringstream test_name; - test_name << "testing message " << msgnum << ", not enough messages"; + test_name << "testing message " << msgnum << ", not enough messages"; tut::ensure(test_name.str(), msgnum < countMessages()); std::string msg(message(msgnum)); @@ -204,7 +204,7 @@ namespace tut on_field++; } // except function, which may have embedded spaces so ends with " : " - else if ( ( on_field == FUNCTION_FIELD ) + else if ( ( on_field == FUNCTION_FIELD ) && ( ':' == msg[scan+1] && ' ' == msg[scan+2] ) ) { @@ -220,9 +220,9 @@ namespace tut { fieldlen = msg.find(' ', start_field) - start_field; } - else if ( fieldnum == FUNCTION_FIELD ) + else if ( fieldnum == FUNCTION_FIELD ) { - fieldlen = msg.find(" : ", start_field) - start_field; + fieldlen = msg.find(" : ", start_field) - start_field; } else if ( MSG_FIELD == fieldnum ) // no delimiter, just everything to the end { @@ -231,8 +231,8 @@ namespace tut return msg.substr(start_field, fieldlen); } - - void ensure_message_field_equals(int msgnum, LogFieldIndex fieldnum, const std::string& expectedText) + + void ensure_message_field_equals(int msgnum, LogFieldIndex fieldnum, const std::string& expectedText) { std::ostringstream test_name; test_name << "testing message " << msgnum << " field " << FieldName[fieldnum] << "\n message: \"" << message(msgnum) << "\"\n "; @@ -240,105 +240,105 @@ namespace tut ensure_equals(test_name.str(), message_field(msgnum, fieldnum), expectedText); } - void ensure_message_does_not_contain(int n, const std::string& expectedText) - { - std::ostringstream test_name; - test_name << "testing message " << n; + void ensure_message_does_not_contain(int n, const std::string& expectedText) + { + std::ostringstream test_name; + test_name << "testing message " << n; - ensure_does_not_contain(test_name.str(), message(n), expectedText); - } - }; + ensure_does_not_contain(test_name.str(), message(n), expectedText); + } + }; - typedef test_group ErrorTestGroup; - typedef ErrorTestGroup::object ErrorTestObject; + typedef test_group ErrorTestGroup; + typedef ErrorTestGroup::object ErrorTestObject; - ErrorTestGroup errorTestGroup("error"); + ErrorTestGroup errorTestGroup("error"); - template<> template<> - void ErrorTestObject::test<1>() - // basic test of output - { - LL_INFOS() << "test" << LL_ENDL; - LL_INFOS() << "bob" << LL_ENDL; + template<> template<> + void ErrorTestObject::test<1>() + // basic test of output + { + LL_INFOS() << "test" << LL_ENDL; + LL_INFOS() << "bob" << LL_ENDL; - ensure_message_field_equals(0, MSG_FIELD, "test"); - ensure_message_field_equals(1, MSG_FIELD, "bob"); - } + ensure_message_field_equals(0, MSG_FIELD, "test"); + ensure_message_field_equals(1, MSG_FIELD, "bob"); + } } namespace { - void writeSome() - { - LL_DEBUGS("WriteTag","AnotherTag") << "one" << LL_ENDL; - LL_INFOS("WriteTag") << "two" << LL_ENDL; - LL_WARNS("WriteTag") << "three" << LL_ENDL; - CATCH(LL_ERRS("WriteTag"), "four"); - } + void writeSome() + { + LL_DEBUGS("WriteTag","AnotherTag") << "one" << LL_ENDL; + LL_INFOS("WriteTag") << "two" << LL_ENDL; + LL_WARNS("WriteTag") << "three" << LL_ENDL; + CATCH(LL_ERRS("WriteTag"), "four"); + } }; namespace tut { - template<> template<> - void ErrorTestObject::test<2>() - // messages are filtered based on default level - { - LLError::setDefaultLevel(LLError::LEVEL_DEBUG); - writeSome(); - ensure_message_field_equals(0, MSG_FIELD, "one"); - ensure_message_field_equals(0, LEVEL_FIELD, "DEBUG"); - ensure_message_field_equals(0, TAGS_FIELD, "#WriteTag#AnotherTag#"); - ensure_message_field_equals(1, MSG_FIELD, "two"); - ensure_message_field_equals(1, LEVEL_FIELD, "INFO"); - ensure_message_field_equals(1, TAGS_FIELD, "#WriteTag#"); - ensure_message_field_equals(2, MSG_FIELD, "three"); - ensure_message_field_equals(2, LEVEL_FIELD, "WARNING"); - ensure_message_field_equals(2, TAGS_FIELD, "#WriteTag#"); - ensure_message_field_equals(3, MSG_FIELD, "four"); - ensure_message_field_equals(3, LEVEL_FIELD, "ERROR"); - ensure_message_field_equals(3, TAGS_FIELD, "#WriteTag#"); - ensure_message_count(4); - - LLError::setDefaultLevel(LLError::LEVEL_INFO); - writeSome(); - ensure_message_field_equals(4, MSG_FIELD, "two"); - ensure_message_field_equals(5, MSG_FIELD, "three"); - ensure_message_field_equals(6, MSG_FIELD, "four"); - ensure_message_count(7); - - LLError::setDefaultLevel(LLError::LEVEL_WARN); - writeSome(); - ensure_message_field_equals(7, MSG_FIELD, "three"); - ensure_message_field_equals(8, MSG_FIELD, "four"); - ensure_message_count(9); - - LLError::setDefaultLevel(LLError::LEVEL_ERROR); - writeSome(); - ensure_message_field_equals(9, MSG_FIELD, "four"); - ensure_message_count(10); - - LLError::setDefaultLevel(LLError::LEVEL_NONE); - writeSome(); - ensure_message_count(10); - } - - template<> template<> - void ErrorTestObject::test<3>() - // error type string in output - { - writeSome(); - ensure_message_field_equals(0, LEVEL_FIELD, "DEBUG"); - ensure_message_field_equals(1, LEVEL_FIELD, "INFO"); - ensure_message_field_equals(2, LEVEL_FIELD, "WARNING"); - ensure_message_field_equals(3, LEVEL_FIELD, "ERROR"); - ensure_message_count(4); - } - - template<> template<> - void ErrorTestObject::test<4>() - // file abbreviation - { - std::string prev, abbreviateFile = __FILE__; + template<> template<> + void ErrorTestObject::test<2>() + // messages are filtered based on default level + { + LLError::setDefaultLevel(LLError::LEVEL_DEBUG); + writeSome(); + ensure_message_field_equals(0, MSG_FIELD, "one"); + ensure_message_field_equals(0, LEVEL_FIELD, "DEBUG"); + ensure_message_field_equals(0, TAGS_FIELD, "#WriteTag#AnotherTag#"); + ensure_message_field_equals(1, MSG_FIELD, "two"); + ensure_message_field_equals(1, LEVEL_FIELD, "INFO"); + ensure_message_field_equals(1, TAGS_FIELD, "#WriteTag#"); + ensure_message_field_equals(2, MSG_FIELD, "three"); + ensure_message_field_equals(2, LEVEL_FIELD, "WARNING"); + ensure_message_field_equals(2, TAGS_FIELD, "#WriteTag#"); + ensure_message_field_equals(3, MSG_FIELD, "four"); + ensure_message_field_equals(3, LEVEL_FIELD, "ERROR"); + ensure_message_field_equals(3, TAGS_FIELD, "#WriteTag#"); + ensure_message_count(4); + + LLError::setDefaultLevel(LLError::LEVEL_INFO); + writeSome(); + ensure_message_field_equals(4, MSG_FIELD, "two"); + ensure_message_field_equals(5, MSG_FIELD, "three"); + ensure_message_field_equals(6, MSG_FIELD, "four"); + ensure_message_count(7); + + LLError::setDefaultLevel(LLError::LEVEL_WARN); + writeSome(); + ensure_message_field_equals(7, MSG_FIELD, "three"); + ensure_message_field_equals(8, MSG_FIELD, "four"); + ensure_message_count(9); + + LLError::setDefaultLevel(LLError::LEVEL_ERROR); + writeSome(); + ensure_message_field_equals(9, MSG_FIELD, "four"); + ensure_message_count(10); + + LLError::setDefaultLevel(LLError::LEVEL_NONE); + writeSome(); + ensure_message_count(10); + } + + template<> template<> + void ErrorTestObject::test<3>() + // error type string in output + { + writeSome(); + ensure_message_field_equals(0, LEVEL_FIELD, "DEBUG"); + ensure_message_field_equals(1, LEVEL_FIELD, "INFO"); + ensure_message_field_equals(2, LEVEL_FIELD, "WARNING"); + ensure_message_field_equals(3, LEVEL_FIELD, "ERROR"); + ensure_message_count(4); + } + + template<> template<> + void ErrorTestObject::test<4>() + // file abbreviation + { + std::string prev, abbreviateFile = __FILE__; do { prev = abbreviateFile; @@ -354,169 +354,169 @@ namespace tut // argument unchanged, THEN check. } while (abbreviateFile != prev); - ensure_ends_with("file name abbreviation", - abbreviateFile, - "llcommon/tests/llerror_test.cpp" - ); - ensure_does_not_contain("file name abbreviation", - abbreviateFile, "indra"); + ensure_ends_with("file name abbreviation", + abbreviateFile, + "llcommon/tests/llerror_test.cpp" + ); + ensure_does_not_contain("file name abbreviation", + abbreviateFile, "indra"); - std::string someFile = + std::string someFile = #if LL_WINDOWS - "C:/amy/bob/cam.cpp" + "C:/amy/bob/cam.cpp" #else - "/amy/bob/cam.cpp" + "/amy/bob/cam.cpp" #endif - ; - std::string someAbbreviation = LLError::abbreviateFile(someFile); + ; + std::string someAbbreviation = LLError::abbreviateFile(someFile); - ensure_equals("non-indra file abbreviation", - someAbbreviation, someFile); - } + ensure_equals("non-indra file abbreviation", + someAbbreviation, someFile); + } } namespace { - std::string locationString(int line) - { - std::ostringstream location; - location << LLError::abbreviateFile(__FILE__) - << "(" << line << ")"; - - return location.str(); - } - - std::string writeReturningLocation() - { - LL_INFOS() << "apple" << LL_ENDL; int this_line = __LINE__; - return locationString(this_line); - } - - void writeReturningLocationAndFunction(std::string& location, std::string& function) - { - LL_INFOS() << "apple" << LL_ENDL; int this_line = __LINE__; - location = locationString(this_line); - function = __FUNCTION__; - } - - std::string errorReturningLocation() - { - int this_line = __LINE__; CATCH(LL_ERRS(), "die"); - return locationString(this_line); - } + std::string locationString(int line) + { + std::ostringstream location; + location << LLError::abbreviateFile(__FILE__) + << "(" << line << ")"; + + return location.str(); + } + + std::string writeReturningLocation() + { + LL_INFOS() << "apple" << LL_ENDL; int this_line = __LINE__; + return locationString(this_line); + } + + void writeReturningLocationAndFunction(std::string& location, std::string& function) + { + LL_INFOS() << "apple" << LL_ENDL; int this_line = __LINE__; + location = locationString(this_line); + function = __FUNCTION__; + } + + std::string errorReturningLocation() + { + int this_line = __LINE__; CATCH(LL_ERRS(), "die"); + return locationString(this_line); + } } /* The following helper functions and class members all log a simple message - from some particular function scope. Each function takes a bool argument - that indicates if it should log its own name or not (in the manner that - existing log messages often do.) The functions all return their C++ - name so that test can be substantial mechanized. + from some particular function scope. Each function takes a bool argument + that indicates if it should log its own name or not (in the manner that + existing log messages often do.) The functions all return their C++ + name so that test can be substantial mechanized. */ std::string logFromGlobal(bool id) { - LL_INFOS() << (id ? "logFromGlobal: " : "") << "hi" << LL_ENDL; - return "logFromGlobal"; + LL_INFOS() << (id ? "logFromGlobal: " : "") << "hi" << LL_ENDL; + return "logFromGlobal"; } static std::string logFromStatic(bool id) { - LL_INFOS() << (id ? "logFromStatic: " : "") << "hi" << LL_ENDL; - return "logFromStatic"; + LL_INFOS() << (id ? "logFromStatic: " : "") << "hi" << LL_ENDL; + return "logFromStatic"; } namespace { - std::string logFromAnon(bool id) - { - LL_INFOS() << (id ? "logFromAnon: " : "") << "hi" << LL_ENDL; - return "logFromAnon"; - } + std::string logFromAnon(bool id) + { + LL_INFOS() << (id ? "logFromAnon: " : "") << "hi" << LL_ENDL; + return "logFromAnon"; + } } namespace Foo { - std::string logFromNamespace(bool id) - { - LL_INFOS() << (id ? "Foo::logFromNamespace: " : "") << "hi" << LL_ENDL; - //return "Foo::logFromNamespace"; - // there is no standard way to get the namespace name, hence - // we won't be testing for it - return "logFromNamespace"; - } + std::string logFromNamespace(bool id) + { + LL_INFOS() << (id ? "Foo::logFromNamespace: " : "") << "hi" << LL_ENDL; + //return "Foo::logFromNamespace"; + // there is no standard way to get the namespace name, hence + // we won't be testing for it + return "logFromNamespace"; + } } namespace { - class ClassWithNoLogType { - public: - std::string logFromMember(bool id) - { - LL_INFOS() << (id ? "ClassWithNoLogType::logFromMember: " : "") << "hi" << LL_ENDL; - return "ClassWithNoLogType::logFromMember"; - } - static std::string logFromStatic(bool id) - { - LL_INFOS() << (id ? "ClassWithNoLogType::logFromStatic: " : "") << "hi" << LL_ENDL; - return "ClassWithNoLogType::logFromStatic"; - } - }; - - class ClassWithLogType { - LOG_CLASS(ClassWithLogType); - public: - std::string logFromMember(bool id) - { - LL_INFOS() << (id ? "ClassWithLogType::logFromMember: " : "") << "hi" << LL_ENDL; - return "ClassWithLogType::logFromMember"; - } - static std::string logFromStatic(bool id) - { - LL_INFOS() << (id ? "ClassWithLogType::logFromStatic: " : "") << "hi" << LL_ENDL; - return "ClassWithLogType::logFromStatic"; - } - }; - - std::string logFromNamespace(bool id) { return Foo::logFromNamespace(id); } - std::string logFromClassWithLogTypeMember(bool id) { ClassWithLogType c; return c.logFromMember(id); } - std::string logFromClassWithLogTypeStatic(bool id) { return ClassWithLogType::logFromStatic(id); } - - void ensure_has(const std::string& message, - const std::string& actual, const std::string& expected) - { - std::string::size_type n1 = actual.find(expected); - if (n1 == std::string::npos) - { - std::stringstream ss; - ss << message << ": " << "expected to find a copy of '" << expected - << "' in actual '" << actual << "'"; - throw tut::failure(ss.str().c_str()); - } - } - - typedef std::string (*LogFromFunction)(bool); - void testLogName(LLError::RecorderPtr recorder, LogFromFunction f, - const std::string& class_name = "") - { - std::dynamic_pointer_cast(recorder)->clearMessages(); - std::string name = f(false); - f(true); - - std::string messageWithoutName = std::dynamic_pointer_cast(recorder)->message(0); - std::string messageWithName = std::dynamic_pointer_cast(recorder)->message(1); - - ensure_has(name + " logged without name", - messageWithoutName, name); - ensure_has(name + " logged with name", - messageWithName, name); - - if (!class_name.empty()) - { - ensure_has(name + "logged without name", - messageWithoutName, class_name); - ensure_has(name + "logged with name", - messageWithName, class_name); - } - } + class ClassWithNoLogType { + public: + std::string logFromMember(bool id) + { + LL_INFOS() << (id ? "ClassWithNoLogType::logFromMember: " : "") << "hi" << LL_ENDL; + return "ClassWithNoLogType::logFromMember"; + } + static std::string logFromStatic(bool id) + { + LL_INFOS() << (id ? "ClassWithNoLogType::logFromStatic: " : "") << "hi" << LL_ENDL; + return "ClassWithNoLogType::logFromStatic"; + } + }; + + class ClassWithLogType { + LOG_CLASS(ClassWithLogType); + public: + std::string logFromMember(bool id) + { + LL_INFOS() << (id ? "ClassWithLogType::logFromMember: " : "") << "hi" << LL_ENDL; + return "ClassWithLogType::logFromMember"; + } + static std::string logFromStatic(bool id) + { + LL_INFOS() << (id ? "ClassWithLogType::logFromStatic: " : "") << "hi" << LL_ENDL; + return "ClassWithLogType::logFromStatic"; + } + }; + + std::string logFromNamespace(bool id) { return Foo::logFromNamespace(id); } + std::string logFromClassWithLogTypeMember(bool id) { ClassWithLogType c; return c.logFromMember(id); } + std::string logFromClassWithLogTypeStatic(bool id) { return ClassWithLogType::logFromStatic(id); } + + void ensure_has(const std::string& message, + const std::string& actual, const std::string& expected) + { + std::string::size_type n1 = actual.find(expected); + if (n1 == std::string::npos) + { + std::stringstream ss; + ss << message << ": " << "expected to find a copy of '" << expected + << "' in actual '" << actual << "'"; + throw tut::failure(ss.str().c_str()); + } + } + + typedef std::string (*LogFromFunction)(bool); + void testLogName(LLError::RecorderPtr recorder, LogFromFunction f, + const std::string& class_name = "") + { + std::dynamic_pointer_cast(recorder)->clearMessages(); + std::string name = f(false); + f(true); + + std::string messageWithoutName = std::dynamic_pointer_cast(recorder)->message(0); + std::string messageWithName = std::dynamic_pointer_cast(recorder)->message(1); + + ensure_has(name + " logged without name", + messageWithoutName, name); + ensure_has(name + " logged with name", + messageWithName, name); + + if (!class_name.empty()) + { + ensure_has(name + "logged without name", + messageWithoutName, class_name); + ensure_has(name + "logged with name", + messageWithName, class_name); + } + } } namespace @@ -540,7 +540,7 @@ namespace tut // backslash, return, and newline are not escaped with backslashes { LLError::setDefaultLevel(LLError::LEVEL_DEBUG); - setWantsMultiline(true); + setWantsMultiline(true); writeMsgNeedsEscaping(); // but should not be now ensure_message_field_equals(0, MSG_FIELD, "backslash\\"); ensure_message_field_equals(1, MSG_FIELD, "newline\nafternewline"); @@ -554,324 +554,324 @@ namespace tut namespace tut { - template<> template<> - // class/function information in output - void ErrorTestObject::test<6>() - { - testLogName(mRecorder, logFromGlobal); - testLogName(mRecorder, logFromStatic); - testLogName(mRecorder, logFromAnon); - testLogName(mRecorder, logFromNamespace); - testLogName(mRecorder, logFromClassWithLogTypeMember, "ClassWithLogType"); - testLogName(mRecorder, logFromClassWithLogTypeStatic, "ClassWithLogType"); - } + template<> template<> + // class/function information in output + void ErrorTestObject::test<6>() + { + testLogName(mRecorder, logFromGlobal); + testLogName(mRecorder, logFromStatic); + testLogName(mRecorder, logFromAnon); + testLogName(mRecorder, logFromNamespace); + testLogName(mRecorder, logFromClassWithLogTypeMember, "ClassWithLogType"); + testLogName(mRecorder, logFromClassWithLogTypeStatic, "ClassWithLogType"); + } } namespace { - std::string innerLogger() - { - LL_INFOS() << "inside" << LL_ENDL; - return "moo"; - } - - std::string outerLogger() - { - LL_INFOS() << "outside(" << innerLogger() << ")" << LL_ENDL; - return "bar"; - } - - class LogWhileLogging - { - public: - void print(std::ostream& out) const - { - LL_INFOS() << "logging" << LL_ENDL; - out << "baz"; - } - }; - - std::ostream& operator<<(std::ostream& out, const LogWhileLogging& l) - { l.print(out); return out; } - - void metaLogger() - { - LogWhileLogging l; - LL_INFOS() << "meta(" << l << ")" << LL_ENDL; - } + std::string innerLogger() + { + LL_INFOS() << "inside" << LL_ENDL; + return "moo"; + } + + std::string outerLogger() + { + LL_INFOS() << "outside(" << innerLogger() << ")" << LL_ENDL; + return "bar"; + } + + class LogWhileLogging + { + public: + void print(std::ostream& out) const + { + LL_INFOS() << "logging" << LL_ENDL; + out << "baz"; + } + }; + + std::ostream& operator<<(std::ostream& out, const LogWhileLogging& l) + { l.print(out); return out; } + + void metaLogger() + { + LogWhileLogging l; + LL_INFOS() << "meta(" << l << ")" << LL_ENDL; + } } namespace tut { - template<> template<> - // handle nested logging - void ErrorTestObject::test<7>() - { - outerLogger(); - ensure_message_field_equals(0, MSG_FIELD, "inside"); - ensure_message_field_equals(1, MSG_FIELD, "outside(moo)"); - ensure_message_count(2); - - metaLogger(); - ensure_message_field_equals(2, MSG_FIELD, "logging"); - ensure_message_field_equals(3, MSG_FIELD, "meta(baz)"); - ensure_message_count(4); - } - - template<> template<> - // special handling of LL_ERRS() calls - void ErrorTestObject::test<8>() - { - std::string location = errorReturningLocation(); - - ensure_message_field_equals(0, LOCATION_FIELD, location); - ensure_message_field_equals(0, MSG_FIELD, "die"); - ensure_message_count(1); - - ensure("fatal callback called", fatalWasCalled); - } + template<> template<> + // handle nested logging + void ErrorTestObject::test<7>() + { + outerLogger(); + ensure_message_field_equals(0, MSG_FIELD, "inside"); + ensure_message_field_equals(1, MSG_FIELD, "outside(moo)"); + ensure_message_count(2); + + metaLogger(); + ensure_message_field_equals(2, MSG_FIELD, "logging"); + ensure_message_field_equals(3, MSG_FIELD, "meta(baz)"); + ensure_message_count(4); + } + + template<> template<> + // special handling of LL_ERRS() calls + void ErrorTestObject::test<8>() + { + std::string location = errorReturningLocation(); + + ensure_message_field_equals(0, LOCATION_FIELD, location); + ensure_message_field_equals(0, MSG_FIELD, "die"); + ensure_message_count(1); + + ensure("fatal callback called", fatalWasCalled); + } } namespace { - std::string roswell() - { - return "1947-07-08T03:04:05Z"; - } - - void ufoSighting() - { - LL_INFOS() << "ufo" << LL_ENDL; - } + std::string roswell() + { + return "1947-07-08T03:04:05Z"; + } + + void ufoSighting() + { + LL_INFOS() << "ufo" << LL_ENDL; + } } namespace tut { - template<> template<> - // time in output (for recorders that need it) - void ErrorTestObject::test<9>() - { - LLError::setTimeFunction(roswell); - - setWantsTime(false); - ufoSighting(); - ensure_message_field_equals(0, MSG_FIELD, "ufo"); - ensure_message_does_not_contain(0, roswell()); - - setWantsTime(true); - ufoSighting(); - ensure_message_field_equals(1, MSG_FIELD, "ufo"); - ensure_message_field_equals(1, TIME_FIELD, roswell()); - } - - template<> template<> - // output order - void ErrorTestObject::test<10>() - { - LLError::setTimeFunction(roswell); - setWantsTime(true); - - std::string location, - function; - writeReturningLocationAndFunction(location, function); - - ensure_equals("order is time level tags location function message", + template<> template<> + // time in output (for recorders that need it) + void ErrorTestObject::test<9>() + { + LLError::setTimeFunction(roswell); + + setWantsTime(false); + ufoSighting(); + ensure_message_field_equals(0, MSG_FIELD, "ufo"); + ensure_message_does_not_contain(0, roswell()); + + setWantsTime(true); + ufoSighting(); + ensure_message_field_equals(1, MSG_FIELD, "ufo"); + ensure_message_field_equals(1, TIME_FIELD, roswell()); + } + + template<> template<> + // output order + void ErrorTestObject::test<10>() + { + LLError::setTimeFunction(roswell); + setWantsTime(true); + + std::string location, + function; + writeReturningLocationAndFunction(location, function); + + ensure_equals("order is time level tags location function message", message(0), roswell() + " INFO " + "# " /* no tag */ + location + " " + function + " : " + "apple"); - } + } - template<> template<> - // multiple recorders - void ErrorTestObject::test<11>() - { - LLError::RecorderPtr altRecorder(new TestRecorder()); - LLError::addRecorder(altRecorder); + template<> template<> + // multiple recorders + void ErrorTestObject::test<11>() + { + LLError::RecorderPtr altRecorder(new TestRecorder()); + LLError::addRecorder(altRecorder); - LL_INFOS() << "boo" << LL_ENDL; + LL_INFOS() << "boo" << LL_ENDL; - ensure_message_field_equals(0, MSG_FIELD, "boo"); - ensure_equals("alt recorder count", std::dynamic_pointer_cast(altRecorder)->countMessages(), 1); - ensure_contains("alt recorder message 0", std::dynamic_pointer_cast(altRecorder)->message(0), "boo"); + ensure_message_field_equals(0, MSG_FIELD, "boo"); + ensure_equals("alt recorder count", std::dynamic_pointer_cast(altRecorder)->countMessages(), 1); + ensure_contains("alt recorder message 0", std::dynamic_pointer_cast(altRecorder)->message(0), "boo"); - LLError::setTimeFunction(roswell); + LLError::setTimeFunction(roswell); - LLError::RecorderPtr anotherRecorder(new TestRecorder()); - std::dynamic_pointer_cast(anotherRecorder)->showTime(true); - LLError::addRecorder(anotherRecorder); + LLError::RecorderPtr anotherRecorder(new TestRecorder()); + std::dynamic_pointer_cast(anotherRecorder)->showTime(true); + LLError::addRecorder(anotherRecorder); - LL_INFOS() << "baz" << LL_ENDL; + LL_INFOS() << "baz" << LL_ENDL; - std::string when = roswell(); + std::string when = roswell(); - ensure_message_does_not_contain(1, when); - ensure_equals("alt recorder count", std::dynamic_pointer_cast(altRecorder)->countMessages(), 2); - ensure_does_not_contain("alt recorder message 1", std::dynamic_pointer_cast(altRecorder)->message(1), when); - ensure_equals("another recorder count", std::dynamic_pointer_cast(anotherRecorder)->countMessages(), 1); - ensure_contains("another recorder message 0", std::dynamic_pointer_cast(anotherRecorder)->message(0), when); + ensure_message_does_not_contain(1, when); + ensure_equals("alt recorder count", std::dynamic_pointer_cast(altRecorder)->countMessages(), 2); + ensure_does_not_contain("alt recorder message 1", std::dynamic_pointer_cast(altRecorder)->message(1), when); + ensure_equals("another recorder count", std::dynamic_pointer_cast(anotherRecorder)->countMessages(), 1); + ensure_contains("another recorder message 0", std::dynamic_pointer_cast(anotherRecorder)->message(0), when); - LLError::removeRecorder(altRecorder); - LLError::removeRecorder(anotherRecorder); - } + LLError::removeRecorder(altRecorder); + LLError::removeRecorder(anotherRecorder); + } } class TestAlpha { - LOG_CLASS(TestAlpha); + LOG_CLASS(TestAlpha); public: - static void doDebug() { LL_DEBUGS() << "add dice" << LL_ENDL; } - static void doInfo() { LL_INFOS() << "any idea" << LL_ENDL; } - static void doWarn() { LL_WARNS() << "aim west" << LL_ENDL; } - static void doError() { CATCH(LL_ERRS(), "ate eels"); } - static void doAll() { doDebug(); doInfo(); doWarn(); doError(); } + static void doDebug() { LL_DEBUGS() << "add dice" << LL_ENDL; } + static void doInfo() { LL_INFOS() << "any idea" << LL_ENDL; } + static void doWarn() { LL_WARNS() << "aim west" << LL_ENDL; } + static void doError() { CATCH(LL_ERRS(), "ate eels"); } + static void doAll() { doDebug(); doInfo(); doWarn(); doError(); } }; class TestBeta { - LOG_CLASS(TestBeta); + LOG_CLASS(TestBeta); public: - static void doDebug() { LL_DEBUGS() << "bed down" << LL_ENDL; } - static void doInfo() { LL_INFOS() << "buy iron" << LL_ENDL; } - static void doWarn() { LL_WARNS() << "bad word" << LL_ENDL; } - static void doError() { CATCH(LL_ERRS(), "big easy"); } - static void doAll() { doDebug(); doInfo(); doWarn(); doError(); } + static void doDebug() { LL_DEBUGS() << "bed down" << LL_ENDL; } + static void doInfo() { LL_INFOS() << "buy iron" << LL_ENDL; } + static void doWarn() { LL_WARNS() << "bad word" << LL_ENDL; } + static void doError() { CATCH(LL_ERRS(), "big easy"); } + static void doAll() { doDebug(); doInfo(); doWarn(); doError(); } }; namespace tut { - template<> template<> - // filtering by class - void ErrorTestObject::test<12>() - { - LLError::setDefaultLevel(LLError::LEVEL_WARN); - LLError::setClassLevel("TestBeta", LLError::LEVEL_INFO); - - TestAlpha::doAll(); - TestBeta::doAll(); - - ensure_message_field_equals(0, MSG_FIELD, "aim west"); - ensure_message_field_equals(1, MSG_FIELD, "ate eels"); - ensure_message_field_equals(2, MSG_FIELD, "buy iron"); - ensure_message_field_equals(3, MSG_FIELD, "bad word"); - ensure_message_field_equals(4, MSG_FIELD, "big easy"); - ensure_message_count(5); - } - - template<> template<> - // filtering by function, and that it will override class filtering - void ErrorTestObject::test<13>() - { - LLError::setDefaultLevel(LLError::LEVEL_DEBUG); - LLError::setClassLevel("TestBeta", LLError::LEVEL_WARN); - LLError::setFunctionLevel("TestBeta::doInfo", LLError::LEVEL_DEBUG); - LLError::setFunctionLevel("TestBeta::doError", LLError::LEVEL_NONE); - - TestBeta::doAll(); - ensure_message_field_equals(0, MSG_FIELD, "buy iron"); - ensure_message_field_equals(1, MSG_FIELD, "bad word"); - ensure_message_count(2); - } - - template<> template<> - // filtering by file - // and that it is overridden by both class and function filtering - void ErrorTestObject::test<14>() - { - LLError::setDefaultLevel(LLError::LEVEL_DEBUG); - LLError::setFileLevel(LLError::abbreviateFile(__FILE__), - LLError::LEVEL_WARN); - LLError::setClassLevel("TestAlpha", LLError::LEVEL_INFO); - LLError::setFunctionLevel("TestAlpha::doError", - LLError::LEVEL_NONE); - LLError::setFunctionLevel("TestBeta::doError", - LLError::LEVEL_NONE); - - TestAlpha::doAll(); - TestBeta::doAll(); - ensure_message_field_equals(0, MSG_FIELD, "any idea"); - ensure_message_field_equals(1, MSG_FIELD, "aim west"); - ensure_message_field_equals(2, MSG_FIELD, "bad word"); - ensure_message_count(3); - } - - template<> template<> - // proper cached, efficient lookup of filtering - void ErrorTestObject::test<15>() - { - LLError::setDefaultLevel(LLError::LEVEL_NONE); - - TestAlpha::doInfo(); - ensure_message_count(0); - ensure_equals("first check", LLError::shouldLogCallCount(), 1); - TestAlpha::doInfo(); - ensure_message_count(0); - ensure_equals("second check", LLError::shouldLogCallCount(), 1); - - LLError::setClassLevel("TestAlpha", LLError::LEVEL_DEBUG); - TestAlpha::doInfo(); - ensure_message_count(1); - ensure_equals("third check", LLError::shouldLogCallCount(), 2); - TestAlpha::doInfo(); - ensure_message_count(2); - ensure_equals("fourth check", LLError::shouldLogCallCount(), 2); - - LLError::setClassLevel("TestAlpha", LLError::LEVEL_WARN); - TestAlpha::doInfo(); - ensure_message_count(2); - ensure_equals("fifth check", LLError::shouldLogCallCount(), 3); - TestAlpha::doInfo(); - ensure_message_count(2); - ensure_equals("sixth check", LLError::shouldLogCallCount(), 3); - } - - template<> template<> - // configuration from LLSD - void ErrorTestObject::test<16>() - { - LLSD config; - config["print-location"] = true; - config["default-level"] = "DEBUG"; - - LLSD set1; - set1["level"] = "WARN"; + template<> template<> + // filtering by class + void ErrorTestObject::test<12>() + { + LLError::setDefaultLevel(LLError::LEVEL_WARN); + LLError::setClassLevel("TestBeta", LLError::LEVEL_INFO); + + TestAlpha::doAll(); + TestBeta::doAll(); + + ensure_message_field_equals(0, MSG_FIELD, "aim west"); + ensure_message_field_equals(1, MSG_FIELD, "ate eels"); + ensure_message_field_equals(2, MSG_FIELD, "buy iron"); + ensure_message_field_equals(3, MSG_FIELD, "bad word"); + ensure_message_field_equals(4, MSG_FIELD, "big easy"); + ensure_message_count(5); + } + + template<> template<> + // filtering by function, and that it will override class filtering + void ErrorTestObject::test<13>() + { + LLError::setDefaultLevel(LLError::LEVEL_DEBUG); + LLError::setClassLevel("TestBeta", LLError::LEVEL_WARN); + LLError::setFunctionLevel("TestBeta::doInfo", LLError::LEVEL_DEBUG); + LLError::setFunctionLevel("TestBeta::doError", LLError::LEVEL_NONE); + + TestBeta::doAll(); + ensure_message_field_equals(0, MSG_FIELD, "buy iron"); + ensure_message_field_equals(1, MSG_FIELD, "bad word"); + ensure_message_count(2); + } + + template<> template<> + // filtering by file + // and that it is overridden by both class and function filtering + void ErrorTestObject::test<14>() + { + LLError::setDefaultLevel(LLError::LEVEL_DEBUG); + LLError::setFileLevel(LLError::abbreviateFile(__FILE__), + LLError::LEVEL_WARN); + LLError::setClassLevel("TestAlpha", LLError::LEVEL_INFO); + LLError::setFunctionLevel("TestAlpha::doError", + LLError::LEVEL_NONE); + LLError::setFunctionLevel("TestBeta::doError", + LLError::LEVEL_NONE); + + TestAlpha::doAll(); + TestBeta::doAll(); + ensure_message_field_equals(0, MSG_FIELD, "any idea"); + ensure_message_field_equals(1, MSG_FIELD, "aim west"); + ensure_message_field_equals(2, MSG_FIELD, "bad word"); + ensure_message_count(3); + } + + template<> template<> + // proper cached, efficient lookup of filtering + void ErrorTestObject::test<15>() + { + LLError::setDefaultLevel(LLError::LEVEL_NONE); + + TestAlpha::doInfo(); + ensure_message_count(0); + ensure_equals("first check", LLError::shouldLogCallCount(), 1); + TestAlpha::doInfo(); + ensure_message_count(0); + ensure_equals("second check", LLError::shouldLogCallCount(), 1); + + LLError::setClassLevel("TestAlpha", LLError::LEVEL_DEBUG); + TestAlpha::doInfo(); + ensure_message_count(1); + ensure_equals("third check", LLError::shouldLogCallCount(), 2); + TestAlpha::doInfo(); + ensure_message_count(2); + ensure_equals("fourth check", LLError::shouldLogCallCount(), 2); + + LLError::setClassLevel("TestAlpha", LLError::LEVEL_WARN); + TestAlpha::doInfo(); + ensure_message_count(2); + ensure_equals("fifth check", LLError::shouldLogCallCount(), 3); + TestAlpha::doInfo(); + ensure_message_count(2); + ensure_equals("sixth check", LLError::shouldLogCallCount(), 3); + } + + template<> template<> + // configuration from LLSD + void ErrorTestObject::test<16>() + { + LLSD config; + config["print-location"] = true; + config["default-level"] = "DEBUG"; + + LLSD set1; + set1["level"] = "WARN"; set1["files"][0] = LLError::abbreviateFile(__FILE__); - LLSD set2; - set2["level"] = "INFO"; - set2["classes"][0] = "TestAlpha"; - - LLSD set3; - set3["level"] = "NONE"; - set3["functions"][0] = "TestAlpha::doError"; - set3["functions"][1] = "TestBeta::doError"; - - config["settings"][0] = set1; - config["settings"][1] = set2; - config["settings"][2] = set3; - - LLError::configure(config); - - TestAlpha::doAll(); - TestBeta::doAll(); - ensure_message_field_equals(0, MSG_FIELD, "any idea"); - ensure_message_field_equals(1, MSG_FIELD, "aim west"); - ensure_message_field_equals(2, MSG_FIELD, "bad word"); - ensure_message_count(3); - - // make sure reconfiguring works - LLSD config2; - config2["default-level"] = "WARN"; - - LLError::configure(config2); - - TestAlpha::doAll(); - TestBeta::doAll(); - ensure_message_field_equals(3, MSG_FIELD, "aim west"); - ensure_message_field_equals(4, MSG_FIELD, "ate eels"); - ensure_message_field_equals(5, MSG_FIELD, "bad word"); - ensure_message_field_equals(6, MSG_FIELD, "big easy"); - ensure_message_count(7); - } + LLSD set2; + set2["level"] = "INFO"; + set2["classes"][0] = "TestAlpha"; + + LLSD set3; + set3["level"] = "NONE"; + set3["functions"][0] = "TestAlpha::doError"; + set3["functions"][1] = "TestBeta::doError"; + + config["settings"][0] = set1; + config["settings"][1] = set2; + config["settings"][2] = set3; + + LLError::configure(config); + + TestAlpha::doAll(); + TestBeta::doAll(); + ensure_message_field_equals(0, MSG_FIELD, "any idea"); + ensure_message_field_equals(1, MSG_FIELD, "aim west"); + ensure_message_field_equals(2, MSG_FIELD, "bad word"); + ensure_message_count(3); + + // make sure reconfiguring works + LLSD config2; + config2["default-level"] = "WARN"; + + LLError::configure(config2); + + TestAlpha::doAll(); + TestBeta::doAll(); + ensure_message_field_equals(3, MSG_FIELD, "aim west"); + ensure_message_field_equals(4, MSG_FIELD, "ate eels"); + ensure_message_field_equals(5, MSG_FIELD, "bad word"); + ensure_message_field_equals(6, MSG_FIELD, "big easy"); + ensure_message_count(7); + } } namespace tut @@ -919,16 +919,16 @@ namespace tut } /* Tests left: - handling of classes without LOG_CLASS + handling of classes without LOG_CLASS - live update of filtering from file + live update of filtering from file - syslog recorder - file recorder - cerr/stderr recorder - fixed buffer recorder - windows recorder + syslog recorder + file recorder + cerr/stderr recorder + fixed buffer recorder + windows recorder - mutex use when logging (?) - strange careful about to crash handling (?) + mutex use when logging (?) + strange careful about to crash handling (?) */ diff --git a/indra/llcommon/tests/lleventcoro_test.cpp b/indra/llcommon/tests/lleventcoro_test.cpp index 01104545c6..a3c54ffaa2 100644 --- a/indra/llcommon/tests/lleventcoro_test.cpp +++ b/indra/llcommon/tests/lleventcoro_test.cpp @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2009-04-22 * @brief Test for coroutine. - * + * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcommon/tests/lleventdispatcher_test.cpp b/indra/llcommon/tests/lleventdispatcher_test.cpp index b0c532887c..a99acba848 100644 --- a/indra/llcommon/tests/lleventdispatcher_test.cpp +++ b/indra/llcommon/tests/lleventdispatcher_test.cpp @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2011-01-20 * @brief Test for lleventdispatcher. - * + * * $LicenseInfo:firstyear=2011&license=viewerlgpl$ * Copyright (c) 2011, Linden Research, Inc. * $/LicenseInfo$ @@ -470,7 +470,7 @@ namespace tut params["a"], "\n" "params[\"b\"]:\n", params["b"]); - // default LLSD::Binary value + // default LLSD::Binary value std::vector binary; for (size_t ix = 0, h = 0xaa; ix < 6; ++ix, h += 0x11) { diff --git a/indra/llcommon/tests/lleventfilter_test.cpp b/indra/llcommon/tests/lleventfilter_test.cpp index fa2cb03e95..a01d7fe415 100644 --- a/indra/llcommon/tests/lleventfilter_test.cpp +++ b/indra/llcommon/tests/lleventfilter_test.cpp @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2009-03-06 * @brief Test for lleventfilter. - * + * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcommon/tests/llframetimer_test.cpp b/indra/llcommon/tests/llframetimer_test.cpp index be372bb855..b9a8c91abf 100644 --- a/indra/llcommon/tests/llframetimer_test.cpp +++ b/indra/llcommon/tests/llframetimer_test.cpp @@ -1,4 +1,4 @@ -/** +/** * @file lltiming_test.cpp * @date 2006-07-23 * @brief Tests the timers. @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -34,88 +34,88 @@ namespace tut { - struct frametimer_test - { - frametimer_test() - { - LLFrameTimer::updateFrameTime(); - } - }; - typedef test_group frametimer_group_t; - typedef frametimer_group_t::object frametimer_object_t; - tut::frametimer_group_t frametimer_instance("LLFrameTimer"); + struct frametimer_test + { + frametimer_test() + { + LLFrameTimer::updateFrameTime(); + } + }; + typedef test_group frametimer_group_t; + typedef frametimer_group_t::object frametimer_object_t; + tut::frametimer_group_t frametimer_instance("LLFrameTimer"); + + template<> template<> + void frametimer_object_t::test<1>() + { + F64 seconds_since_epoch = LLFrameTimer::getTotalSeconds(); + LLFrameTimer timer; + timer.setExpiryAt(seconds_since_epoch); + F64 expires_at = timer.expiresAt(); + ensure_distance( + "set expiry matches get expiry", + expires_at, + seconds_since_epoch, + 0.001); + } - template<> template<> - void frametimer_object_t::test<1>() - { - F64 seconds_since_epoch = LLFrameTimer::getTotalSeconds(); - LLFrameTimer timer; - timer.setExpiryAt(seconds_since_epoch); - F64 expires_at = timer.expiresAt(); - ensure_distance( - "set expiry matches get expiry", - expires_at, - seconds_since_epoch, - 0.001); - } + template<> template<> + void frametimer_object_t::test<2>() + { + F64 seconds_since_epoch = LLFrameTimer::getTotalSeconds(); + seconds_since_epoch += 10.0; + LLFrameTimer timer; + timer.setExpiryAt(seconds_since_epoch); + F64 expires_at = timer.expiresAt(); + ensure_distance( + "set expiry matches get expiry 1", + expires_at, + seconds_since_epoch, + 0.001); + seconds_since_epoch += 10.0; + timer.setExpiryAt(seconds_since_epoch); + expires_at = timer.expiresAt(); + ensure_distance( + "set expiry matches get expiry 2", + expires_at, + seconds_since_epoch, + 0.001); + } + template<> template<> + void frametimer_object_t::test<3>() + { + clock_t t1 = clock(); + ms_sleep(200); + clock_t t2 = clock(); + clock_t elapsed = t2 - t1 + 1; + std::cout << "Note: using clock(), ms_sleep() actually took " << (long)elapsed << "ms" << std::endl; - template<> template<> - void frametimer_object_t::test<2>() - { - F64 seconds_since_epoch = LLFrameTimer::getTotalSeconds(); - seconds_since_epoch += 10.0; - LLFrameTimer timer; - timer.setExpiryAt(seconds_since_epoch); - F64 expires_at = timer.expiresAt(); - ensure_distance( - "set expiry matches get expiry 1", - expires_at, - seconds_since_epoch, - 0.001); - seconds_since_epoch += 10.0; - timer.setExpiryAt(seconds_since_epoch); - expires_at = timer.expiresAt(); - ensure_distance( - "set expiry matches get expiry 2", - expires_at, - seconds_since_epoch, - 0.001); - } - template<> template<> - void frametimer_object_t::test<3>() - { - clock_t t1 = clock(); - ms_sleep(200); - clock_t t2 = clock(); - clock_t elapsed = t2 - t1 + 1; - std::cout << "Note: using clock(), ms_sleep() actually took " << (long)elapsed << "ms" << std::endl; + F64 seconds_since_epoch = LLFrameTimer::getTotalSeconds(); + seconds_since_epoch += 2.0; + LLFrameTimer timer; + timer.setExpiryAt(seconds_since_epoch); + /* + * Note that the ms_sleep(200) below is only guaranteed to return + * in 200ms _or_more_, so it should be true that by the 10th + * iteration we've gotten to the 2 seconds requested above + * and the timer should expire, but it can expire in fewer iterations + * if one or more of the ms_sleep calls takes longer. + * (as it did when we moved to Mac OS X 10.10) + */ + int iterations_until_expiration = 0; + while ( !timer.hasExpired() ) + { + ms_sleep(200); + LLFrameTimer::updateFrameTime(); + iterations_until_expiration++; + } + ensure("timer took too long to expire", iterations_until_expiration <= 10); + } - F64 seconds_since_epoch = LLFrameTimer::getTotalSeconds(); - seconds_since_epoch += 2.0; - LLFrameTimer timer; - timer.setExpiryAt(seconds_since_epoch); - /* - * Note that the ms_sleep(200) below is only guaranteed to return - * in 200ms _or_more_, so it should be true that by the 10th - * iteration we've gotten to the 2 seconds requested above - * and the timer should expire, but it can expire in fewer iterations - * if one or more of the ms_sleep calls takes longer. - * (as it did when we moved to Mac OS X 10.10) - */ - int iterations_until_expiration = 0; - while ( !timer.hasExpired() ) - { - ms_sleep(200); - LLFrameTimer::updateFrameTime(); - iterations_until_expiration++; - } - ensure("timer took too long to expire", iterations_until_expiration <= 10); - } - /* - template<> template<> - void frametimer_object_t::test<4>() - { - } + template<> template<> + void frametimer_object_t::test<4>() + { + } */ } diff --git a/indra/llcommon/tests/llheteromap_test.cpp b/indra/llcommon/tests/llheteromap_test.cpp index 686bffb878..cabfb91593 100644 --- a/indra/llcommon/tests/llheteromap_test.cpp +++ b/indra/llcommon/tests/llheteromap_test.cpp @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2016-10-12 * @brief Test for llheteromap. - * + * * $LicenseInfo:firstyear=2016&license=viewerlgpl$ * Copyright (c) 2016, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/tests/llinstancetracker_test.cpp b/indra/llcommon/tests/llinstancetracker_test.cpp index 95af9c2a50..c6eb0fdf75 100644 --- a/indra/llcommon/tests/llinstancetracker_test.cpp +++ b/indra/llcommon/tests/llinstancetracker_test.cpp @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2009-11-10 * @brief Test for llinstancetracker. - * + * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -170,7 +170,7 @@ namespace tut { Unkeyed one, two, three; typedef std::set KeySet; - + KeySet instances; instances.insert(&one); instances.insert(&two); diff --git a/indra/llcommon/tests/lllazy_test.cpp b/indra/llcommon/tests/lllazy_test.cpp index 542306ee22..923fe952a9 100644 --- a/indra/llcommon/tests/lllazy_test.cpp +++ b/indra/llcommon/tests/lllazy_test.cpp @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2009-01-28 * @brief Tests of lllazy.h. - * + * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcommon/tests/llleap_test.cpp b/indra/llcommon/tests/llleap_test.cpp index 7197dedfbf..fa48bcdefd 100644 --- a/indra/llcommon/tests/llleap_test.cpp +++ b/indra/llcommon/tests/llleap_test.cpp @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2012-02-21 * @brief Test for llleap. - * + * * $LicenseInfo:firstyear=2012&license=viewerlgpl$ * Copyright (c) 2012, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/tests/llmainthreadtask_test.cpp b/indra/llcommon/tests/llmainthreadtask_test.cpp index 69b11ccafb..9ccf391327 100644 --- a/indra/llcommon/tests/llmainthreadtask_test.cpp +++ b/indra/llcommon/tests/llmainthreadtask_test.cpp @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2019-12-05 * @brief Test for llmainthreadtask. - * + * * $LicenseInfo:firstyear=2019&license=viewerlgpl$ * Copyright (c) 2019, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/tests/llmemtype_test.cpp b/indra/llcommon/tests/llmemtype_test.cpp index 1f050d6dc7..2d64d342ae 100644 --- a/indra/llcommon/tests/llmemtype_test.cpp +++ b/indra/llcommon/tests/llmemtype_test.cpp @@ -3,25 +3,25 @@ * @author Palmer Truelson * @date 2008-03- * @brief Test for llmemtype.cpp. - * + * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -37,14 +37,14 @@ std::stack memTypeStack; void LLAllocator::pushMemType(S32 i) { - memTypeStack.push(i); + memTypeStack.push(i); } S32 LLAllocator::popMemType(void) { - S32 ret = memTypeStack.top(); - memTypeStack.pop(); - return ret; + S32 ret = memTypeStack.top(); + memTypeStack.pop(); + return ret; } namespace tut @@ -69,49 +69,49 @@ namespace tut ensure("Simplest test ever", true); } - // test with no scripts - template<> template<> - void object::test<2>() - { - { - LLMemType m1(LLMemType::MTYPE_INIT); - } - ensure("Test that you can construct and destruct the mem type"); - } - - // test creation and stack testing - template<> template<> - void object::test<3>() - { - { - ensure("Test that creation and destruction properly inc/dec the stack"); - ensure_equals(memTypeStack.size(), 0); - { - LLMemType m1(LLMemType::MTYPE_INIT); - ensure_equals(memTypeStack.size(), 1); - LLMemType m2(LLMemType::MTYPE_STARTUP); - ensure_equals(memTypeStack.size(), 2); - } - ensure_equals(memTypeStack.size(), 0); - } - } - - // test with no scripts - template<> template<> - void object::test<4>() - { - // catch the begining and end - std::string test_name = LLMemType::getNameFromID(LLMemType::MTYPE_INIT.mID); - ensure_equals("Init name", test_name, "Init"); - - std::string test_name2 = LLMemType::getNameFromID(LLMemType::MTYPE_VOLUME.mID); - ensure_equals("Volume name", test_name2, "Volume"); - - std::string test_name3 = LLMemType::getNameFromID(LLMemType::MTYPE_OTHER.mID); - ensure_equals("Other name", test_name3, "Other"); + // test with no scripts + template<> template<> + void object::test<2>() + { + { + LLMemType m1(LLMemType::MTYPE_INIT); + } + ensure("Test that you can construct and destruct the mem type"); + } + + // test creation and stack testing + template<> template<> + void object::test<3>() + { + { + ensure("Test that creation and destruction properly inc/dec the stack"); + ensure_equals(memTypeStack.size(), 0); + { + LLMemType m1(LLMemType::MTYPE_INIT); + ensure_equals(memTypeStack.size(), 1); + LLMemType m2(LLMemType::MTYPE_STARTUP); + ensure_equals(memTypeStack.size(), 2); + } + ensure_equals(memTypeStack.size(), 0); + } + } + + // test with no scripts + template<> template<> + void object::test<4>() + { + // catch the begining and end + std::string test_name = LLMemType::getNameFromID(LLMemType::MTYPE_INIT.mID); + ensure_equals("Init name", test_name, "Init"); + + std::string test_name2 = LLMemType::getNameFromID(LLMemType::MTYPE_VOLUME.mID); + ensure_equals("Volume name", test_name2, "Volume"); + + std::string test_name3 = LLMemType::getNameFromID(LLMemType::MTYPE_OTHER.mID); + ensure_equals("Other name", test_name3, "Other"); std::string test_name4 = LLMemType::getNameFromID(-1); ensure_equals("Invalid name", test_name4, "INVALID"); - } + } }; diff --git a/indra/llcommon/tests/llpounceable_test.cpp b/indra/llcommon/tests/llpounceable_test.cpp index 2f4915ce11..b3024966c5 100644 --- a/indra/llcommon/tests/llpounceable_test.cpp +++ b/indra/llcommon/tests/llpounceable_test.cpp @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2015-05-22 * @brief Test for llpounceable. - * + * * $LicenseInfo:firstyear=2015&license=viewerlgpl$ * Copyright (c) 2015, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/tests/llprocess_test.cpp b/indra/llcommon/tests/llprocess_test.cpp index 628f046f55..6e8422ca0c 100644 --- a/indra/llcommon/tests/llprocess_test.cpp +++ b/indra/llcommon/tests/llprocess_test.cpp @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2011-12-19 * @brief Test for llprocess. - * + * * $LicenseInfo:firstyear=2011&license=viewerlgpl$ * Copyright (c) 2011, Linden Research, Inc. * $/LicenseInfo$ @@ -1075,7 +1075,7 @@ namespace tut { EventListener(LLEventPump& pump) { - mConnection = + mConnection = pump.listen("EventListener", boost::bind(&EventListener::tick, this, _1)); } diff --git a/indra/llcommon/tests/llprocessor_test.cpp b/indra/llcommon/tests/llprocessor_test.cpp index 884e1b5e5b..a2467d9205 100644 --- a/indra/llcommon/tests/llprocessor_test.cpp +++ b/indra/llcommon/tests/llprocessor_test.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llprocessor_test.cpp * @date 2010-06-01 * * $LicenseInfo:firstyear=2010&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -32,30 +32,30 @@ namespace tut { - struct processor - { - }; - - typedef test_group processor_t; - typedef processor_t::object processor_object_t; - tut::processor_t tut_processor("LLProcessor"); - - template<> template<> - void processor_object_t::test<1>() - { - set_test_name("LLProcessorInfo regression test"); - - LLProcessorInfo pi; - F64 freq = pi.getCPUFrequency(); - //bool sse = pi.hasSSE(); - //bool sse2 = pi.hasSSE2(); - //bool alitvec = pi.hasAltivec(); - std::string family = pi.getCPUFamilyName(); - std::string brand = pi.getCPUBrandName(); - //std::string steam = pi.getCPUFeatureDescription(); - - ensure_not_equals("Unknown Brand name", brand, "Unknown"); - ensure_not_equals("Unknown Family name", family, "Unknown"); - ensure("Reasonable CPU Frequency > 100 && < 10000", freq > 100 && freq < 10000); - } + struct processor + { + }; + + typedef test_group processor_t; + typedef processor_t::object processor_object_t; + tut::processor_t tut_processor("LLProcessor"); + + template<> template<> + void processor_object_t::test<1>() + { + set_test_name("LLProcessorInfo regression test"); + + LLProcessorInfo pi; + F64 freq = pi.getCPUFrequency(); + //bool sse = pi.hasSSE(); + //bool sse2 = pi.hasSSE2(); + //bool alitvec = pi.hasAltivec(); + std::string family = pi.getCPUFamilyName(); + std::string brand = pi.getCPUBrandName(); + //std::string steam = pi.getCPUFeatureDescription(); + + ensure_not_equals("Unknown Brand name", brand, "Unknown"); + ensure_not_equals("Unknown Family name", family, "Unknown"); + ensure("Reasonable CPU Frequency > 100 && < 10000", freq > 100 && freq < 10000); + } } diff --git a/indra/llcommon/tests/llprocinfo_test.cpp b/indra/llcommon/tests/llprocinfo_test.cpp index 12d5a695ee..6a151048c2 100644 --- a/indra/llcommon/tests/llprocinfo_test.cpp +++ b/indra/llcommon/tests/llprocinfo_test.cpp @@ -1,25 +1,25 @@ -/** +/** * @file llprocinfo_test.cpp * @brief Tests for the LLProcInfo class. * * $LicenseInfo:firstyear=2013&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2013, 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$ */ @@ -40,9 +40,9 @@ namespace tut struct procinfo_test { - procinfo_test() - { - } + procinfo_test() + { + } }; typedef test_group procinfo_group_t; @@ -54,14 +54,14 @@ tut::procinfo_group_t procinfo_instance("LLProcInfo"); template<> template<> void procinfo_object_t::test<1>() { - LLProcInfo::time_type user(bad_user), system(bad_system); + LLProcInfo::time_type user(bad_user), system(bad_system); + + set_test_name("getCPUUsage() basic function"); - set_test_name("getCPUUsage() basic function"); + LLProcInfo::getCPUUsage(user, system); - LLProcInfo::getCPUUsage(user, system); - - ensure_not_equals("getCPUUsage() writes to its user argument", user, bad_user); - ensure_not_equals("getCPUUsage() writes to its system argument", system, bad_system); + ensure_not_equals("getCPUUsage() writes to its user argument", user, bad_user); + ensure_not_equals("getCPUUsage() writes to its system argument", system, bad_system); } @@ -69,22 +69,22 @@ void procinfo_object_t::test<1>() template<> template<> void procinfo_object_t::test<2>() { - LLProcInfo::time_type user(bad_user), system(bad_system); - LLProcInfo::time_type user2(bad_user), system2(bad_system); - - set_test_name("getCPUUsage() increases over time"); - - LLProcInfo::getCPUUsage(user, system); - - for (int i(0); i < 100000; ++i) - { - ms_sleep(0); - } - - LLProcInfo::getCPUUsage(user2, system2); - - ensure_equals("getCPUUsage() user value doesn't decrease over time", user2 >= user, true); - ensure_equals("getCPUUsage() system value doesn't decrease over time", system2 >= system, true); + LLProcInfo::time_type user(bad_user), system(bad_system); + LLProcInfo::time_type user2(bad_user), system2(bad_system); + + set_test_name("getCPUUsage() increases over time"); + + LLProcInfo::getCPUUsage(user, system); + + for (int i(0); i < 100000; ++i) + { + ms_sleep(0); + } + + LLProcInfo::getCPUUsage(user2, system2); + + ensure_equals("getCPUUsage() user value doesn't decrease over time", user2 >= user, true); + ensure_equals("getCPUUsage() system value doesn't decrease over time", system2 >= system, true); } diff --git a/indra/llcommon/tests/llrand_test.cpp b/indra/llcommon/tests/llrand_test.cpp index ac5a33d0ba..a0dd4ef576 100644 --- a/indra/llcommon/tests/llrand_test.cpp +++ b/indra/llcommon/tests/llrand_test.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llrandom_test.cpp * @author Phoenix * @date 2007-01-25 @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -49,76 +49,76 @@ void ensure_in_range(const std::string_view& name, namespace tut { - struct random - { - }; + struct random + { + }; - typedef test_group random_t; - typedef random_t::object random_object_t; - tut::random_t tut_random("LLSeedRand"); + typedef test_group random_t; + typedef random_t::object random_object_t; + tut::random_t tut_random("LLSeedRand"); - template<> template<> - void random_object_t::test<1>() - { - for(S32 ii = 0; ii < 100000; ++ii) - { - ensure_in_range("frand", ll_frand(), 0.0f, 1.0f); - } - } + template<> template<> + void random_object_t::test<1>() + { + for(S32 ii = 0; ii < 100000; ++ii) + { + ensure_in_range("frand", ll_frand(), 0.0f, 1.0f); + } + } - template<> template<> - void random_object_t::test<2>() - { - for(S32 ii = 0; ii < 100000; ++ii) - { - ensure_in_range("drand", ll_drand(), 0.0, 1.0); - } - } + template<> template<> + void random_object_t::test<2>() + { + for(S32 ii = 0; ii < 100000; ++ii) + { + ensure_in_range("drand", ll_drand(), 0.0, 1.0); + } + } - template<> template<> - void random_object_t::test<3>() - { - for(S32 ii = 0; ii < 100000; ++ii) - { - ensure_in_range("frand(2.0f)", ll_frand(2.0f) - 1.0f, -1.0f, 1.0f); - } - } + template<> template<> + void random_object_t::test<3>() + { + for(S32 ii = 0; ii < 100000; ++ii) + { + ensure_in_range("frand(2.0f)", ll_frand(2.0f) - 1.0f, -1.0f, 1.0f); + } + } - template<> template<> - void random_object_t::test<4>() - { - for(S32 ii = 0; ii < 100000; ++ii) - { - // Negate the result so we don't have to allow a templated low-end - // comparison as well. - ensure_in_range("-frand(-7.0)", -ll_frand(-7.0), 0.0f, 7.0f); - } - } + template<> template<> + void random_object_t::test<4>() + { + for(S32 ii = 0; ii < 100000; ++ii) + { + // Negate the result so we don't have to allow a templated low-end + // comparison as well. + ensure_in_range("-frand(-7.0)", -ll_frand(-7.0), 0.0f, 7.0f); + } + } - template<> template<> - void random_object_t::test<5>() - { - for(S32 ii = 0; ii < 100000; ++ii) - { - ensure_in_range("-drand(-2.0)", -ll_drand(-2.0), 0.0, 2.0); - } - } + template<> template<> + void random_object_t::test<5>() + { + for(S32 ii = 0; ii < 100000; ++ii) + { + ensure_in_range("-drand(-2.0)", -ll_drand(-2.0), 0.0, 2.0); + } + } - template<> template<> - void random_object_t::test<6>() - { - for(S32 ii = 0; ii < 100000; ++ii) - { - ensure_in_range("rand(100)", ll_rand(100), 0, 100); - } - } + template<> template<> + void random_object_t::test<6>() + { + for(S32 ii = 0; ii < 100000; ++ii) + { + ensure_in_range("rand(100)", ll_rand(100), 0, 100); + } + } - template<> template<> - void random_object_t::test<7>() - { - for(S32 ii = 0; ii < 100000; ++ii) - { - ensure_in_range("-rand(-127)", -ll_rand(-127), 0, 127); - } - } + template<> template<> + void random_object_t::test<7>() + { + for(S32 ii = 0; ii < 100000; ++ii) + { + ensure_in_range("-rand(-127)", -ll_rand(-127), 0, 127); + } + } } diff --git a/indra/llcommon/tests/llsdserialize_test.cpp b/indra/llcommon/tests/llsdserialize_test.cpp index ac40125f75..56fdc51e82 100644 --- a/indra/llcommon/tests/llsdserialize_test.cpp +++ b/indra/llcommon/tests/llsdserialize_test.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llsdserialize_test.cpp * @date 2006-04 * @brief LLSDSerialize unit tests @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -64,313 +64,313 @@ typedef std::function P std::vector string_to_vector(const std::string& str) { - return std::vector(str.begin(), str.end()); + return std::vector(str.begin(), str.end()); } namespace tut { - struct sd_xml_data - { - sd_xml_data() - { - mFormatter = new LLSDXMLFormatter; - } - LLSD mSD; - LLPointer mFormatter; - void xml_test(const char* name, const std::string& expected) - { - std::ostringstream ostr; - mFormatter->format(mSD, ostr); - ensure_equals(name, ostr.str(), expected); - } - }; - - typedef test_group sd_xml_test; - typedef sd_xml_test::object sd_xml_object; - tut::sd_xml_test sd_xml_stream("LLSDXMLFormatter"); - - template<> template<> - void sd_xml_object::test<1>() - { - // random atomic tests - std::string expected; - - expected = "\n"; - xml_test("undef", expected); - - mSD = 3463; - expected = "3463\n"; - xml_test("integer", expected); - - mSD = ""; - expected = "\n"; - xml_test("empty string", expected); - - mSD = "foobar"; - expected = "foobar\n"; - xml_test("string", expected); - - mSD = LLUUID::null; - expected = "\n"; - xml_test("null uuid", expected); - - mSD = LLUUID("c96f9b1e-f589-4100-9774-d98643ce0bed"); - expected = "c96f9b1e-f589-4100-9774-d98643ce0bed\n"; - xml_test("uuid", expected); - - mSD = LLURI("https://secondlife.com/login"); - expected = "https://secondlife.com/login\n"; - xml_test("uri", expected); - - mSD = LLDate("2006-04-24T16:11:33Z"); - expected = "2006-04-24T16:11:33Z\n"; - xml_test("date", expected); - - // Generated by: echo -n 'hello' | openssl enc -e -base64 - std::vector hello; - hello.push_back('h'); - hello.push_back('e'); - hello.push_back('l'); - hello.push_back('l'); - hello.push_back('o'); - mSD = hello; - expected = "aGVsbG8=\n"; - xml_test("binary", expected); - } - - template<> template<> - void sd_xml_object::test<2>() - { - // tests with boolean values. - std::string expected; - - mFormatter->boolalpha(true); - mSD = true; - expected = "true\n"; - xml_test("bool alpha true", expected); - mSD = false; - expected = "false\n"; - xml_test("bool alpha false", expected); - - mFormatter->boolalpha(false); - mSD = true; - expected = "1\n"; - xml_test("bool true", expected); - mSD = false; - expected = "0\n"; - xml_test("bool false", expected); - } - - - template<> template<> - void sd_xml_object::test<3>() - { - // tests with real values. - std::string expected; - - mFormatter->realFormat("%.2f"); - mSD = 1.0; - expected = "1.00\n"; - xml_test("real 1", expected); - - mSD = -34379.0438; - expected = "-34379.04\n"; - xml_test("real reduced precision", expected); - mFormatter->realFormat("%.4f"); - expected = "-34379.0438\n"; - xml_test("higher precision", expected); - - mFormatter->realFormat("%.0f"); - mSD = 0.0; - expected = "0\n"; - xml_test("no decimal 0", expected); - mSD = 3287.4387; - expected = "3287\n"; - xml_test("no decimal real number", expected); - } - - template<> template<> - void sd_xml_object::test<4>() - { - // tests with arrays - std::string expected; - - mSD = LLSD::emptyArray(); - expected = "\n"; - xml_test("empty array", expected); - - mSD.append(LLSD()); - expected = "\n"; - xml_test("1 element array", expected); - - mSD.append(1); - expected = "1\n"; - xml_test("2 element array", expected); - } - - template<> template<> - void sd_xml_object::test<5>() - { - // tests with arrays - std::string expected; - - mSD = LLSD::emptyMap(); - expected = "\n"; - xml_test("empty map", expected); - - mSD["foo"] = "bar"; - expected = "foobar\n"; - xml_test("1 element map", expected); - - mSD["baz"] = LLSD(); - expected = "bazfoobar\n"; - xml_test("2 element map", expected); - } - - template<> template<> - void sd_xml_object::test<6>() - { - // tests with binary - std::string expected; - - // Generated by: echo -n 'hello' | openssl enc -e -base64 - mSD = string_to_vector("hello"); - expected = "aGVsbG8=\n"; - xml_test("binary", expected); - - mSD = string_to_vector("6|6|asdfhappybox|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|00000000-0000-0000-0000-000000000000|7fffffff|7fffffff|0|0|82000|450fe394-2904-c9ad-214c-a07eb7feec29|(No Description)|0|10|0"); - expected = "Nnw2fGFzZGZoYXBweWJveHw2MGU0NGVjNS0zMDVjLTQzYzItOWExOS1iNGI4OWIxYWUyYTZ8NjBlNDRlYzUtMzA1Yy00M2MyLTlhMTktYjRiODliMWFlMmE2fDYwZTQ0ZWM1LTMwNWMtNDNjMi05YTE5LWI0Yjg5YjFhZTJhNnwwMDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDB8N2ZmZmZmZmZ8N2ZmZmZmZmZ8MHwwfDgyMDAwfDQ1MGZlMzk0LTI5MDQtYzlhZC0yMTRjLWEwN2ViN2ZlZWMyOXwoTm8gRGVzY3JpcHRpb24pfDB8MTB8MA==\n"; - xml_test("binary", expected); - } - - class TestLLSDSerializeData - { - public: - TestLLSDSerializeData(); - ~TestLLSDSerializeData(); - - void doRoundTripTests(const std::string&); - void checkRoundTrip(const std::string&, const LLSD& v); - - void setFormatterParser(LLPointer formatter, LLPointer parser) - { - mFormatter = [formatter](const LLSD& data, std::ostream& str) - { - formatter->format(data, str); - }; - // this lambda must be mutable since otherwise the bound 'parser' - // is assumed to point to a const LLSDParser - mParser = [parser](std::istream& istr, LLSD& data, llssize max_bytes) mutable - { - // reset() call is needed since test code re-uses parser object - parser->reset(); - return (parser->parse(istr, data, max_bytes) > 0); - }; - } - - void setParser(bool (*parser)(LLSD&, std::istream&, llssize)) - { - // why does LLSDSerialize::deserialize() reverse the parse() params?? - mParser = [parser](std::istream& istr, LLSD& data, llssize max_bytes) - { - return parser(data, istr, max_bytes); - }; - } - - FormatterFunction mFormatter; - ParserFunction mParser; - }; - - TestLLSDSerializeData::TestLLSDSerializeData() - { - } - - TestLLSDSerializeData::~TestLLSDSerializeData() - { - } - - void TestLLSDSerializeData::checkRoundTrip(const std::string& msg, const LLSD& v) - { - std::stringstream stream; - mFormatter(v, stream); - //LL_INFOS() << "checkRoundTrip: length " << stream.str().length() << LL_ENDL; - LLSD w; - mParser(stream, w, stream.str().size()); - - try - { - ensure_equals(msg, w, v); - } - catch (...) - { - std::cerr << "the serialized string was:" << std::endl; - std::cerr << stream.str() << std::endl; - throw; - } - } - - static void fillmap(LLSD& root, U32 width, U32 depth) - { - if(depth == 0) - { - root["foo"] = "bar"; - return; - } - - for(U32 i = 0; i < width; ++i) - { - std::string key = llformat("child %d", i); - root[key] = LLSD::emptyMap(); - fillmap(root[key], width, depth - 1); - } - } - - void TestLLSDSerializeData::doRoundTripTests(const std::string& msg) - { - LLSD v; - checkRoundTrip(msg + " undefined", v); - - v = true; - checkRoundTrip(msg + " true bool", v); - - v = false; - checkRoundTrip(msg + " false bool", v); - - v = 1; - checkRoundTrip(msg + " positive int", v); - - v = 0; - checkRoundTrip(msg + " zero int", v); - - v = -1; - checkRoundTrip(msg + " negative int", v); - - v = 1234.5f; - checkRoundTrip(msg + " positive float", v); - - v = 0.0f; - checkRoundTrip(msg + " zero float", v); - - v = -1234.5f; - checkRoundTrip(msg + " negative float", v); - - // FIXME: need a NaN test - - v = LLUUID::null; - checkRoundTrip(msg + " null uuid", v); - - LLUUID newUUID; - newUUID.generate(); - v = newUUID; - checkRoundTrip(msg + " new uuid", v); - - v = ""; - checkRoundTrip(msg + " empty string", v); - - v = "some string"; - checkRoundTrip(msg + " non-empty string", v); - - v = + struct sd_xml_data + { + sd_xml_data() + { + mFormatter = new LLSDXMLFormatter; + } + LLSD mSD; + LLPointer mFormatter; + void xml_test(const char* name, const std::string& expected) + { + std::ostringstream ostr; + mFormatter->format(mSD, ostr); + ensure_equals(name, ostr.str(), expected); + } + }; + + typedef test_group sd_xml_test; + typedef sd_xml_test::object sd_xml_object; + tut::sd_xml_test sd_xml_stream("LLSDXMLFormatter"); + + template<> template<> + void sd_xml_object::test<1>() + { + // random atomic tests + std::string expected; + + expected = "\n"; + xml_test("undef", expected); + + mSD = 3463; + expected = "3463\n"; + xml_test("integer", expected); + + mSD = ""; + expected = "\n"; + xml_test("empty string", expected); + + mSD = "foobar"; + expected = "foobar\n"; + xml_test("string", expected); + + mSD = LLUUID::null; + expected = "\n"; + xml_test("null uuid", expected); + + mSD = LLUUID("c96f9b1e-f589-4100-9774-d98643ce0bed"); + expected = "c96f9b1e-f589-4100-9774-d98643ce0bed\n"; + xml_test("uuid", expected); + + mSD = LLURI("https://secondlife.com/login"); + expected = "https://secondlife.com/login\n"; + xml_test("uri", expected); + + mSD = LLDate("2006-04-24T16:11:33Z"); + expected = "2006-04-24T16:11:33Z\n"; + xml_test("date", expected); + + // Generated by: echo -n 'hello' | openssl enc -e -base64 + std::vector hello; + hello.push_back('h'); + hello.push_back('e'); + hello.push_back('l'); + hello.push_back('l'); + hello.push_back('o'); + mSD = hello; + expected = "aGVsbG8=\n"; + xml_test("binary", expected); + } + + template<> template<> + void sd_xml_object::test<2>() + { + // tests with boolean values. + std::string expected; + + mFormatter->boolalpha(true); + mSD = true; + expected = "true\n"; + xml_test("bool alpha true", expected); + mSD = false; + expected = "false\n"; + xml_test("bool alpha false", expected); + + mFormatter->boolalpha(false); + mSD = true; + expected = "1\n"; + xml_test("bool true", expected); + mSD = false; + expected = "0\n"; + xml_test("bool false", expected); + } + + + template<> template<> + void sd_xml_object::test<3>() + { + // tests with real values. + std::string expected; + + mFormatter->realFormat("%.2f"); + mSD = 1.0; + expected = "1.00\n"; + xml_test("real 1", expected); + + mSD = -34379.0438; + expected = "-34379.04\n"; + xml_test("real reduced precision", expected); + mFormatter->realFormat("%.4f"); + expected = "-34379.0438\n"; + xml_test("higher precision", expected); + + mFormatter->realFormat("%.0f"); + mSD = 0.0; + expected = "0\n"; + xml_test("no decimal 0", expected); + mSD = 3287.4387; + expected = "3287\n"; + xml_test("no decimal real number", expected); + } + + template<> template<> + void sd_xml_object::test<4>() + { + // tests with arrays + std::string expected; + + mSD = LLSD::emptyArray(); + expected = "\n"; + xml_test("empty array", expected); + + mSD.append(LLSD()); + expected = "\n"; + xml_test("1 element array", expected); + + mSD.append(1); + expected = "1\n"; + xml_test("2 element array", expected); + } + + template<> template<> + void sd_xml_object::test<5>() + { + // tests with arrays + std::string expected; + + mSD = LLSD::emptyMap(); + expected = "\n"; + xml_test("empty map", expected); + + mSD["foo"] = "bar"; + expected = "foobar\n"; + xml_test("1 element map", expected); + + mSD["baz"] = LLSD(); + expected = "bazfoobar\n"; + xml_test("2 element map", expected); + } + + template<> template<> + void sd_xml_object::test<6>() + { + // tests with binary + std::string expected; + + // Generated by: echo -n 'hello' | openssl enc -e -base64 + mSD = string_to_vector("hello"); + expected = "aGVsbG8=\n"; + xml_test("binary", expected); + + mSD = string_to_vector("6|6|asdfhappybox|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|00000000-0000-0000-0000-000000000000|7fffffff|7fffffff|0|0|82000|450fe394-2904-c9ad-214c-a07eb7feec29|(No Description)|0|10|0"); + expected = "Nnw2fGFzZGZoYXBweWJveHw2MGU0NGVjNS0zMDVjLTQzYzItOWExOS1iNGI4OWIxYWUyYTZ8NjBlNDRlYzUtMzA1Yy00M2MyLTlhMTktYjRiODliMWFlMmE2fDYwZTQ0ZWM1LTMwNWMtNDNjMi05YTE5LWI0Yjg5YjFhZTJhNnwwMDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDB8N2ZmZmZmZmZ8N2ZmZmZmZmZ8MHwwfDgyMDAwfDQ1MGZlMzk0LTI5MDQtYzlhZC0yMTRjLWEwN2ViN2ZlZWMyOXwoTm8gRGVzY3JpcHRpb24pfDB8MTB8MA==\n"; + xml_test("binary", expected); + } + + class TestLLSDSerializeData + { + public: + TestLLSDSerializeData(); + ~TestLLSDSerializeData(); + + void doRoundTripTests(const std::string&); + void checkRoundTrip(const std::string&, const LLSD& v); + + void setFormatterParser(LLPointer formatter, LLPointer parser) + { + mFormatter = [formatter](const LLSD& data, std::ostream& str) + { + formatter->format(data, str); + }; + // this lambda must be mutable since otherwise the bound 'parser' + // is assumed to point to a const LLSDParser + mParser = [parser](std::istream& istr, LLSD& data, llssize max_bytes) mutable + { + // reset() call is needed since test code re-uses parser object + parser->reset(); + return (parser->parse(istr, data, max_bytes) > 0); + }; + } + + void setParser(bool (*parser)(LLSD&, std::istream&, llssize)) + { + // why does LLSDSerialize::deserialize() reverse the parse() params?? + mParser = [parser](std::istream& istr, LLSD& data, llssize max_bytes) + { + return parser(data, istr, max_bytes); + }; + } + + FormatterFunction mFormatter; + ParserFunction mParser; + }; + + TestLLSDSerializeData::TestLLSDSerializeData() + { + } + + TestLLSDSerializeData::~TestLLSDSerializeData() + { + } + + void TestLLSDSerializeData::checkRoundTrip(const std::string& msg, const LLSD& v) + { + std::stringstream stream; + mFormatter(v, stream); + //LL_INFOS() << "checkRoundTrip: length " << stream.str().length() << LL_ENDL; + LLSD w; + mParser(stream, w, stream.str().size()); + + try + { + ensure_equals(msg, w, v); + } + catch (...) + { + std::cerr << "the serialized string was:" << std::endl; + std::cerr << stream.str() << std::endl; + throw; + } + } + + static void fillmap(LLSD& root, U32 width, U32 depth) + { + if(depth == 0) + { + root["foo"] = "bar"; + return; + } + + for(U32 i = 0; i < width; ++i) + { + std::string key = llformat("child %d", i); + root[key] = LLSD::emptyMap(); + fillmap(root[key], width, depth - 1); + } + } + + void TestLLSDSerializeData::doRoundTripTests(const std::string& msg) + { + LLSD v; + checkRoundTrip(msg + " undefined", v); + + v = true; + checkRoundTrip(msg + " true bool", v); + + v = false; + checkRoundTrip(msg + " false bool", v); + + v = 1; + checkRoundTrip(msg + " positive int", v); + + v = 0; + checkRoundTrip(msg + " zero int", v); + + v = -1; + checkRoundTrip(msg + " negative int", v); + + v = 1234.5f; + checkRoundTrip(msg + " positive float", v); + + v = 0.0f; + checkRoundTrip(msg + " zero float", v); + + v = -1234.5f; + checkRoundTrip(msg + " negative float", v); + + // FIXME: need a NaN test + + v = LLUUID::null; + checkRoundTrip(msg + " null uuid", v); + + LLUUID newUUID; + newUUID.generate(); + v = newUUID; + checkRoundTrip(msg + " new uuid", v); + + v = ""; + checkRoundTrip(msg + " empty string", v); + + v = "some string"; + checkRoundTrip(msg + " non-empty string", v); + + v = "Second Life is a 3-D virtual world entirely built and owned by its residents. " "Since opening to the public in 2003, it has grown explosively and today is " "inhabited by nearly 100,000 people from around the globe.\n" @@ -390,437 +390,437 @@ namespace tut "currency exchanges.\n" "\n" "Welcome to Second Life. We look forward to seeing you in-world!\n" - ; - checkRoundTrip(msg + " long string", v); - - static const U32 block_size = 0x000020; - for (U32 block = 0x000000; block <= 0x10ffff; block += block_size) - { - std::ostringstream out; - - for (U32 c = block; c < block + block_size; ++c) - { - if (c <= 0x000001f - && c != 0x000009 - && c != 0x00000a) - { - // see XML standard, sections 2.2 and 4.1 - continue; - } - if (0x00d800 <= c && c <= 0x00dfff) { continue; } - if (0x00fdd0 <= c && c <= 0x00fdef) { continue; } - if ((c & 0x00fffe) == 0x00fffe) { continue; } - // see Unicode standard, section 15.8 - - if (c <= 0x00007f) - { - out << (char)(c & 0x7f); - } - else if (c <= 0x0007ff) - { - out << (char)(0xc0 | ((c >> 6) & 0x1f)); - out << (char)(0x80 | ((c >> 0) & 0x3f)); - } - else if (c <= 0x00ffff) - { - out << (char)(0xe0 | ((c >> 12) & 0x0f)); - out << (char)(0x80 | ((c >> 6) & 0x3f)); - out << (char)(0x80 | ((c >> 0) & 0x3f)); - } - else - { - out << (char)(0xf0 | ((c >> 18) & 0x07)); - out << (char)(0x80 | ((c >> 12) & 0x3f)); - out << (char)(0x80 | ((c >> 6) & 0x3f)); - out << (char)(0x80 | ((c >> 0) & 0x3f)); - } - } - - v = out.str(); - - std::ostringstream blockmsg; - blockmsg << msg << " unicode string block 0x" << std::hex << block; - checkRoundTrip(blockmsg.str(), v); - } - - LLDate epoch; - v = epoch; - checkRoundTrip(msg + " epoch date", v); - - LLDate aDay("2002-12-07T05:07:15.00Z"); - v = aDay; - checkRoundTrip(msg + " date", v); - - LLURI path("http://slurl.com/secondlife/Ambleside/57/104/26/"); - v = path; - checkRoundTrip(msg + " url", v); - - const char source[] = "it must be a blue moon again"; - std::vector data; - // note, includes terminating '\0' - copy(&source[0], &source[sizeof(source)], back_inserter(data)); - - v = data; - checkRoundTrip(msg + " binary", v); - - v = LLSD::emptyMap(); - checkRoundTrip(msg + " empty map", v); - - v = LLSD::emptyMap(); - v["name"] = "luke"; //v.insert("name", "luke"); - v["age"] = 3; //v.insert("age", 3); - checkRoundTrip(msg + " map", v); - - v.clear(); - v["a"]["1"] = true; - v["b"]["0"] = false; - checkRoundTrip(msg + " nested maps", v); - - v = LLSD::emptyArray(); - checkRoundTrip(msg + " empty array", v); - - v = LLSD::emptyArray(); - v.append("ali"); - v.append(28); - checkRoundTrip(msg + " array", v); - - v.clear(); - v[0][0] = true; - v[1][0] = false; - checkRoundTrip(msg + " nested arrays", v); - - v = LLSD::emptyMap(); - fillmap(v, 10, 3); // 10^6 maps - checkRoundTrip(msg + " many nested maps", v); - } - - typedef tut::test_group TestLLSDSerializeGroup; - typedef TestLLSDSerializeGroup::object TestLLSDSerializeObject; - TestLLSDSerializeGroup gTestLLSDSerializeGroup("llsd serialization"); - - template<> template<> - void TestLLSDSerializeObject::test<1>() - { - setFormatterParser(new LLSDNotationFormatter(false, "", LLSDFormatter::OPTIONS_PRETTY_BINARY), - new LLSDNotationParser()); - doRoundTripTests("pretty binary notation serialization"); - } - - template<> template<> - void TestLLSDSerializeObject::test<2>() - { - setFormatterParser(new LLSDNotationFormatter(false, "", LLSDFormatter::OPTIONS_NONE), - new LLSDNotationParser()); - doRoundTripTests("raw binary notation serialization"); - } - - template<> template<> - void TestLLSDSerializeObject::test<3>() - { - setFormatterParser(new LLSDXMLFormatter(), new LLSDXMLParser()); - doRoundTripTests("xml serialization"); - } - - template<> template<> - void TestLLSDSerializeObject::test<4>() - { - setFormatterParser(new LLSDBinaryFormatter(), new LLSDBinaryParser()); - doRoundTripTests("binary serialization"); - } - - template<> template<> - void TestLLSDSerializeObject::test<5>() - { - mFormatter = [](const LLSD& sd, std::ostream& str) - { - LLSDSerialize::serialize(sd, str, LLSDSerialize::LLSD_BINARY); - }; - setParser(LLSDSerialize::deserialize); - doRoundTripTests("serialize(LLSD_BINARY)"); - }; - - template<> template<> - void TestLLSDSerializeObject::test<6>() - { - mFormatter = [](const LLSD& sd, std::ostream& str) - { - LLSDSerialize::serialize(sd, str, LLSDSerialize::LLSD_XML); - }; - setParser(LLSDSerialize::deserialize); - doRoundTripTests("serialize(LLSD_XML)"); - }; - - template<> template<> - void TestLLSDSerializeObject::test<7>() - { - mFormatter = [](const LLSD& sd, std::ostream& str) - { - LLSDSerialize::serialize(sd, str, LLSDSerialize::LLSD_NOTATION); - }; - setParser(LLSDSerialize::deserialize); - // In this test, serialize(LLSD_NOTATION) emits a header recognized by - // deserialize(). - doRoundTripTests("serialize(LLSD_NOTATION)"); - }; - - template<> template<> - void TestLLSDSerializeObject::test<8>() - { - setFormatterParser(new LLSDNotationFormatter(false, "", LLSDFormatter::OPTIONS_NONE), - new LLSDNotationParser()); - setParser(LLSDSerialize::deserialize); - // This is an interesting test because LLSDNotationFormatter does not - // emit an llsd/notation header. - doRoundTripTests("LLSDNotationFormatter -> deserialize"); - }; - - template<> template<> - void TestLLSDSerializeObject::test<9>() - { - setFormatterParser(new LLSDXMLFormatter(false, "", LLSDFormatter::OPTIONS_NONE), - new LLSDXMLParser()); - setParser(LLSDSerialize::deserialize); - // This is an interesting test because LLSDXMLFormatter does not - // emit an LLSD/XML header. - doRoundTripTests("LLSDXMLFormatter -> deserialize"); - }; + ; + checkRoundTrip(msg + " long string", v); + + static const U32 block_size = 0x000020; + for (U32 block = 0x000000; block <= 0x10ffff; block += block_size) + { + std::ostringstream out; + + for (U32 c = block; c < block + block_size; ++c) + { + if (c <= 0x000001f + && c != 0x000009 + && c != 0x00000a) + { + // see XML standard, sections 2.2 and 4.1 + continue; + } + if (0x00d800 <= c && c <= 0x00dfff) { continue; } + if (0x00fdd0 <= c && c <= 0x00fdef) { continue; } + if ((c & 0x00fffe) == 0x00fffe) { continue; } + // see Unicode standard, section 15.8 + + if (c <= 0x00007f) + { + out << (char)(c & 0x7f); + } + else if (c <= 0x0007ff) + { + out << (char)(0xc0 | ((c >> 6) & 0x1f)); + out << (char)(0x80 | ((c >> 0) & 0x3f)); + } + else if (c <= 0x00ffff) + { + out << (char)(0xe0 | ((c >> 12) & 0x0f)); + out << (char)(0x80 | ((c >> 6) & 0x3f)); + out << (char)(0x80 | ((c >> 0) & 0x3f)); + } + else + { + out << (char)(0xf0 | ((c >> 18) & 0x07)); + out << (char)(0x80 | ((c >> 12) & 0x3f)); + out << (char)(0x80 | ((c >> 6) & 0x3f)); + out << (char)(0x80 | ((c >> 0) & 0x3f)); + } + } + + v = out.str(); + + std::ostringstream blockmsg; + blockmsg << msg << " unicode string block 0x" << std::hex << block; + checkRoundTrip(blockmsg.str(), v); + } + + LLDate epoch; + v = epoch; + checkRoundTrip(msg + " epoch date", v); + + LLDate aDay("2002-12-07T05:07:15.00Z"); + v = aDay; + checkRoundTrip(msg + " date", v); + + LLURI path("http://slurl.com/secondlife/Ambleside/57/104/26/"); + v = path; + checkRoundTrip(msg + " url", v); + + const char source[] = "it must be a blue moon again"; + std::vector data; + // note, includes terminating '\0' + copy(&source[0], &source[sizeof(source)], back_inserter(data)); + + v = data; + checkRoundTrip(msg + " binary", v); + + v = LLSD::emptyMap(); + checkRoundTrip(msg + " empty map", v); + + v = LLSD::emptyMap(); + v["name"] = "luke"; //v.insert("name", "luke"); + v["age"] = 3; //v.insert("age", 3); + checkRoundTrip(msg + " map", v); + + v.clear(); + v["a"]["1"] = true; + v["b"]["0"] = false; + checkRoundTrip(msg + " nested maps", v); + + v = LLSD::emptyArray(); + checkRoundTrip(msg + " empty array", v); + + v = LLSD::emptyArray(); + v.append("ali"); + v.append(28); + checkRoundTrip(msg + " array", v); + + v.clear(); + v[0][0] = true; + v[1][0] = false; + checkRoundTrip(msg + " nested arrays", v); + + v = LLSD::emptyMap(); + fillmap(v, 10, 3); // 10^6 maps + checkRoundTrip(msg + " many nested maps", v); + } + + typedef tut::test_group TestLLSDSerializeGroup; + typedef TestLLSDSerializeGroup::object TestLLSDSerializeObject; + TestLLSDSerializeGroup gTestLLSDSerializeGroup("llsd serialization"); + + template<> template<> + void TestLLSDSerializeObject::test<1>() + { + setFormatterParser(new LLSDNotationFormatter(false, "", LLSDFormatter::OPTIONS_PRETTY_BINARY), + new LLSDNotationParser()); + doRoundTripTests("pretty binary notation serialization"); + } + + template<> template<> + void TestLLSDSerializeObject::test<2>() + { + setFormatterParser(new LLSDNotationFormatter(false, "", LLSDFormatter::OPTIONS_NONE), + new LLSDNotationParser()); + doRoundTripTests("raw binary notation serialization"); + } + + template<> template<> + void TestLLSDSerializeObject::test<3>() + { + setFormatterParser(new LLSDXMLFormatter(), new LLSDXMLParser()); + doRoundTripTests("xml serialization"); + } + + template<> template<> + void TestLLSDSerializeObject::test<4>() + { + setFormatterParser(new LLSDBinaryFormatter(), new LLSDBinaryParser()); + doRoundTripTests("binary serialization"); + } + + template<> template<> + void TestLLSDSerializeObject::test<5>() + { + mFormatter = [](const LLSD& sd, std::ostream& str) + { + LLSDSerialize::serialize(sd, str, LLSDSerialize::LLSD_BINARY); + }; + setParser(LLSDSerialize::deserialize); + doRoundTripTests("serialize(LLSD_BINARY)"); + }; + + template<> template<> + void TestLLSDSerializeObject::test<6>() + { + mFormatter = [](const LLSD& sd, std::ostream& str) + { + LLSDSerialize::serialize(sd, str, LLSDSerialize::LLSD_XML); + }; + setParser(LLSDSerialize::deserialize); + doRoundTripTests("serialize(LLSD_XML)"); + }; + + template<> template<> + void TestLLSDSerializeObject::test<7>() + { + mFormatter = [](const LLSD& sd, std::ostream& str) + { + LLSDSerialize::serialize(sd, str, LLSDSerialize::LLSD_NOTATION); + }; + setParser(LLSDSerialize::deserialize); + // In this test, serialize(LLSD_NOTATION) emits a header recognized by + // deserialize(). + doRoundTripTests("serialize(LLSD_NOTATION)"); + }; + + template<> template<> + void TestLLSDSerializeObject::test<8>() + { + setFormatterParser(new LLSDNotationFormatter(false, "", LLSDFormatter::OPTIONS_NONE), + new LLSDNotationParser()); + setParser(LLSDSerialize::deserialize); + // This is an interesting test because LLSDNotationFormatter does not + // emit an llsd/notation header. + doRoundTripTests("LLSDNotationFormatter -> deserialize"); + }; + + template<> template<> + void TestLLSDSerializeObject::test<9>() + { + setFormatterParser(new LLSDXMLFormatter(false, "", LLSDFormatter::OPTIONS_NONE), + new LLSDXMLParser()); + setParser(LLSDSerialize::deserialize); + // This is an interesting test because LLSDXMLFormatter does not + // emit an LLSD/XML header. + doRoundTripTests("LLSDXMLFormatter -> deserialize"); + }; /*==========================================================================*| - // We do not expect this test to succeed. Without a header, neither - // notation LLSD nor binary LLSD reliably start with a distinct character, - // the way XML LLSD starts with '<'. By convention, we default to notation - // rather than binary. - template<> template<> - void TestLLSDSerializeObject::test<10>() - { - setFormatterParser(new LLSDBinaryFormatter(false, "", LLSDFormatter::OPTIONS_NONE), - new LLSDBinaryParser()); - setParser(LLSDSerialize::deserialize); - // This is an interesting test because LLSDBinaryFormatter does not - // emit an LLSD/Binary header. - doRoundTripTests("LLSDBinaryFormatter -> deserialize"); - }; + // We do not expect this test to succeed. Without a header, neither + // notation LLSD nor binary LLSD reliably start with a distinct character, + // the way XML LLSD starts with '<'. By convention, we default to notation + // rather than binary. + template<> template<> + void TestLLSDSerializeObject::test<10>() + { + setFormatterParser(new LLSDBinaryFormatter(false, "", LLSDFormatter::OPTIONS_NONE), + new LLSDBinaryParser()); + setParser(LLSDSerialize::deserialize); + // This is an interesting test because LLSDBinaryFormatter does not + // emit an LLSD/Binary header. + doRoundTripTests("LLSDBinaryFormatter -> deserialize"); + }; |*==========================================================================*/ - /** - * @class TestLLSDParsing - * @brief Base class for of a parse tester. - */ - template - class TestLLSDParsing - { - public: - TestLLSDParsing() - { - mParser = new parser_t; - } - - void ensureParse( - const std::string& msg, - const std::string& in, - const LLSD& expected_value, - S32 expected_count, - S32 depth_limit = -1) - { - std::stringstream input; - input.str(in); - - LLSD parsed_result; - mParser->reset(); // reset() call is needed since test code re-uses mParser - S32 parsed_count = mParser->parse(input, parsed_result, in.size(), depth_limit); - ensure_equals(msg.c_str(), parsed_result, expected_value); - - // This count check is really only useful for expected - // parse failures, since the ensures equal will already - // require equality. - std::string count_msg(msg); - count_msg += " (count)"; - ensure_equals(count_msg, parsed_count, expected_count); - } - - LLPointer mParser; - }; - - - /** - * @class TestLLSDXMLParsing - * @brief Concrete instance of a parse tester. - */ - class TestLLSDXMLParsing : public TestLLSDParsing - { - public: - TestLLSDXMLParsing() {} - }; - - typedef tut::test_group TestLLSDXMLParsingGroup; - typedef TestLLSDXMLParsingGroup::object TestLLSDXMLParsingObject; - TestLLSDXMLParsingGroup gTestLLSDXMLParsingGroup("llsd XML parsing"); - - template<> template<> - void TestLLSDXMLParsingObject::test<1>() - { - // test handling of xml not recognized as llsd results in an - // LLSD Undefined - ensureParse( - "malformed xml", - "ha ha", - LLSD(), - LLSDParser::PARSE_FAILURE); - ensureParse( - "not llsd", - "

ha ha

", - LLSD(), - LLSDParser::PARSE_FAILURE); - ensureParse( - "value without llsd", - "ha ha", - LLSD(), - LLSDParser::PARSE_FAILURE); - ensureParse( - "key without llsd", - "ha ha", - LLSD(), - LLSDParser::PARSE_FAILURE); - } - - - template<> template<> - void TestLLSDXMLParsingObject::test<2>() - { - // test handling of unrecognized or unparseable llsd values - LLSD v; - v["amy"] = 23; - v["bob"] = LLSD(); - v["cam"] = 1.23; - - ensureParse( - "unknown data type", - "" - "amy23" - "bob99999999999999999" - "cam1.23" - "", - v, - v.size() + 1); - } - - template<> template<> - void TestLLSDXMLParsingObject::test<3>() - { - // test handling of nested bad data - - LLSD v; - v["amy"] = 23; - v["cam"] = 1.23; - - ensureParse( - "map with html", - "" - "amy23" - "ha ha" - "cam1.23" - "", - v, - v.size() + 1); - - v.clear(); - v["amy"] = 23; - v["cam"] = 1.23; - ensureParse( - "map with value for key", - "" - "amy23" - "ha ha" - "cam1.23" - "", - v, - v.size() + 1); - - v.clear(); - v["amy"] = 23; - v["bob"] = LLSD::emptyMap(); - v["cam"] = 1.23; - ensureParse( - "map with map of html", - "" - "amy23" - "bob" - "" - "ha ha" - "" - "cam1.23" - "", - v, - v.size() + 1); - - v.clear(); - v[0] = 23; - v[1] = LLSD(); - v[2] = 1.23; - - ensureParse( - "array value of html", - "" - "23" - "ha ha" - "1.23" - "", - v, - v.size() + 1); - - v.clear(); - v[0] = 23; - v[1] = LLSD::emptyMap(); - v[2] = 1.23; - ensureParse( - "array with map of html", - "" - "23" - "" - "ha ha" - "" - "1.23" - "", - v, - v.size() + 1); - } - - template<> template<> - void TestLLSDXMLParsingObject::test<4>() - { - // test handling of binary object in XML - std::string xml; - LLSD expected; - - // Generated by: echo -n 'hello' | openssl enc -e -base64 - expected = string_to_vector("hello"); - xml = "aGVsbG8=\n"; - ensureParse( - "the word 'hello' packed in binary encoded base64", - xml, - expected, - 1); - - expected = string_to_vector("6|6|asdfhappybox|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|00000000-0000-0000-0000-000000000000|7fffffff|7fffffff|0|0|82000|450fe394-2904-c9ad-214c-a07eb7feec29|(No Description)|0|10|0"); - xml = "Nnw2fGFzZGZoYXBweWJveHw2MGU0NGVjNS0zMDVjLTQzYzItOWExOS1iNGI4OWIxYWUyYTZ8NjBlNDRlYzUtMzA1Yy00M2MyLTlhMTktYjRiODliMWFlMmE2fDYwZTQ0ZWM1LTMwNWMtNDNjMi05YTE5LWI0Yjg5YjFhZTJhNnwwMDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDB8N2ZmZmZmZmZ8N2ZmZmZmZmZ8MHwwfDgyMDAwfDQ1MGZlMzk0LTI5MDQtYzlhZC0yMTRjLWEwN2ViN2ZlZWMyOXwoTm8gRGVzY3JpcHRpb24pfDB8MTB8MA==\n"; - ensureParse( - "a common binary blob for object -> agent offline inv transfer", - xml, - expected, - 1); - - expected = string_to_vector("6|6|asdfhappybox|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|00000000-0000-0000-0000-000000000000|7fffffff|7fffffff|0|0|82000|450fe394-2904-c9ad-214c-a07eb7feec29|(No Description)|0|10|0"); - xml = "Nnw2fGFzZGZoYXBweWJveHw2MGU0NGVjNS0zMDVjLTQzYzItOWExOS1iNGI4OWIxYWUyYTZ8NjBl\n"; - xml += "NDRlYzUtMzA1Yy00M2MyLTlhMTktYjRiODliMWFlMmE2fDYwZTQ0ZWM1LTMwNWMtNDNjMi05YTE5\n"; - xml += "LWI0Yjg5YjFhZTJhNnwwMDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDB8N2ZmZmZm\n"; - xml += "ZmZ8N2ZmZmZmZmZ8MHwwfDgyMDAwfDQ1MGZlMzk0LTI5MDQtYzlhZC0yMTRjLWEwN2ViN2ZlZWMy\n"; - xml += "OXwoTm8gRGVzY3JpcHRpb24pfDB8MTB8MA==\n"; - ensureParse( - "a common binary blob for object -> agent offline inv transfer", - xml, - expected, - 1); - } + /** + * @class TestLLSDParsing + * @brief Base class for of a parse tester. + */ + template + class TestLLSDParsing + { + public: + TestLLSDParsing() + { + mParser = new parser_t; + } + + void ensureParse( + const std::string& msg, + const std::string& in, + const LLSD& expected_value, + S32 expected_count, + S32 depth_limit = -1) + { + std::stringstream input; + input.str(in); + + LLSD parsed_result; + mParser->reset(); // reset() call is needed since test code re-uses mParser + S32 parsed_count = mParser->parse(input, parsed_result, in.size(), depth_limit); + ensure_equals(msg.c_str(), parsed_result, expected_value); + + // This count check is really only useful for expected + // parse failures, since the ensures equal will already + // require equality. + std::string count_msg(msg); + count_msg += " (count)"; + ensure_equals(count_msg, parsed_count, expected_count); + } + + LLPointer mParser; + }; + + + /** + * @class TestLLSDXMLParsing + * @brief Concrete instance of a parse tester. + */ + class TestLLSDXMLParsing : public TestLLSDParsing + { + public: + TestLLSDXMLParsing() {} + }; + + typedef tut::test_group TestLLSDXMLParsingGroup; + typedef TestLLSDXMLParsingGroup::object TestLLSDXMLParsingObject; + TestLLSDXMLParsingGroup gTestLLSDXMLParsingGroup("llsd XML parsing"); + + template<> template<> + void TestLLSDXMLParsingObject::test<1>() + { + // test handling of xml not recognized as llsd results in an + // LLSD Undefined + ensureParse( + "malformed xml", + "ha ha", + LLSD(), + LLSDParser::PARSE_FAILURE); + ensureParse( + "not llsd", + "

ha ha

", + LLSD(), + LLSDParser::PARSE_FAILURE); + ensureParse( + "value without llsd", + "ha ha", + LLSD(), + LLSDParser::PARSE_FAILURE); + ensureParse( + "key without llsd", + "ha ha", + LLSD(), + LLSDParser::PARSE_FAILURE); + } + + + template<> template<> + void TestLLSDXMLParsingObject::test<2>() + { + // test handling of unrecognized or unparseable llsd values + LLSD v; + v["amy"] = 23; + v["bob"] = LLSD(); + v["cam"] = 1.23; + + ensureParse( + "unknown data type", + "" + "amy23" + "bob99999999999999999" + "cam1.23" + "", + v, + v.size() + 1); + } + + template<> template<> + void TestLLSDXMLParsingObject::test<3>() + { + // test handling of nested bad data + + LLSD v; + v["amy"] = 23; + v["cam"] = 1.23; + + ensureParse( + "map with html", + "" + "amy23" + "ha ha" + "cam1.23" + "", + v, + v.size() + 1); + + v.clear(); + v["amy"] = 23; + v["cam"] = 1.23; + ensureParse( + "map with value for key", + "" + "amy23" + "ha ha" + "cam1.23" + "", + v, + v.size() + 1); + + v.clear(); + v["amy"] = 23; + v["bob"] = LLSD::emptyMap(); + v["cam"] = 1.23; + ensureParse( + "map with map of html", + "" + "amy23" + "bob" + "" + "ha ha" + "" + "cam1.23" + "", + v, + v.size() + 1); + + v.clear(); + v[0] = 23; + v[1] = LLSD(); + v[2] = 1.23; + + ensureParse( + "array value of html", + "" + "23" + "ha ha" + "1.23" + "", + v, + v.size() + 1); + + v.clear(); + v[0] = 23; + v[1] = LLSD::emptyMap(); + v[2] = 1.23; + ensureParse( + "array with map of html", + "" + "23" + "" + "ha ha" + "" + "1.23" + "", + v, + v.size() + 1); + } + + template<> template<> + void TestLLSDXMLParsingObject::test<4>() + { + // test handling of binary object in XML + std::string xml; + LLSD expected; + + // Generated by: echo -n 'hello' | openssl enc -e -base64 + expected = string_to_vector("hello"); + xml = "aGVsbG8=\n"; + ensureParse( + "the word 'hello' packed in binary encoded base64", + xml, + expected, + 1); + + expected = string_to_vector("6|6|asdfhappybox|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|00000000-0000-0000-0000-000000000000|7fffffff|7fffffff|0|0|82000|450fe394-2904-c9ad-214c-a07eb7feec29|(No Description)|0|10|0"); + xml = "Nnw2fGFzZGZoYXBweWJveHw2MGU0NGVjNS0zMDVjLTQzYzItOWExOS1iNGI4OWIxYWUyYTZ8NjBlNDRlYzUtMzA1Yy00M2MyLTlhMTktYjRiODliMWFlMmE2fDYwZTQ0ZWM1LTMwNWMtNDNjMi05YTE5LWI0Yjg5YjFhZTJhNnwwMDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDB8N2ZmZmZmZmZ8N2ZmZmZmZmZ8MHwwfDgyMDAwfDQ1MGZlMzk0LTI5MDQtYzlhZC0yMTRjLWEwN2ViN2ZlZWMyOXwoTm8gRGVzY3JpcHRpb24pfDB8MTB8MA==\n"; + ensureParse( + "a common binary blob for object -> agent offline inv transfer", + xml, + expected, + 1); + + expected = string_to_vector("6|6|asdfhappybox|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|60e44ec5-305c-43c2-9a19-b4b89b1ae2a6|00000000-0000-0000-0000-000000000000|7fffffff|7fffffff|0|0|82000|450fe394-2904-c9ad-214c-a07eb7feec29|(No Description)|0|10|0"); + xml = "Nnw2fGFzZGZoYXBweWJveHw2MGU0NGVjNS0zMDVjLTQzYzItOWExOS1iNGI4OWIxYWUyYTZ8NjBl\n"; + xml += "NDRlYzUtMzA1Yy00M2MyLTlhMTktYjRiODliMWFlMmE2fDYwZTQ0ZWM1LTMwNWMtNDNjMi05YTE5\n"; + xml += "LWI0Yjg5YjFhZTJhNnwwMDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDB8N2ZmZmZm\n"; + xml += "ZmZ8N2ZmZmZmZmZ8MHwwfDgyMDAwfDQ1MGZlMzk0LTI5MDQtYzlhZC0yMTRjLWEwN2ViN2ZlZWMy\n"; + xml += "OXwoTm8gRGVzY3JpcHRpb24pfDB8MTB8MA==\n"; + ensureParse( + "a common binary blob for object -> agent offline inv transfer", + xml, + expected, + 1); + } template<> template<> void TestLLSDXMLParsingObject::test<5>() @@ -858,272 +858,272 @@ namespace tut } - /* - TODO: - test XML parsing - binary with unrecognized encoding - nested LLSD tags - multiple values inside an LLSD - */ - - - /** - * @class TestLLSDNotationParsing - * @brief Concrete instance of a parse tester. - */ - class TestLLSDNotationParsing : public TestLLSDParsing - { - public: - TestLLSDNotationParsing() {} - }; - - typedef tut::test_group TestLLSDNotationParsingGroup; - typedef TestLLSDNotationParsingGroup::object TestLLSDNotationParsingObject; - TestLLSDNotationParsingGroup gTestLLSDNotationParsingGroup( - "llsd notation parsing"); - - template<> template<> - void TestLLSDNotationParsingObject::test<1>() - { - // test handling of xml not recognized as llsd results in an - // LLSD Undefined - ensureParse( - "malformed notation map", - "{'ha ha'", - LLSD(), - LLSDParser::PARSE_FAILURE); - ensureParse( - "malformed notation array", - "['ha ha'", - LLSD(), - LLSDParser::PARSE_FAILURE); - ensureParse( - "malformed notation string", - "'ha ha", - LLSD(), - LLSDParser::PARSE_FAILURE); - ensureParse( - "bad notation noise", - "g48ejlnfr", - LLSD(), - LLSDParser::PARSE_FAILURE); - } - - template<> template<> - void TestLLSDNotationParsingObject::test<2>() - { - ensureParse("valid undef", "!", LLSD(), 1); - } - - template<> template<> - void TestLLSDNotationParsingObject::test<3>() - { - LLSD val = false; - ensureParse("valid boolean false 0", "false", val, 1); - ensureParse("valid boolean false 1", "f", val, 1); - ensureParse("valid boolean false 2", "0", val, 1); - ensureParse("valid boolean false 3", "F", val, 1); - ensureParse("valid boolean false 4", "FALSE", val, 1); - val = true; - ensureParse("valid boolean true 0", "true", val, 1); - ensureParse("valid boolean true 1", "t", val, 1); - ensureParse("valid boolean true 2", "1", val, 1); - ensureParse("valid boolean true 3", "T", val, 1); - ensureParse("valid boolean true 4", "TRUE", val, 1); - - val.clear(); - ensureParse("invalid true", "TR", val, LLSDParser::PARSE_FAILURE); - ensureParse("invalid false", "FAL", val, LLSDParser::PARSE_FAILURE); - } - - template<> template<> - void TestLLSDNotationParsingObject::test<4>() - { - LLSD val = 123; - ensureParse("valid integer", "i123", val, 1); - val.clear(); - ensureParse("invalid integer", "421", val, LLSDParser::PARSE_FAILURE); - } - - template<> template<> - void TestLLSDNotationParsingObject::test<5>() - { - LLSD val = 456.7; - ensureParse("valid real", "r456.7", val, 1); - val.clear(); - ensureParse("invalid real", "456.7", val, LLSDParser::PARSE_FAILURE); - } - - template<> template<> - void TestLLSDNotationParsingObject::test<6>() - { - LLUUID id; - LLSD val = id; - ensureParse( - "unparseable uuid", - "u123", - LLSD(), - LLSDParser::PARSE_FAILURE); - id.generate(); - val = id; - std::string uuid_str("u"); - uuid_str += id.asString(); - ensureParse("valid uuid", uuid_str.c_str(), val, 1); - } - - template<> template<> - void TestLLSDNotationParsingObject::test<7>() - { - LLSD val = std::string("foolish"); - ensureParse("valid string 1", "\"foolish\"", val, 1); - val = std::string("g'day"); - ensureParse("valid string 2", "\"g'day\"", val, 1); - val = std::string("have a \"nice\" day"); - ensureParse("valid string 3", "'have a \"nice\" day'", val, 1); - val = std::string("whatever"); - ensureParse("valid string 4", "s(8)\"whatever\"", val, 1); - } - - template<> template<> - void TestLLSDNotationParsingObject::test<8>() - { - ensureParse( - "invalid string 1", - "s(7)\"whatever\"", - LLSD(), - LLSDParser::PARSE_FAILURE); - ensureParse( - "invalid string 2", - "s(9)\"whatever\"", - LLSD(), - LLSDParser::PARSE_FAILURE); - } - - template<> template<> - void TestLLSDNotationParsingObject::test<9>() - { - LLSD val = LLURI("http://www.google.com"); - ensureParse("valid uri", "l\"http://www.google.com\"", val, 1); - } - - template<> template<> - void TestLLSDNotationParsingObject::test<10>() - { - LLSD val = LLDate("2007-12-28T09:22:53.10Z"); - ensureParse("valid date", "d\"2007-12-28T09:22:53.10Z\"", val, 1); - } - - template<> template<> - void TestLLSDNotationParsingObject::test<11>() - { - std::vector vec; - vec.push_back((U8)'a'); vec.push_back((U8)'b'); vec.push_back((U8)'c'); - vec.push_back((U8)'3'); vec.push_back((U8)'2'); vec.push_back((U8)'1'); - LLSD val = vec; - ensureParse("valid binary b64", "b64\"YWJjMzIx\"", val, 1); - ensureParse("valid bainry b16", "b16\"616263333231\"", val, 1); - ensureParse("valid bainry raw", "b(6)\"abc321\"", val, 1); - } - - template<> template<> - void TestLLSDNotationParsingObject::test<12>() - { - ensureParse( - "invalid -- binary length specified too long", - "b(7)\"abc321\"", - LLSD(), - LLSDParser::PARSE_FAILURE); - ensureParse( - "invalid -- binary length specified way too long", - "b(1000000)\"abc321\"", - LLSD(), - LLSDParser::PARSE_FAILURE); - } - - template<> template<> - void TestLLSDNotationParsingObject::test<13>() - { - LLSD val; - val["amy"] = 23; - val["bob"] = LLSD(); - val["cam"] = 1.23; - ensureParse("simple map", "{'amy':i23,'bob':!,'cam':r1.23}", val, 4); - - val["bob"] = LLSD::emptyMap(); - val["bob"]["vehicle"] = std::string("bicycle"); - ensureParse( - "nested map", - "{'amy':i23,'bob':{'vehicle':'bicycle'},'cam':r1.23}", - val, - 5); - } - - template<> template<> - void TestLLSDNotationParsingObject::test<14>() - { - LLSD val; - val.append(23); - val.append(LLSD()); - val.append(1.23); - ensureParse("simple array", "[i23,!,r1.23]", val, 4); - val[1] = LLSD::emptyArray(); - val[1].append("bicycle"); - ensureParse("nested array", "[i23,['bicycle'],r1.23]", val, 5); - } - - template<> template<> - void TestLLSDNotationParsingObject::test<15>() - { - LLSD val; - val["amy"] = 23; - val["bob"]["dogs"] = LLSD::emptyArray(); - val["bob"]["dogs"].append(LLSD::emptyMap()); - val["bob"]["dogs"][0]["name"] = std::string("groove"); - val["bob"]["dogs"][0]["breed"] = std::string("samoyed"); - val["bob"]["dogs"].append(LLSD::emptyMap()); - val["bob"]["dogs"][1]["name"] = std::string("greyley"); - val["bob"]["dogs"][1]["breed"] = std::string("chow/husky"); - val["cam"] = 1.23; - ensureParse( - "nested notation", - "{'amy':i23," - " 'bob':{'dogs':[" - "{'name':'groove', 'breed':'samoyed'}," - "{'name':'greyley', 'breed':'chow/husky'}]}," - " 'cam':r1.23}", - val, - 11); - } - - template<> template<> - void TestLLSDNotationParsingObject::test<16>() - { - // text to make sure that incorrect sizes bail because - std::string bad_str("s(5)\"hi\""); - ensureParse( - "size longer than bytes left", - bad_str, - LLSD(), - LLSDParser::PARSE_FAILURE); - } - - template<> template<> - void TestLLSDNotationParsingObject::test<17>() - { - // text to make sure that incorrect sizes bail because - std::string bad_bin("b(5)\"hi\""); - ensureParse( - "size longer than bytes left", - bad_bin, - LLSD(), - LLSDParser::PARSE_FAILURE); - } + /* + TODO: + test XML parsing + binary with unrecognized encoding + nested LLSD tags + multiple values inside an LLSD + */ + + + /** + * @class TestLLSDNotationParsing + * @brief Concrete instance of a parse tester. + */ + class TestLLSDNotationParsing : public TestLLSDParsing + { + public: + TestLLSDNotationParsing() {} + }; + + typedef tut::test_group TestLLSDNotationParsingGroup; + typedef TestLLSDNotationParsingGroup::object TestLLSDNotationParsingObject; + TestLLSDNotationParsingGroup gTestLLSDNotationParsingGroup( + "llsd notation parsing"); + + template<> template<> + void TestLLSDNotationParsingObject::test<1>() + { + // test handling of xml not recognized as llsd results in an + // LLSD Undefined + ensureParse( + "malformed notation map", + "{'ha ha'", + LLSD(), + LLSDParser::PARSE_FAILURE); + ensureParse( + "malformed notation array", + "['ha ha'", + LLSD(), + LLSDParser::PARSE_FAILURE); + ensureParse( + "malformed notation string", + "'ha ha", + LLSD(), + LLSDParser::PARSE_FAILURE); + ensureParse( + "bad notation noise", + "g48ejlnfr", + LLSD(), + LLSDParser::PARSE_FAILURE); + } + + template<> template<> + void TestLLSDNotationParsingObject::test<2>() + { + ensureParse("valid undef", "!", LLSD(), 1); + } + + template<> template<> + void TestLLSDNotationParsingObject::test<3>() + { + LLSD val = false; + ensureParse("valid boolean false 0", "false", val, 1); + ensureParse("valid boolean false 1", "f", val, 1); + ensureParse("valid boolean false 2", "0", val, 1); + ensureParse("valid boolean false 3", "F", val, 1); + ensureParse("valid boolean false 4", "FALSE", val, 1); + val = true; + ensureParse("valid boolean true 0", "true", val, 1); + ensureParse("valid boolean true 1", "t", val, 1); + ensureParse("valid boolean true 2", "1", val, 1); + ensureParse("valid boolean true 3", "T", val, 1); + ensureParse("valid boolean true 4", "TRUE", val, 1); + + val.clear(); + ensureParse("invalid true", "TR", val, LLSDParser::PARSE_FAILURE); + ensureParse("invalid false", "FAL", val, LLSDParser::PARSE_FAILURE); + } + + template<> template<> + void TestLLSDNotationParsingObject::test<4>() + { + LLSD val = 123; + ensureParse("valid integer", "i123", val, 1); + val.clear(); + ensureParse("invalid integer", "421", val, LLSDParser::PARSE_FAILURE); + } + + template<> template<> + void TestLLSDNotationParsingObject::test<5>() + { + LLSD val = 456.7; + ensureParse("valid real", "r456.7", val, 1); + val.clear(); + ensureParse("invalid real", "456.7", val, LLSDParser::PARSE_FAILURE); + } + + template<> template<> + void TestLLSDNotationParsingObject::test<6>() + { + LLUUID id; + LLSD val = id; + ensureParse( + "unparseable uuid", + "u123", + LLSD(), + LLSDParser::PARSE_FAILURE); + id.generate(); + val = id; + std::string uuid_str("u"); + uuid_str += id.asString(); + ensureParse("valid uuid", uuid_str.c_str(), val, 1); + } + + template<> template<> + void TestLLSDNotationParsingObject::test<7>() + { + LLSD val = std::string("foolish"); + ensureParse("valid string 1", "\"foolish\"", val, 1); + val = std::string("g'day"); + ensureParse("valid string 2", "\"g'day\"", val, 1); + val = std::string("have a \"nice\" day"); + ensureParse("valid string 3", "'have a \"nice\" day'", val, 1); + val = std::string("whatever"); + ensureParse("valid string 4", "s(8)\"whatever\"", val, 1); + } + + template<> template<> + void TestLLSDNotationParsingObject::test<8>() + { + ensureParse( + "invalid string 1", + "s(7)\"whatever\"", + LLSD(), + LLSDParser::PARSE_FAILURE); + ensureParse( + "invalid string 2", + "s(9)\"whatever\"", + LLSD(), + LLSDParser::PARSE_FAILURE); + } + + template<> template<> + void TestLLSDNotationParsingObject::test<9>() + { + LLSD val = LLURI("http://www.google.com"); + ensureParse("valid uri", "l\"http://www.google.com\"", val, 1); + } + + template<> template<> + void TestLLSDNotationParsingObject::test<10>() + { + LLSD val = LLDate("2007-12-28T09:22:53.10Z"); + ensureParse("valid date", "d\"2007-12-28T09:22:53.10Z\"", val, 1); + } + + template<> template<> + void TestLLSDNotationParsingObject::test<11>() + { + std::vector vec; + vec.push_back((U8)'a'); vec.push_back((U8)'b'); vec.push_back((U8)'c'); + vec.push_back((U8)'3'); vec.push_back((U8)'2'); vec.push_back((U8)'1'); + LLSD val = vec; + ensureParse("valid binary b64", "b64\"YWJjMzIx\"", val, 1); + ensureParse("valid bainry b16", "b16\"616263333231\"", val, 1); + ensureParse("valid bainry raw", "b(6)\"abc321\"", val, 1); + } + + template<> template<> + void TestLLSDNotationParsingObject::test<12>() + { + ensureParse( + "invalid -- binary length specified too long", + "b(7)\"abc321\"", + LLSD(), + LLSDParser::PARSE_FAILURE); + ensureParse( + "invalid -- binary length specified way too long", + "b(1000000)\"abc321\"", + LLSD(), + LLSDParser::PARSE_FAILURE); + } + + template<> template<> + void TestLLSDNotationParsingObject::test<13>() + { + LLSD val; + val["amy"] = 23; + val["bob"] = LLSD(); + val["cam"] = 1.23; + ensureParse("simple map", "{'amy':i23,'bob':!,'cam':r1.23}", val, 4); + + val["bob"] = LLSD::emptyMap(); + val["bob"]["vehicle"] = std::string("bicycle"); + ensureParse( + "nested map", + "{'amy':i23,'bob':{'vehicle':'bicycle'},'cam':r1.23}", + val, + 5); + } + + template<> template<> + void TestLLSDNotationParsingObject::test<14>() + { + LLSD val; + val.append(23); + val.append(LLSD()); + val.append(1.23); + ensureParse("simple array", "[i23,!,r1.23]", val, 4); + val[1] = LLSD::emptyArray(); + val[1].append("bicycle"); + ensureParse("nested array", "[i23,['bicycle'],r1.23]", val, 5); + } + + template<> template<> + void TestLLSDNotationParsingObject::test<15>() + { + LLSD val; + val["amy"] = 23; + val["bob"]["dogs"] = LLSD::emptyArray(); + val["bob"]["dogs"].append(LLSD::emptyMap()); + val["bob"]["dogs"][0]["name"] = std::string("groove"); + val["bob"]["dogs"][0]["breed"] = std::string("samoyed"); + val["bob"]["dogs"].append(LLSD::emptyMap()); + val["bob"]["dogs"][1]["name"] = std::string("greyley"); + val["bob"]["dogs"][1]["breed"] = std::string("chow/husky"); + val["cam"] = 1.23; + ensureParse( + "nested notation", + "{'amy':i23," + " 'bob':{'dogs':[" + "{'name':'groove', 'breed':'samoyed'}," + "{'name':'greyley', 'breed':'chow/husky'}]}," + " 'cam':r1.23}", + val, + 11); + } + + template<> template<> + void TestLLSDNotationParsingObject::test<16>() + { + // text to make sure that incorrect sizes bail because + std::string bad_str("s(5)\"hi\""); + ensureParse( + "size longer than bytes left", + bad_str, + LLSD(), + LLSDParser::PARSE_FAILURE); + } + + template<> template<> + void TestLLSDNotationParsingObject::test<17>() + { + // text to make sure that incorrect sizes bail because + std::string bad_bin("b(5)\"hi\""); + ensureParse( + "size longer than bytes left", + bad_bin, + LLSD(), + LLSDParser::PARSE_FAILURE); + } template<> template<> void TestLLSDNotationParsingObject::test<18>() { - LLSD level_1 = LLSD::emptyMap(); level_1["level_2"] = 99; - LLSD level_0 = LLSD::emptyMap(); level_0["level_1"] = level_1; + LLSD level_1 = LLSD::emptyMap(); level_1["level_2"] = 99; + LLSD level_0 = LLSD::emptyMap(); level_0["level_1"] = level_1; LLSD deep = LLSD::emptyMap(); deep["level_0"] = level_0; @@ -1168,7 +1168,7 @@ namespace tut template<> template<> void TestLLSDNotationParsingObject::test<20>() { - LLSD end = LLSD::emptyMap(); end["end"] = (S32)99; + LLSD end = LLSD::emptyMap(); end["end"] = (S32)99; LLSD level_49 = LLSD::emptyMap(); level_49["level_49"] = end; LLSD level_48 = LLSD::emptyMap(); level_48["level_48"] = level_49; @@ -1259,536 +1259,536 @@ namespace tut 9); } - /** - * @class TestLLSDBinaryParsing - * @brief Concrete instance of a parse tester. - */ - class TestLLSDBinaryParsing : public TestLLSDParsing - { - public: - TestLLSDBinaryParsing() {} - }; - - typedef tut::test_group TestLLSDBinaryParsingGroup; - typedef TestLLSDBinaryParsingGroup::object TestLLSDBinaryParsingObject; - TestLLSDBinaryParsingGroup gTestLLSDBinaryParsingGroup( - "llsd binary parsing"); - - template<> template<> - void TestLLSDBinaryParsingObject::test<1>() - { - std::vector vec; - vec.resize(6); - vec[0] = 'a'; vec[1] = 'b'; vec[2] = 'c'; - vec[3] = '3'; vec[4] = '2'; vec[5] = '1'; - std::string string_expected((char*)&vec[0], vec.size()); - LLSD value = string_expected; - - vec.resize(11); - vec[0] = 's'; // for string - vec[5] = 'a'; vec[6] = 'b'; vec[7] = 'c'; - vec[8] = '3'; vec[9] = '2'; vec[10] = '1'; - - uint32_t size = htonl(6); - memcpy(&vec[1], &size, sizeof(uint32_t)); - std::string str_good((char*)&vec[0], vec.size()); - ensureParse("correct string parse", str_good, value, 1); - - size = htonl(7); - memcpy(&vec[1], &size, sizeof(uint32_t)); - std::string str_bad_1((char*)&vec[0], vec.size()); - ensureParse( - "incorrect size string parse", - str_bad_1, - LLSD(), - LLSDParser::PARSE_FAILURE); - - size = htonl(100000); - memcpy(&vec[1], &size, sizeof(uint32_t)); - std::string str_bad_2((char*)&vec[0], vec.size()); - ensureParse( - "incorrect size string parse", - str_bad_2, - LLSD(), - LLSDParser::PARSE_FAILURE); - } - - template<> template<> - void TestLLSDBinaryParsingObject::test<2>() - { - std::vector vec; - vec.resize(6); - vec[0] = 'a'; vec[1] = 'b'; vec[2] = 'c'; - vec[3] = '3'; vec[4] = '2'; vec[5] = '1'; - LLSD value = vec; - - vec.resize(11); - vec[0] = 'b'; // for binary - vec[5] = 'a'; vec[6] = 'b'; vec[7] = 'c'; - vec[8] = '3'; vec[9] = '2'; vec[10] = '1'; - - uint32_t size = htonl(6); - memcpy(&vec[1], &size, sizeof(uint32_t)); - std::string str_good((char*)&vec[0], vec.size()); - ensureParse("correct binary parse", str_good, value, 1); - - size = htonl(7); - memcpy(&vec[1], &size, sizeof(uint32_t)); - std::string str_bad_1((char*)&vec[0], vec.size()); - ensureParse( - "incorrect size binary parse 1", - str_bad_1, - LLSD(), - LLSDParser::PARSE_FAILURE); - - size = htonl(100000); - memcpy(&vec[1], &size, sizeof(uint32_t)); - std::string str_bad_2((char*)&vec[0], vec.size()); - ensureParse( - "incorrect size binary parse 2", - str_bad_2, - LLSD(), - LLSDParser::PARSE_FAILURE); - } - - template<> template<> - void TestLLSDBinaryParsingObject::test<3>() - { - // test handling of xml not recognized as llsd results in an - // LLSD Undefined - ensureParse( - "malformed binary map", - "{'ha ha'", - LLSD(), - LLSDParser::PARSE_FAILURE); - ensureParse( - "malformed binary array", - "['ha ha'", - LLSD(), - LLSDParser::PARSE_FAILURE); - ensureParse( - "malformed binary string", - "'ha ha", - LLSD(), - LLSDParser::PARSE_FAILURE); - ensureParse( - "bad noise", - "g48ejlnfr", - LLSD(), - LLSDParser::PARSE_FAILURE); - } - template<> template<> - void TestLLSDBinaryParsingObject::test<4>() - { - ensureParse("valid undef", "!", LLSD(), 1); - } - - template<> template<> - void TestLLSDBinaryParsingObject::test<5>() - { - LLSD val = false; - ensureParse("valid boolean false 2", "0", val, 1); - val = true; - ensureParse("valid boolean true 2", "1", val, 1); - - val.clear(); - ensureParse("invalid true", "t", val, LLSDParser::PARSE_FAILURE); - ensureParse("invalid false", "f", val, LLSDParser::PARSE_FAILURE); - } - - template<> template<> - void TestLLSDBinaryParsingObject::test<6>() - { - std::vector vec; - vec.push_back('{'); - vec.resize(vec.size() + 4); - uint32_t size = htonl(1); - memcpy(&vec[1], &size, sizeof(uint32_t)); - vec.push_back('k'); - int key_size_loc = vec.size(); - size = htonl(1); // 1 too short - vec.resize(vec.size() + 4); - memcpy(&vec[key_size_loc], &size, sizeof(uint32_t)); - vec.push_back('a'); vec.push_back('m'); vec.push_back('y'); - vec.push_back('i'); - int integer_loc = vec.size(); - vec.resize(vec.size() + 4); - uint32_t val_int = htonl(23); - memcpy(&vec[integer_loc], &val_int, sizeof(uint32_t)); - std::string str_bad_1((char*)&vec[0], vec.size()); - ensureParse( - "invalid key size", - str_bad_1, - LLSD(), - LLSDParser::PARSE_FAILURE); - - // check with correct size, but unterminated map (missing '}') - size = htonl(3); // correct size - memcpy(&vec[key_size_loc], &size, sizeof(uint32_t)); - std::string str_bad_2((char*)&vec[0], vec.size()); - ensureParse( - "valid key size, unterminated map", - str_bad_2, - LLSD(), - LLSDParser::PARSE_FAILURE); - - // check w/ correct size and correct map termination - LLSD val; - val["amy"] = 23; - vec.push_back('}'); - std::string str_good((char*)&vec[0], vec.size()); - ensureParse( - "valid map", - str_good, - val, - 2); - - // check w/ incorrect sizes and correct map termination - size = htonl(0); // 1 too few (for the map entry) - memcpy(&vec[1], &size, sizeof(uint32_t)); - std::string str_bad_3((char*)&vec[0], vec.size()); - ensureParse( - "invalid map too long", - str_bad_3, - LLSD(), - LLSDParser::PARSE_FAILURE); - - size = htonl(2); // 1 too many - memcpy(&vec[1], &size, sizeof(uint32_t)); - std::string str_bad_4((char*)&vec[0], vec.size()); - ensureParse( - "invalid map too short", - str_bad_4, - LLSD(), - LLSDParser::PARSE_FAILURE); - } - - template<> template<> - void TestLLSDBinaryParsingObject::test<7>() - { - std::vector vec; - vec.push_back('['); - vec.resize(vec.size() + 4); - uint32_t size = htonl(1); // 1 too short - memcpy(&vec[1], &size, sizeof(uint32_t)); - vec.push_back('"'); vec.push_back('a'); vec.push_back('m'); - vec.push_back('y'); vec.push_back('"'); vec.push_back('i'); - int integer_loc = vec.size(); - vec.resize(vec.size() + 4); - uint32_t val_int = htonl(23); - memcpy(&vec[integer_loc], &val_int, sizeof(uint32_t)); - - std::string str_bad_1((char*)&vec[0], vec.size()); - ensureParse( - "invalid array size", - str_bad_1, - LLSD(), - LLSDParser::PARSE_FAILURE); - - // check with correct size, but unterminated map (missing ']') - size = htonl(2); // correct size - memcpy(&vec[1], &size, sizeof(uint32_t)); - std::string str_bad_2((char*)&vec[0], vec.size()); - ensureParse( - "unterminated array", - str_bad_2, - LLSD(), - LLSDParser::PARSE_FAILURE); - - // check w/ correct size and correct map termination - LLSD val; - val.append("amy"); - val.append(23); - vec.push_back(']'); - std::string str_good((char*)&vec[0], vec.size()); - ensureParse( - "valid array", - str_good, - val, - 3); - - // check with too many elements - size = htonl(3); // 1 too long - memcpy(&vec[1], &size, sizeof(uint32_t)); - std::string str_bad_3((char*)&vec[0], vec.size()); - ensureParse( - "array too short", - str_bad_3, - LLSD(), - LLSDParser::PARSE_FAILURE); - } - - template<> template<> - void TestLLSDBinaryParsingObject::test<8>() - { - std::vector vec; - vec.push_back('{'); - vec.resize(vec.size() + 4); - memset(&vec[1], 0, 4); - vec.push_back('}'); - std::string str_good((char*)&vec[0], vec.size()); - LLSD val = LLSD::emptyMap(); - ensureParse( - "empty map", - str_good, - val, - 1); - } - - template<> template<> - void TestLLSDBinaryParsingObject::test<9>() - { - std::vector vec; - vec.push_back('['); - vec.resize(vec.size() + 4); - memset(&vec[1], 0, 4); - vec.push_back(']'); - std::string str_good((char*)&vec[0], vec.size()); - LLSD val = LLSD::emptyArray(); - ensureParse( - "empty array", - str_good, - val, - 1); - } - - template<> template<> - void TestLLSDBinaryParsingObject::test<10>() - { - std::vector vec; - vec.push_back('l'); - vec.resize(vec.size() + 4); - uint32_t size = htonl(14); // 1 too long - memcpy(&vec[1], &size, sizeof(uint32_t)); - vec.push_back('h'); vec.push_back('t'); vec.push_back('t'); - vec.push_back('p'); vec.push_back(':'); vec.push_back('/'); - vec.push_back('/'); vec.push_back('s'); vec.push_back('l'); - vec.push_back('.'); vec.push_back('c'); vec.push_back('o'); - vec.push_back('m'); - std::string str_bad((char*)&vec[0], vec.size()); - ensureParse( - "invalid uri length size", - str_bad, - LLSD(), - LLSDParser::PARSE_FAILURE); - - LLSD val; - val = LLURI("http://sl.com"); - size = htonl(13); // correct length - memcpy(&vec[1], &size, sizeof(uint32_t)); - std::string str_good((char*)&vec[0], vec.size()); - ensureParse( - "valid key size", - str_good, - val, - 1); - } + /** + * @class TestLLSDBinaryParsing + * @brief Concrete instance of a parse tester. + */ + class TestLLSDBinaryParsing : public TestLLSDParsing + { + public: + TestLLSDBinaryParsing() {} + }; + + typedef tut::test_group TestLLSDBinaryParsingGroup; + typedef TestLLSDBinaryParsingGroup::object TestLLSDBinaryParsingObject; + TestLLSDBinaryParsingGroup gTestLLSDBinaryParsingGroup( + "llsd binary parsing"); + + template<> template<> + void TestLLSDBinaryParsingObject::test<1>() + { + std::vector vec; + vec.resize(6); + vec[0] = 'a'; vec[1] = 'b'; vec[2] = 'c'; + vec[3] = '3'; vec[4] = '2'; vec[5] = '1'; + std::string string_expected((char*)&vec[0], vec.size()); + LLSD value = string_expected; + + vec.resize(11); + vec[0] = 's'; // for string + vec[5] = 'a'; vec[6] = 'b'; vec[7] = 'c'; + vec[8] = '3'; vec[9] = '2'; vec[10] = '1'; + + uint32_t size = htonl(6); + memcpy(&vec[1], &size, sizeof(uint32_t)); + std::string str_good((char*)&vec[0], vec.size()); + ensureParse("correct string parse", str_good, value, 1); + + size = htonl(7); + memcpy(&vec[1], &size, sizeof(uint32_t)); + std::string str_bad_1((char*)&vec[0], vec.size()); + ensureParse( + "incorrect size string parse", + str_bad_1, + LLSD(), + LLSDParser::PARSE_FAILURE); + + size = htonl(100000); + memcpy(&vec[1], &size, sizeof(uint32_t)); + std::string str_bad_2((char*)&vec[0], vec.size()); + ensureParse( + "incorrect size string parse", + str_bad_2, + LLSD(), + LLSDParser::PARSE_FAILURE); + } + + template<> template<> + void TestLLSDBinaryParsingObject::test<2>() + { + std::vector vec; + vec.resize(6); + vec[0] = 'a'; vec[1] = 'b'; vec[2] = 'c'; + vec[3] = '3'; vec[4] = '2'; vec[5] = '1'; + LLSD value = vec; + + vec.resize(11); + vec[0] = 'b'; // for binary + vec[5] = 'a'; vec[6] = 'b'; vec[7] = 'c'; + vec[8] = '3'; vec[9] = '2'; vec[10] = '1'; + + uint32_t size = htonl(6); + memcpy(&vec[1], &size, sizeof(uint32_t)); + std::string str_good((char*)&vec[0], vec.size()); + ensureParse("correct binary parse", str_good, value, 1); + + size = htonl(7); + memcpy(&vec[1], &size, sizeof(uint32_t)); + std::string str_bad_1((char*)&vec[0], vec.size()); + ensureParse( + "incorrect size binary parse 1", + str_bad_1, + LLSD(), + LLSDParser::PARSE_FAILURE); + + size = htonl(100000); + memcpy(&vec[1], &size, sizeof(uint32_t)); + std::string str_bad_2((char*)&vec[0], vec.size()); + ensureParse( + "incorrect size binary parse 2", + str_bad_2, + LLSD(), + LLSDParser::PARSE_FAILURE); + } + + template<> template<> + void TestLLSDBinaryParsingObject::test<3>() + { + // test handling of xml not recognized as llsd results in an + // LLSD Undefined + ensureParse( + "malformed binary map", + "{'ha ha'", + LLSD(), + LLSDParser::PARSE_FAILURE); + ensureParse( + "malformed binary array", + "['ha ha'", + LLSD(), + LLSDParser::PARSE_FAILURE); + ensureParse( + "malformed binary string", + "'ha ha", + LLSD(), + LLSDParser::PARSE_FAILURE); + ensureParse( + "bad noise", + "g48ejlnfr", + LLSD(), + LLSDParser::PARSE_FAILURE); + } + template<> template<> + void TestLLSDBinaryParsingObject::test<4>() + { + ensureParse("valid undef", "!", LLSD(), 1); + } + + template<> template<> + void TestLLSDBinaryParsingObject::test<5>() + { + LLSD val = false; + ensureParse("valid boolean false 2", "0", val, 1); + val = true; + ensureParse("valid boolean true 2", "1", val, 1); + + val.clear(); + ensureParse("invalid true", "t", val, LLSDParser::PARSE_FAILURE); + ensureParse("invalid false", "f", val, LLSDParser::PARSE_FAILURE); + } + + template<> template<> + void TestLLSDBinaryParsingObject::test<6>() + { + std::vector vec; + vec.push_back('{'); + vec.resize(vec.size() + 4); + uint32_t size = htonl(1); + memcpy(&vec[1], &size, sizeof(uint32_t)); + vec.push_back('k'); + int key_size_loc = vec.size(); + size = htonl(1); // 1 too short + vec.resize(vec.size() + 4); + memcpy(&vec[key_size_loc], &size, sizeof(uint32_t)); + vec.push_back('a'); vec.push_back('m'); vec.push_back('y'); + vec.push_back('i'); + int integer_loc = vec.size(); + vec.resize(vec.size() + 4); + uint32_t val_int = htonl(23); + memcpy(&vec[integer_loc], &val_int, sizeof(uint32_t)); + std::string str_bad_1((char*)&vec[0], vec.size()); + ensureParse( + "invalid key size", + str_bad_1, + LLSD(), + LLSDParser::PARSE_FAILURE); + + // check with correct size, but unterminated map (missing '}') + size = htonl(3); // correct size + memcpy(&vec[key_size_loc], &size, sizeof(uint32_t)); + std::string str_bad_2((char*)&vec[0], vec.size()); + ensureParse( + "valid key size, unterminated map", + str_bad_2, + LLSD(), + LLSDParser::PARSE_FAILURE); + + // check w/ correct size and correct map termination + LLSD val; + val["amy"] = 23; + vec.push_back('}'); + std::string str_good((char*)&vec[0], vec.size()); + ensureParse( + "valid map", + str_good, + val, + 2); + + // check w/ incorrect sizes and correct map termination + size = htonl(0); // 1 too few (for the map entry) + memcpy(&vec[1], &size, sizeof(uint32_t)); + std::string str_bad_3((char*)&vec[0], vec.size()); + ensureParse( + "invalid map too long", + str_bad_3, + LLSD(), + LLSDParser::PARSE_FAILURE); + + size = htonl(2); // 1 too many + memcpy(&vec[1], &size, sizeof(uint32_t)); + std::string str_bad_4((char*)&vec[0], vec.size()); + ensureParse( + "invalid map too short", + str_bad_4, + LLSD(), + LLSDParser::PARSE_FAILURE); + } + + template<> template<> + void TestLLSDBinaryParsingObject::test<7>() + { + std::vector vec; + vec.push_back('['); + vec.resize(vec.size() + 4); + uint32_t size = htonl(1); // 1 too short + memcpy(&vec[1], &size, sizeof(uint32_t)); + vec.push_back('"'); vec.push_back('a'); vec.push_back('m'); + vec.push_back('y'); vec.push_back('"'); vec.push_back('i'); + int integer_loc = vec.size(); + vec.resize(vec.size() + 4); + uint32_t val_int = htonl(23); + memcpy(&vec[integer_loc], &val_int, sizeof(uint32_t)); + + std::string str_bad_1((char*)&vec[0], vec.size()); + ensureParse( + "invalid array size", + str_bad_1, + LLSD(), + LLSDParser::PARSE_FAILURE); + + // check with correct size, but unterminated map (missing ']') + size = htonl(2); // correct size + memcpy(&vec[1], &size, sizeof(uint32_t)); + std::string str_bad_2((char*)&vec[0], vec.size()); + ensureParse( + "unterminated array", + str_bad_2, + LLSD(), + LLSDParser::PARSE_FAILURE); + + // check w/ correct size and correct map termination + LLSD val; + val.append("amy"); + val.append(23); + vec.push_back(']'); + std::string str_good((char*)&vec[0], vec.size()); + ensureParse( + "valid array", + str_good, + val, + 3); + + // check with too many elements + size = htonl(3); // 1 too long + memcpy(&vec[1], &size, sizeof(uint32_t)); + std::string str_bad_3((char*)&vec[0], vec.size()); + ensureParse( + "array too short", + str_bad_3, + LLSD(), + LLSDParser::PARSE_FAILURE); + } + + template<> template<> + void TestLLSDBinaryParsingObject::test<8>() + { + std::vector vec; + vec.push_back('{'); + vec.resize(vec.size() + 4); + memset(&vec[1], 0, 4); + vec.push_back('}'); + std::string str_good((char*)&vec[0], vec.size()); + LLSD val = LLSD::emptyMap(); + ensureParse( + "empty map", + str_good, + val, + 1); + } + + template<> template<> + void TestLLSDBinaryParsingObject::test<9>() + { + std::vector vec; + vec.push_back('['); + vec.resize(vec.size() + 4); + memset(&vec[1], 0, 4); + vec.push_back(']'); + std::string str_good((char*)&vec[0], vec.size()); + LLSD val = LLSD::emptyArray(); + ensureParse( + "empty array", + str_good, + val, + 1); + } + + template<> template<> + void TestLLSDBinaryParsingObject::test<10>() + { + std::vector vec; + vec.push_back('l'); + vec.resize(vec.size() + 4); + uint32_t size = htonl(14); // 1 too long + memcpy(&vec[1], &size, sizeof(uint32_t)); + vec.push_back('h'); vec.push_back('t'); vec.push_back('t'); + vec.push_back('p'); vec.push_back(':'); vec.push_back('/'); + vec.push_back('/'); vec.push_back('s'); vec.push_back('l'); + vec.push_back('.'); vec.push_back('c'); vec.push_back('o'); + vec.push_back('m'); + std::string str_bad((char*)&vec[0], vec.size()); + ensureParse( + "invalid uri length size", + str_bad, + LLSD(), + LLSDParser::PARSE_FAILURE); + + LLSD val; + val = LLURI("http://sl.com"); + size = htonl(13); // correct length + memcpy(&vec[1], &size, sizeof(uint32_t)); + std::string str_good((char*)&vec[0], vec.size()); + ensureParse( + "valid key size", + str_good, + val, + 1); + } /* - template<> template<> - void TestLLSDBinaryParsingObject::test<11>() - { - } + template<> template<> + void TestLLSDBinaryParsingObject::test<11>() + { + } */ /** - * @class TestLLSDCrossCompatible - * @brief Miscellaneous serialization and parsing tests - */ - class TestLLSDCrossCompatible - { - public: - TestLLSDCrossCompatible() {} - - void ensureBinaryAndNotation( - const std::string& msg, - const LLSD& input) - { - // to binary, and back again - std::stringstream str1; - S32 count1 = LLSDSerialize::toBinary(input, str1); - LLSD actual_value_bin; - S32 count2 = LLSDSerialize::fromBinary( - actual_value_bin, - str1, - LLSDSerialize::SIZE_UNLIMITED); - ensure_equals( - "ensureBinaryAndNotation binary count", - count2, - count1); - - // to notation and back again - std::stringstream str2; - S32 count3 = LLSDSerialize::toNotation(actual_value_bin, str2); - ensure_equals( - "ensureBinaryAndNotation notation count1", - count3, - count2); - LLSD actual_value_notation; - S32 count4 = LLSDSerialize::fromNotation( - actual_value_notation, - str2, - LLSDSerialize::SIZE_UNLIMITED); - ensure_equals( - "ensureBinaryAndNotation notation count2", - count4, - count3); - ensure_equals( - (msg + " (binaryandnotation)").c_str(), - actual_value_notation, - input); - } - - void ensureBinaryAndXML( - const std::string& msg, - const LLSD& input) - { - // to binary, and back again - std::stringstream str1; - S32 count1 = LLSDSerialize::toBinary(input, str1); - LLSD actual_value_bin; - S32 count2 = LLSDSerialize::fromBinary( - actual_value_bin, - str1, - LLSDSerialize::SIZE_UNLIMITED); - ensure_equals( - "ensureBinaryAndXML binary count", - count2, - count1); - - // to xml and back again - std::stringstream str2; - S32 count3 = LLSDSerialize::toXML(actual_value_bin, str2); - ensure_equals( - "ensureBinaryAndXML xml count1", - count3, - count2); - LLSD actual_value_xml; - S32 count4 = LLSDSerialize::fromXML(actual_value_xml, str2); - ensure_equals( - "ensureBinaryAndXML xml count2", - count4, - count3); - ensure_equals((msg + " (binaryandxml)").c_str(), actual_value_xml, input); - } - }; - - typedef tut::test_group TestLLSDCompatibleGroup; - typedef TestLLSDCompatibleGroup::object TestLLSDCompatibleObject; - TestLLSDCompatibleGroup gTestLLSDCompatibleGroup( - "llsd serialize compatible"); - - template<> template<> - void TestLLSDCompatibleObject::test<1>() - { - LLSD test; - ensureBinaryAndNotation("undef", test); - ensureBinaryAndXML("undef", test); - test = true; - ensureBinaryAndNotation("boolean true", test); - ensureBinaryAndXML("boolean true", test); - test = false; - ensureBinaryAndNotation("boolean false", test); - ensureBinaryAndXML("boolean false", test); - test = 0; - ensureBinaryAndNotation("integer zero", test); - ensureBinaryAndXML("integer zero", test); - test = 1; - ensureBinaryAndNotation("integer positive", test); - ensureBinaryAndXML("integer positive", test); - test = -234567; - ensureBinaryAndNotation("integer negative", test); - ensureBinaryAndXML("integer negative", test); - test = 0.0; - ensureBinaryAndNotation("real zero", test); - ensureBinaryAndXML("real zero", test); - test = 1.0; - ensureBinaryAndNotation("real positive", test); - ensureBinaryAndXML("real positive", test); - test = -1.0; - ensureBinaryAndNotation("real negative", test); - ensureBinaryAndXML("real negative", test); - } - - template<> template<> - void TestLLSDCompatibleObject::test<2>() - { - LLSD test; - test = "foobar"; - ensureBinaryAndNotation("string", test); - ensureBinaryAndXML("string", test); - } - - template<> template<> - void TestLLSDCompatibleObject::test<3>() - { - LLSD test; - LLUUID id; - id.generate(); - test = id; - ensureBinaryAndNotation("uuid", test); - ensureBinaryAndXML("uuid", test); - } - - template<> template<> - void TestLLSDCompatibleObject::test<4>() - { - LLSD test; - test = LLDate(12345.0); - ensureBinaryAndNotation("date", test); - ensureBinaryAndXML("date", test); - } - - template<> template<> - void TestLLSDCompatibleObject::test<5>() - { - LLSD test; - test = LLURI("http://www.secondlife.com/"); - ensureBinaryAndNotation("uri", test); - ensureBinaryAndXML("uri", test); - } - - template<> template<> - void TestLLSDCompatibleObject::test<6>() - { - LLSD test; - typedef std::vector buf_t; - buf_t val; - for(int ii = 0; ii < 100; ++ii) - { - srand(ii); /* Flawfinder: ignore */ - S32 size = rand() % 100 + 10; - std::generate_n( - std::back_insert_iterator(val), - size, - rand); - } - test = val; - ensureBinaryAndNotation("binary", test); - ensureBinaryAndXML("binary", test); - } - - template<> template<> - void TestLLSDCompatibleObject::test<7>() - { - LLSD test; - test = LLSD::emptyArray(); - test.append(1); - test.append("hello"); - ensureBinaryAndNotation("array", test); - ensureBinaryAndXML("array", test); - } - - template<> template<> - void TestLLSDCompatibleObject::test<8>() - { - LLSD test; - test = LLSD::emptyArray(); - test["foo"] = "bar"; - test["baz"] = 100; - ensureBinaryAndNotation("map", test); - ensureBinaryAndXML("map", test); - } + * @class TestLLSDCrossCompatible + * @brief Miscellaneous serialization and parsing tests + */ + class TestLLSDCrossCompatible + { + public: + TestLLSDCrossCompatible() {} + + void ensureBinaryAndNotation( + const std::string& msg, + const LLSD& input) + { + // to binary, and back again + std::stringstream str1; + S32 count1 = LLSDSerialize::toBinary(input, str1); + LLSD actual_value_bin; + S32 count2 = LLSDSerialize::fromBinary( + actual_value_bin, + str1, + LLSDSerialize::SIZE_UNLIMITED); + ensure_equals( + "ensureBinaryAndNotation binary count", + count2, + count1); + + // to notation and back again + std::stringstream str2; + S32 count3 = LLSDSerialize::toNotation(actual_value_bin, str2); + ensure_equals( + "ensureBinaryAndNotation notation count1", + count3, + count2); + LLSD actual_value_notation; + S32 count4 = LLSDSerialize::fromNotation( + actual_value_notation, + str2, + LLSDSerialize::SIZE_UNLIMITED); + ensure_equals( + "ensureBinaryAndNotation notation count2", + count4, + count3); + ensure_equals( + (msg + " (binaryandnotation)").c_str(), + actual_value_notation, + input); + } + + void ensureBinaryAndXML( + const std::string& msg, + const LLSD& input) + { + // to binary, and back again + std::stringstream str1; + S32 count1 = LLSDSerialize::toBinary(input, str1); + LLSD actual_value_bin; + S32 count2 = LLSDSerialize::fromBinary( + actual_value_bin, + str1, + LLSDSerialize::SIZE_UNLIMITED); + ensure_equals( + "ensureBinaryAndXML binary count", + count2, + count1); + + // to xml and back again + std::stringstream str2; + S32 count3 = LLSDSerialize::toXML(actual_value_bin, str2); + ensure_equals( + "ensureBinaryAndXML xml count1", + count3, + count2); + LLSD actual_value_xml; + S32 count4 = LLSDSerialize::fromXML(actual_value_xml, str2); + ensure_equals( + "ensureBinaryAndXML xml count2", + count4, + count3); + ensure_equals((msg + " (binaryandxml)").c_str(), actual_value_xml, input); + } + }; + + typedef tut::test_group TestLLSDCompatibleGroup; + typedef TestLLSDCompatibleGroup::object TestLLSDCompatibleObject; + TestLLSDCompatibleGroup gTestLLSDCompatibleGroup( + "llsd serialize compatible"); + + template<> template<> + void TestLLSDCompatibleObject::test<1>() + { + LLSD test; + ensureBinaryAndNotation("undef", test); + ensureBinaryAndXML("undef", test); + test = true; + ensureBinaryAndNotation("boolean true", test); + ensureBinaryAndXML("boolean true", test); + test = false; + ensureBinaryAndNotation("boolean false", test); + ensureBinaryAndXML("boolean false", test); + test = 0; + ensureBinaryAndNotation("integer zero", test); + ensureBinaryAndXML("integer zero", test); + test = 1; + ensureBinaryAndNotation("integer positive", test); + ensureBinaryAndXML("integer positive", test); + test = -234567; + ensureBinaryAndNotation("integer negative", test); + ensureBinaryAndXML("integer negative", test); + test = 0.0; + ensureBinaryAndNotation("real zero", test); + ensureBinaryAndXML("real zero", test); + test = 1.0; + ensureBinaryAndNotation("real positive", test); + ensureBinaryAndXML("real positive", test); + test = -1.0; + ensureBinaryAndNotation("real negative", test); + ensureBinaryAndXML("real negative", test); + } + + template<> template<> + void TestLLSDCompatibleObject::test<2>() + { + LLSD test; + test = "foobar"; + ensureBinaryAndNotation("string", test); + ensureBinaryAndXML("string", test); + } + + template<> template<> + void TestLLSDCompatibleObject::test<3>() + { + LLSD test; + LLUUID id; + id.generate(); + test = id; + ensureBinaryAndNotation("uuid", test); + ensureBinaryAndXML("uuid", test); + } + + template<> template<> + void TestLLSDCompatibleObject::test<4>() + { + LLSD test; + test = LLDate(12345.0); + ensureBinaryAndNotation("date", test); + ensureBinaryAndXML("date", test); + } + + template<> template<> + void TestLLSDCompatibleObject::test<5>() + { + LLSD test; + test = LLURI("http://www.secondlife.com/"); + ensureBinaryAndNotation("uri", test); + ensureBinaryAndXML("uri", test); + } + + template<> template<> + void TestLLSDCompatibleObject::test<6>() + { + LLSD test; + typedef std::vector buf_t; + buf_t val; + for(int ii = 0; ii < 100; ++ii) + { + srand(ii); /* Flawfinder: ignore */ + S32 size = rand() % 100 + 10; + std::generate_n( + std::back_insert_iterator(val), + size, + rand); + } + test = val; + ensureBinaryAndNotation("binary", test); + ensureBinaryAndXML("binary", test); + } + + template<> template<> + void TestLLSDCompatibleObject::test<7>() + { + LLSD test; + test = LLSD::emptyArray(); + test.append(1); + test.append("hello"); + ensureBinaryAndNotation("array", test); + ensureBinaryAndXML("array", test); + } + + template<> template<> + void TestLLSDCompatibleObject::test<8>() + { + LLSD test; + test = LLSD::emptyArray(); + test["foo"] = "bar"; + test["baz"] = 100; + ensureBinaryAndNotation("map", test); + ensureBinaryAndXML("map", test); + } // helper for TestPythonCompatible static std::string import_llsd("import os.path\n" @@ -2130,7 +2130,7 @@ namespace tut item.asReal(), 3.14, 7); // 7 bits ~= 0.01 ensure("Failed to read LLSD::String from Python", itemFromStream(inf, item, parse)); - ensure_equals(item.asString(), + ensure_equals(item.asString(), "This string\n" "has several\n" "lines."); diff --git a/indra/llcommon/tests/llsingleton_test.cpp b/indra/llcommon/tests/llsingleton_test.cpp index 6f8aaaa0cb..adf5804272 100644 --- a/indra/llcommon/tests/llsingleton_test.cpp +++ b/indra/llcommon/tests/llsingleton_test.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llsingleton_test.cpp * @date 2011-08-11 * @brief Unit test for the LLSingleton class diff --git a/indra/llcommon/tests/llstreamqueue_test.cpp b/indra/llcommon/tests/llstreamqueue_test.cpp index 8af057328b..82b451119e 100644 --- a/indra/llcommon/tests/llstreamqueue_test.cpp +++ b/indra/llcommon/tests/llstreamqueue_test.cpp @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2012-01-05 * @brief Test for llstreamqueue. - * + * * $LicenseInfo:firstyear=2012&license=viewerlgpl$ * Copyright (c) 2012, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/tests/llstring_test.cpp b/indra/llcommon/tests/llstring_test.cpp index a7aa347222..3fadfa5334 100644 --- a/indra/llcommon/tests/llstring_test.cpp +++ b/indra/llcommon/tests/llstring_test.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llstring_test.cpp * @author Adroit, Steve Linden, Tofu Linden * @date 2006-12-24 @@ -7,21 +7,21 @@ * $LicenseInfo:firstyear=2007&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -37,835 +37,835 @@ using boost::assign::list_of; namespace tut { - struct string_index - { - }; - typedef test_group string_index_t; - typedef string_index_t::object string_index_object_t; - tut::string_index_t tut_string_index("LLString"); - - template<> template<> - void string_index_object_t::test<1>() - { - std::string llstr1; - ensure("Empty std::string", (llstr1.size() == 0) && llstr1.empty()); - - std::string llstr2("Hello"); - ensure("std::string = Hello", (!strcmp(llstr2.c_str(), "Hello")) && (llstr2.size() == 5) && !llstr2.empty()); - - std::string llstr3(llstr2); - ensure("std::string = std::string(std::string)", (!strcmp(llstr3.c_str(), "Hello")) && (llstr3.size() == 5) && !llstr3.empty()); - - std::string str("Hello World"); - std::string llstr4(str, 6); - ensure("std::string = std::string(s, size_type pos, size_type n = npos)", (!strcmp(llstr4.c_str(), "World")) && (llstr4.size() == 5) && !llstr4.empty()); - - std::string llstr5(str, str.size()); - ensure("std::string = std::string(s, size_type pos, size_type n = npos)", (llstr5.size() == 0) && llstr5.empty()); - - std::string llstr6(5, 'A'); - ensure("std::string = std::string(count, c)", (!strcmp(llstr6.c_str(), "AAAAA")) && (llstr6.size() == 5) && !llstr6.empty()); - - std::string llstr7("Hello World", 5); - ensure("std::string(s, n)", (!strcmp(llstr7.c_str(), "Hello")) && (llstr7.size() == 5) && !llstr7.empty()); - - std::string llstr8("Hello World", 6, 5); - ensure("std::string(s, n, count)", (!strcmp(llstr8.c_str(), "World")) && (llstr8.size() == 5) && !llstr8.empty()); - - std::string llstr9("Hello World", sizeof("Hello World")-1, 5); // go past end - ensure("std::string(s, n, count) goes past end", (llstr9.size() == 0) && llstr9.empty()); - } - - template<> template<> - void string_index_object_t::test<3>() - { - std::string str("Len=5"); - ensure("isValidIndex failed", LLStringUtil::isValidIndex(str, 0) == TRUE && - LLStringUtil::isValidIndex(str, 5) == TRUE && - LLStringUtil::isValidIndex(str, 6) == FALSE); - - std::string str1; - ensure("isValidIndex failed fo rempty string", LLStringUtil::isValidIndex(str1, 0) == FALSE); - } - - template<> template<> - void string_index_object_t::test<4>() - { - std::string str_val(" Testing the extra whitespaces "); - LLStringUtil::trimHead(str_val); - ensure_equals("1: trimHead failed", str_val, "Testing the extra whitespaces "); - - std::string str_val1("\n\t\r\n Testing the extra whitespaces "); - LLStringUtil::trimHead(str_val1); - ensure_equals("2: trimHead failed", str_val1, "Testing the extra whitespaces "); - } - - template<> template<> - void string_index_object_t::test<5>() - { - std::string str_val(" Testing the extra whitespaces "); - LLStringUtil::trimTail(str_val); - ensure_equals("1: trimTail failed", str_val, " Testing the extra whitespaces"); - - std::string str_val1("\n Testing the extra whitespaces \n\t\r\n "); - LLStringUtil::trimTail(str_val1); - ensure_equals("2: trimTail failed", str_val1, "\n Testing the extra whitespaces"); - } - - - template<> template<> - void string_index_object_t::test<6>() - { - std::string str_val(" \t \r Testing the extra \r\n whitespaces \n \t "); - LLStringUtil::trim(str_val); - ensure_equals("1: trim failed", str_val, "Testing the extra \r\n whitespaces"); - } - - template<> template<> - void string_index_object_t::test<7>() - { - std::string str("Second LindenLabs"); - LLStringUtil::truncate(str, 6); - ensure_equals("1: truncate", str, "Second"); - - // further truncate more than the length - LLStringUtil::truncate(str, 0); - ensure_equals("2: truncate", str, ""); - } - - template<> template<> - void string_index_object_t::test<8>() - { - std::string str_val("SecondLife Source"); - LLStringUtil::toUpper(str_val); - ensure_equals("toUpper failed", str_val, "SECONDLIFE SOURCE"); - } - - template<> template<> - void string_index_object_t::test<9>() - { - std::string str_val("SecondLife Source"); - LLStringUtil::toLower(str_val); - ensure_equals("toLower failed", str_val, "secondlife source"); - } - - template<> template<> - void string_index_object_t::test<10>() - { - std::string str_val("Second"); - ensure("1. isHead failed", LLStringUtil::isHead(str_val, "SecondLife Source") == TRUE); - ensure("2. isHead failed", LLStringUtil::isHead(str_val, " SecondLife Source") == FALSE); - std::string str_val2(""); - ensure("3. isHead failed", LLStringUtil::isHead(str_val2, "") == FALSE); - } - - template<> template<> - void string_index_object_t::test<11>() - { - std::string str_val("Hello.\n\n Lindenlabs. \n This is \na simple test.\n"); - std::string orig_str_val(str_val); - LLStringUtil::addCRLF(str_val); - ensure_equals("addCRLF failed", str_val, "Hello.\r\n\r\n Lindenlabs. \r\n This is \r\na simple test.\r\n"); - LLStringUtil::removeCRLF(str_val); - ensure_equals("removeCRLF failed", str_val, orig_str_val); - } - - template<> template<> - void string_index_object_t::test<12>() - { - std::string str_val("Hello.\n\n\t \t Lindenlabs. \t\t"); - std::string orig_str_val(str_val); - LLStringUtil::replaceTabsWithSpaces(str_val, 1); - ensure_equals("replaceTabsWithSpaces failed", str_val, "Hello.\n\n Lindenlabs. "); - LLStringUtil::replaceTabsWithSpaces(orig_str_val, 0); - ensure_equals("replaceTabsWithSpaces failed for 0", orig_str_val, "Hello.\n\n Lindenlabs. "); - - str_val = "\t\t\t\t"; - LLStringUtil::replaceTabsWithSpaces(str_val, 0); - ensure_equals("replaceTabsWithSpaces failed for all tabs", str_val, ""); - } - - template<> template<> - void string_index_object_t::test<13>() - { - std::string str_val("Hello.\n\n\t\t\r\nLindenlabsX."); - LLStringUtil::replaceNonstandardASCII(str_val, 'X'); - ensure_equals("replaceNonstandardASCII failed", str_val, "Hello.\n\nXXX\nLindenlabsX."); - } - - template<> template<> - void string_index_object_t::test<14>() - { - std::string str_val("Hello.\n\t\r\nABCDEFGHIABABAB"); - LLStringUtil::replaceChar(str_val, 'A', 'X'); - ensure_equals("1: replaceChar failed", str_val, "Hello.\n\t\r\nXBCDEFGHIXBXBXB"); - std::string str_val1("Hello.\n\t\r\nABCDEFGHIABABAB"); - } - - template<> template<> - void string_index_object_t::test<15>() - { - std::string str_val("Hello.\n\r\t"); - ensure("containsNonprintable failed", LLStringUtil::containsNonprintable(str_val) == TRUE); - - str_val = "ABC "; - ensure("containsNonprintable failed", LLStringUtil::containsNonprintable(str_val) == FALSE); - } - - template<> template<> - void string_index_object_t::test<16>() - { - std::string str_val("Hello.\n\r\t Again!"); - LLStringUtil::stripNonprintable(str_val); - ensure_equals("stripNonprintable failed", str_val, "Hello. Again!"); - - str_val = "\r\n\t\t"; - LLStringUtil::stripNonprintable(str_val); - ensure_equals("stripNonprintable resulting in empty string failed", str_val, ""); - - str_val = ""; - LLStringUtil::stripNonprintable(str_val); - ensure_equals("stripNonprintable of empty string resulting in empty string failed", str_val, ""); - } - - template<> template<> - void string_index_object_t::test<17>() - { - BOOL value; - std::string str_val("1"); - ensure("convertToBOOL 1 failed", LLStringUtil::convertToBOOL(str_val, value) && value); - str_val = "T"; - ensure("convertToBOOL T failed", LLStringUtil::convertToBOOL(str_val, value) && value); - str_val = "t"; - ensure("convertToBOOL t failed", LLStringUtil::convertToBOOL(str_val, value) && value); - str_val = "TRUE"; - ensure("convertToBOOL TRUE failed", LLStringUtil::convertToBOOL(str_val, value) && value); - str_val = "True"; - ensure("convertToBOOL True failed", LLStringUtil::convertToBOOL(str_val, value) && value); - str_val = "true"; - ensure("convertToBOOL true failed", LLStringUtil::convertToBOOL(str_val, value) && value); - - str_val = "0"; - ensure("convertToBOOL 0 failed", LLStringUtil::convertToBOOL(str_val, value) && !value); - str_val = "F"; - ensure("convertToBOOL F failed", LLStringUtil::convertToBOOL(str_val, value) && !value); - str_val = "f"; - ensure("convertToBOOL f failed", LLStringUtil::convertToBOOL(str_val, value) && !value); - str_val = "FALSE"; - ensure("convertToBOOL FASLE failed", LLStringUtil::convertToBOOL(str_val, value) && !value); - str_val = "False"; - ensure("convertToBOOL False failed", LLStringUtil::convertToBOOL(str_val, value) && !value); - str_val = "false"; - ensure("convertToBOOL false failed", LLStringUtil::convertToBOOL(str_val, value) && !value); - - str_val = "Tblah"; - ensure("convertToBOOL false failed", !LLStringUtil::convertToBOOL(str_val, value)); - } - - template<> template<> - void string_index_object_t::test<18>() - { - U8 value; - std::string str_val("255"); - ensure("1: convertToU8 failed", LLStringUtil::convertToU8(str_val, value) && value == 255); - - str_val = "0"; - ensure("2: convertToU8 failed", LLStringUtil::convertToU8(str_val, value) && value == 0); - - str_val = "-1"; - ensure("3: convertToU8 failed", !LLStringUtil::convertToU8(str_val, value)); - - str_val = "256"; // bigger than MAX_U8 - ensure("4: convertToU8 failed", !LLStringUtil::convertToU8(str_val, value)); - } - - template<> template<> - void string_index_object_t::test<19>() - { - S8 value; - std::string str_val("127"); - ensure("1: convertToS8 failed", LLStringUtil::convertToS8(str_val, value) && value == 127); - - str_val = "0"; - ensure("2: convertToS8 failed", LLStringUtil::convertToS8(str_val, value) && value == 0); - - str_val = "-128"; - ensure("3: convertToS8 failed", LLStringUtil::convertToS8(str_val, value) && value == -128); - - str_val = "128"; // bigger than MAX_S8 - ensure("4: convertToS8 failed", !LLStringUtil::convertToS8(str_val, value)); - - str_val = "-129"; - ensure("5: convertToS8 failed", !LLStringUtil::convertToS8(str_val, value)); - } - - template<> template<> - void string_index_object_t::test<20>() - { - S16 value; - std::string str_val("32767"); - ensure("1: convertToS16 failed", LLStringUtil::convertToS16(str_val, value) && value == 32767); - - str_val = "0"; - ensure("2: convertToS16 failed", LLStringUtil::convertToS16(str_val, value) && value == 0); - - str_val = "-32768"; - ensure("3: convertToS16 failed", LLStringUtil::convertToS16(str_val, value) && value == -32768); - - str_val = "32768"; - ensure("4: convertToS16 failed", !LLStringUtil::convertToS16(str_val, value)); - - str_val = "-32769"; - ensure("5: convertToS16 failed", !LLStringUtil::convertToS16(str_val, value)); - } - - template<> template<> - void string_index_object_t::test<21>() - { - U16 value; - std::string str_val("65535"); //0xFFFF - ensure("1: convertToU16 failed", LLStringUtil::convertToU16(str_val, value) && value == 65535); - - str_val = "0"; - ensure("2: convertToU16 failed", LLStringUtil::convertToU16(str_val, value) && value == 0); - - str_val = "-1"; - ensure("3: convertToU16 failed", !LLStringUtil::convertToU16(str_val, value)); - - str_val = "65536"; - ensure("4: convertToU16 failed", !LLStringUtil::convertToU16(str_val, value)); - } - - template<> template<> - void string_index_object_t::test<22>() - { - U32 value; - std::string str_val("4294967295"); //0xFFFFFFFF - ensure("1: convertToU32 failed", LLStringUtil::convertToU32(str_val, value) && value == 4294967295UL); - - str_val = "0"; - ensure("2: convertToU32 failed", LLStringUtil::convertToU32(str_val, value) && value == 0); - - str_val = "4294967296"; - ensure("3: convertToU32 failed", !LLStringUtil::convertToU32(str_val, value)); - } - - template<> template<> - void string_index_object_t::test<23>() - { - S32 value; - std::string str_val("2147483647"); //0x7FFFFFFF - ensure("1: convertToS32 failed", LLStringUtil::convertToS32(str_val, value) && value == 2147483647); - - str_val = "0"; - ensure("2: convertToS32 failed", LLStringUtil::convertToS32(str_val, value) && value == 0); - - // Avoid "unary minus operator applied to unsigned type" warning on VC++. JC - S32 min_val = -2147483647 - 1; - str_val = "-2147483648"; - ensure("3: convertToS32 failed", LLStringUtil::convertToS32(str_val, value) && value == min_val); - - str_val = "2147483648"; - ensure("4: convertToS32 failed", !LLStringUtil::convertToS32(str_val, value)); - - str_val = "-2147483649"; - ensure("5: convertToS32 failed", !LLStringUtil::convertToS32(str_val, value)); - } - - template<> template<> - void string_index_object_t::test<24>() - { - F32 value; - std::string str_val("2147483647"); //0x7FFFFFFF - ensure("1: convertToF32 failed", LLStringUtil::convertToF32(str_val, value) && value == 2147483647); - - str_val = "0"; - ensure("2: convertToF32 failed", LLStringUtil::convertToF32(str_val, value) && value == 0); - - /* Need to find max/min F32 values - str_val = "-2147483648"; - ensure("3: convertToF32 failed", LLStringUtil::convertToF32(str_val, value) && value == -2147483648); - - str_val = "2147483648"; - ensure("4: convertToF32 failed", !LLStringUtil::convertToF32(str_val, value)); - - str_val = "-2147483649"; - ensure("5: convertToF32 failed", !LLStringUtil::convertToF32(str_val, value)); - */ - } - - template<> template<> - void string_index_object_t::test<25>() - { - F64 value; - std::string str_val("9223372036854775807"); //0x7FFFFFFFFFFFFFFF - ensure("1: convertToF64 failed", LLStringUtil::convertToF64(str_val, value) && value == 9223372036854775807LL); - - str_val = "0"; - ensure("2: convertToF64 failed", LLStringUtil::convertToF64(str_val, value) && value == 0.0F); - - /* Need to find max/min F64 values - str_val = "-2147483648"; - ensure("3: convertToF32 failed", LLStringUtil::convertToF32(str_val, value) && value == -2147483648); - - str_val = "2147483648"; - ensure("4: convertToF32 failed", !LLStringUtil::convertToF32(str_val, value)); - - str_val = "-2147483649"; - ensure("5: convertToF32 failed", !LLStringUtil::convertToF32(str_val, value)); - */ - } - - template<> template<> - void string_index_object_t::test<26>() - { - const char* str1 = NULL; - const char* str2 = NULL; - - ensure("1: compareStrings failed", LLStringUtil::compareStrings(str1, str2) == 0); - str2 = "A"; - ensure("2: compareStrings failed", LLStringUtil::compareStrings(str1, str2) > 0); - ensure("3: compareStrings failed", LLStringUtil::compareStrings(str2, str1) < 0); - - str1 = "A is smaller than B"; - str2 = "B is greater than A"; - ensure("4: compareStrings failed", LLStringUtil::compareStrings(str1, str2) < 0); - - str2 = "A is smaller than B"; - ensure("5: compareStrings failed", LLStringUtil::compareStrings(str1, str2) == 0); - } - - template<> template<> - void string_index_object_t::test<27>() - { - const char* str1 = NULL; - const char* str2 = NULL; - - ensure("1: compareInsensitive failed", LLStringUtil::compareInsensitive(str1, str2) == 0); - str2 = "A"; - ensure("2: compareInsensitive failed", LLStringUtil::compareInsensitive(str1, str2) > 0); - ensure("3: compareInsensitive failed", LLStringUtil::compareInsensitive(str2, str1) < 0); - - str1 = "A is equal to a"; - str2 = "a is EQUAL to A"; - ensure("4: compareInsensitive failed", LLStringUtil::compareInsensitive(str1, str2) == 0); - } - - template<> template<> - void string_index_object_t::test<28>() - { - std::string lhs_str("PROgraM12files"); - std::string rhs_str("PROgram12Files"); - ensure("compareDict 1 failed", LLStringUtil::compareDict(lhs_str, rhs_str) < 0); - ensure("precedesDict 1 failed", LLStringUtil::precedesDict(lhs_str, rhs_str) == TRUE); - - lhs_str = "PROgram12Files"; - rhs_str = "PROgram12Files"; - ensure("compareDict 2 failed", LLStringUtil::compareDict(lhs_str, rhs_str) == 0); - ensure("precedesDict 2 failed", LLStringUtil::precedesDict(lhs_str, rhs_str) == FALSE); - - lhs_str = "PROgram12Files"; - rhs_str = "PROgRAM12FILES"; - ensure("compareDict 3 failed", LLStringUtil::compareDict(lhs_str, rhs_str) > 0); - ensure("precedesDict 3 failed", LLStringUtil::precedesDict(lhs_str, rhs_str) == FALSE); - } - - template<> template<> - void string_index_object_t::test<29>() - { - char str1[] = "First String..."; - char str2[100]; - - LLStringUtil::copy(str2, str1, 100); - ensure("LLStringUtil::copy with enough dest length failed", strcmp(str2, str1) == 0); - LLStringUtil::copy(str2, str1, sizeof("First")); - ensure("LLStringUtil::copy with less dest length failed", strcmp(str2, "First") == 0); - } - - template<> template<> - void string_index_object_t::test<30>() - { - std::string str1 = "This is the sentence..."; - std::string str2 = "This is the "; - std::string str3 = "first "; - std::string str4 = "This is the first sentence..."; - std::string str5 = "This is the sentence...first "; - std::string dest; - - dest = str1; - LLStringUtil::copyInto(dest, str3, str2.length()); - ensure("LLStringUtil::copyInto insert failed", dest == str4); - - dest = str1; - LLStringUtil::copyInto(dest, str3, dest.length()); - ensure("LLStringUtil::copyInto append failed", dest == str5); - } - - template<> template<> - void string_index_object_t::test<31>() - { - std::string stripped; - - // Plain US ASCII text, including spaces and punctuation, - // should not be altered. - std::string simple_text = "Hello, world!"; - stripped = LLStringFn::strip_invalid_xml(simple_text); - ensure("Simple text passed unchanged", stripped == simple_text); - - // Control characters should be removed - // except for 0x09, 0x0a, 0x0d - std::string control_chars; - for (char c = 0x01; c < 0x20; c++) - { - control_chars.push_back(c); - } - std::string allowed_control_chars; - allowed_control_chars.push_back( (char)0x09 ); - allowed_control_chars.push_back( (char)0x0a ); - allowed_control_chars.push_back( (char)0x0d ); - - stripped = LLStringFn::strip_invalid_xml(control_chars); - ensure("Only tab, LF, CR control characters allowed", - stripped == allowed_control_chars); - - // UTF-8 should be passed intact, including high byte - // characters. Try Francais (with C squiggle cedilla) - std::string french = "Fran"; - french.push_back( (char)0xC3 ); - french.push_back( (char)0xA7 ); - french += "ais"; - stripped = LLStringFn::strip_invalid_xml( french ); - ensure("UTF-8 high byte text is allowed", french == stripped ); - } - - template<> template<> - void string_index_object_t::test<32>() - { - // Test LLStringUtil::format() string interpolation - LLStringUtil::format_map_t fmt_map; - std::string s; - int subcount; - - fmt_map["[TRICK1]"] = "[A]"; - fmt_map["[A]"] = "a"; - fmt_map["[B]"] = "b"; - fmt_map["[AAA]"] = "aaa"; - fmt_map["[BBB]"] = "bbb"; - fmt_map["[TRICK2]"] = "[A]"; - fmt_map["[EXPLOIT]"] = "!!!!!!!!!!!![EXPLOIT]!!!!!!!!!!!!"; - fmt_map["[KEYLONGER]"] = "short"; - fmt_map["[KEYSHORTER]"] = "Am I not a long string?"; - fmt_map["?"] = "?"; - fmt_map["[DELETE]"] = ""; - fmt_map["[]"] = "[]"; // doesn't do a substitution, but shouldn't crash either - - for (LLStringUtil::format_map_t::const_iterator iter = fmt_map.begin(); iter != fmt_map.end(); ++iter) - { - // Test when source string is entirely one key - std::string s1 = (std::string)iter->first; - std::string s2 = (std::string)iter->second; - subcount = LLStringUtil::format(s1, fmt_map); - ensure_equals("LLStringUtil::format: Raw interpolation result", s1, s2); - if (s1 == "?" || s1 == "[]") // no interp expected - { - ensure_equals("LLStringUtil::format: Raw interpolation result count", 0, subcount); - } - else - { - ensure_equals("LLStringUtil::format: Raw interpolation result count", 1, subcount); - } - } - - for (LLStringUtil::format_map_t::const_iterator iter = fmt_map.begin(); iter != fmt_map.end(); ++iter) - { - // Test when source string is one key, duplicated - std::string s1 = (std::string)iter->first; - std::string s2 = (std::string)iter->second; - s = s1 + s1 + s1 + s1; - subcount = LLStringUtil::format(s, fmt_map); - ensure_equals("LLStringUtil::format: Rawx4 interpolation result", s, s2 + s2 + s2 + s2); - if (s1 == "?" || s1 == "[]") // no interp expected - { - ensure_equals("LLStringUtil::format: Rawx4 interpolation result count", 0, subcount); - } - else - { - ensure_equals("LLStringUtil::format: Rawx4 interpolation result count", 4, subcount); - } - } - - // Test when source string has no keys - std::string srcs = "!!!!!!!!!!!!!!!!"; - s = srcs; - subcount = LLStringUtil::format(s, fmt_map); - ensure_equals("LLStringUtil::format: No key test result", s, srcs); - ensure_equals("LLStringUtil::format: No key test result count", 0, subcount); - - // Test when source string has no keys and is empty - std::string srcs3; - s = srcs3; - subcount = LLStringUtil::format(s, fmt_map); - ensure("LLStringUtil::format: No key test3 result", s.empty()); - ensure_equals("LLStringUtil::format: No key test3 result count", 0, subcount); - - // Test a substitution where a key is substituted with blankness - std::string srcs2 = "[DELETE]"; - s = srcs2; - subcount = LLStringUtil::format(s, fmt_map); - ensure("LLStringUtil::format: Delete key test2 result", s.empty()); - ensure_equals("LLStringUtil::format: Delete key test2 result count", 1, subcount); - - // Test an assorted substitution - std::string srcs4 = "[TRICK1][A][B][AAA][BBB][TRICK2][KEYLONGER][KEYSHORTER]?[DELETE]"; - s = srcs4; - subcount = LLStringUtil::format(s, fmt_map); - ensure_equals("LLStringUtil::format: Assorted Test1 result", s, "[A]abaaabbb[A]shortAm I not a long string??"); - ensure_equals("LLStringUtil::format: Assorted Test1 result count", 9, subcount); - - // Test an assorted substitution - std::string srcs5 = "[DELETE]?[KEYSHORTER][KEYLONGER][TRICK2][BBB][AAA][B][A][TRICK1]"; - s = srcs5; - subcount = LLStringUtil::format(s, fmt_map); - ensure_equals("LLStringUtil::format: Assorted Test2 result", s, "?Am I not a long string?short[A]bbbaaaba[A]"); - ensure_equals("LLStringUtil::format: Assorted Test2 result count", 9, subcount); - - // Test on nested brackets - std::string srcs6 = "[[TRICK1]][[A]][[B]][[AAA]][[BBB]][[TRICK2]][[KEYLONGER]][[KEYSHORTER]]?[[DELETE]]"; - s = srcs6; - subcount = LLStringUtil::format(s, fmt_map); - ensure_equals("LLStringUtil::format: Assorted Test2 result", s, "[[A]][a][b][aaa][bbb][[A]][short][Am I not a long string?]?[]"); - ensure_equals("LLStringUtil::format: Assorted Test2 result count", 9, subcount); - - - // Test an assorted substitution - std::string srcs8 = "foo[DELETE]bar?"; - s = srcs8; - subcount = LLStringUtil::format(s, fmt_map); - ensure_equals("LLStringUtil::format: Assorted Test3 result", s, "foobar?"); - ensure_equals("LLStringUtil::format: Assorted Test3 result count", 1, subcount); - } - - template<> template<> - void string_index_object_t::test<33>() - { - // Test LLStringUtil::format() string interpolation - LLStringUtil::format_map_t blank_fmt_map; - std::string s; - int subcount; - - // Test substituting out of a blank format_map - std::string srcs6 = "12345"; - s = srcs6; - subcount = LLStringUtil::format(s, blank_fmt_map); - ensure_equals("LLStringUtil::format: Blankfmt Test1 result", s, "12345"); - ensure_equals("LLStringUtil::format: Blankfmt Test1 result count", 0, subcount); - - // Test substituting a blank string out of a blank format_map - std::string srcs7; - s = srcs7; - subcount = LLStringUtil::format(s, blank_fmt_map); - ensure("LLStringUtil::format: Blankfmt Test2 result", s.empty()); - ensure_equals("LLStringUtil::format: Blankfmt Test2 result count", 0, subcount); - } - - template<> template<> - void string_index_object_t::test<34>() - { - // Test that incorrect LLStringUtil::format() use does not explode. - LLStringUtil::format_map_t nasty_fmt_map; - std::string s; - int subcount; - - nasty_fmt_map[""] = "never used"; // see, this is nasty. - - // Test substituting out of a nasty format_map - std::string srcs6 = "12345"; - s = srcs6; - subcount = LLStringUtil::format(s, nasty_fmt_map); - ensure_equals("LLStringUtil::format: Nastyfmt Test1 result", s, "12345"); - ensure_equals("LLStringUtil::format: Nastyfmt Test1 result count", 0, subcount); - - // Test substituting a blank string out of a nasty format_map - std::string srcs7; - s = srcs7; - subcount = LLStringUtil::format(s, nasty_fmt_map); - ensure("LLStringUtil::format: Nastyfmt Test2 result", s.empty()); - ensure_equals("LLStringUtil::format: Nastyfmt Test2 result count", 0, subcount); - } - - template<> template<> - void string_index_object_t::test<35>() - { - // Make sure startsWith works - std::string string("anybody in there?"); - std::string substr("anybody"); - ensure("startsWith works.", LLStringUtil::startsWith(string, substr)); - } - - template<> template<> - void string_index_object_t::test<36>() - { - // Make sure startsWith correctly fails - std::string string("anybody in there?"); - std::string substr("there"); - ensure("startsWith fails.", !LLStringUtil::startsWith(string, substr)); - } - - template<> template<> - void string_index_object_t::test<37>() - { - // startsWith fails on empty strings - std::string value("anybody in there?"); - std::string empty; - ensure("empty string.", !LLStringUtil::startsWith(value, empty)); - ensure("empty substr.", !LLStringUtil::startsWith(empty, value)); - ensure("empty everything.", !LLStringUtil::startsWith(empty, empty)); - } - - template<> template<> - void string_index_object_t::test<38>() - { - // Make sure endsWith works correctly - std::string string("anybody in there?"); - std::string substr("there?"); - ensure("endsWith works.", LLStringUtil::endsWith(string, substr)); - } - - template<> template<> - void string_index_object_t::test<39>() - { - // Make sure endsWith correctly fails - std::string string("anybody in there?"); - std::string substr("anybody"); - ensure("endsWith fails.", !LLStringUtil::endsWith(string, substr)); - substr = "there"; - ensure("endsWith fails.", !LLStringUtil::endsWith(string, substr)); - substr = "ther?"; - ensure("endsWith fails.", !LLStringUtil::endsWith(string, substr)); - } - - template<> template<> - void string_index_object_t::test<40>() - { - // endsWith fails on empty strings - std::string value("anybody in there?"); - std::string empty; - ensure("empty string.", !LLStringUtil::endsWith(value, empty)); - ensure("empty substr.", !LLStringUtil::endsWith(empty, value)); - ensure("empty everything.", !LLStringUtil::endsWith(empty, empty)); - } - - template<> template<> - void string_index_object_t::test<41>() - { - set_test_name("getTokens(\"delims\")"); - ensure_equals("empty string", LLStringUtil::getTokens("", " "), StringVec()); - ensure_equals("only delims", - LLStringUtil::getTokens(" \r\n ", " \r\n"), StringVec()); - ensure_equals("sequence of delims", - LLStringUtil::getTokens(",,, one ,,,", ","), list_of("one")); - // nat considers this a dubious implementation side effect, but I'd - // hate to change it now... - ensure_equals("noncontiguous tokens", - LLStringUtil::getTokens(", ,, , one ,,,", ","), list_of("")("")("one")); - ensure_equals("space-padded tokens", - LLStringUtil::getTokens(", one , two ,", ","), list_of("one")("two")); - ensure_equals("no delims", LLStringUtil::getTokens("one", ","), list_of("one")); - } - - // Shorthand for verifying that getTokens() behaves the same when you - // don't pass a string of escape characters, when you pass an empty string - // (different overloads), and when you pass a string of characters that - // aren't actually present. - void ensure_getTokens(const std::string& desc, - const std::string& string, - const std::string& drop_delims, - const std::string& keep_delims, - const std::string& quotes, - const std::vector& expect) - { - ensure_equals(desc + " - no esc", - LLStringUtil::getTokens(string, drop_delims, keep_delims, quotes), - expect); - ensure_equals(desc + " - empty esc", - LLStringUtil::getTokens(string, drop_delims, keep_delims, quotes, ""), - expect); - ensure_equals(desc + " - unused esc", - LLStringUtil::getTokens(string, drop_delims, keep_delims, quotes, "!"), - expect); - } - - void ensure_getTokens(const std::string& desc, - const std::string& string, - const std::string& drop_delims, - const std::string& keep_delims, - const std::vector& expect) - { - ensure_getTokens(desc, string, drop_delims, keep_delims, "", expect); - } - - template<> template<> - void string_index_object_t::test<42>() - { - set_test_name("getTokens(\"delims\", etc.)"); - // Signatures to test in this method: - // getTokens(string, drop_delims, keep_delims [, quotes [, escapes]]) - // If you omit keep_delims, you get the older function (test above). - - // cases like the getTokens(string, delims) tests above - ensure_getTokens("empty string", "", " ", "", StringVec()); - ensure_getTokens("only delims", - " \r\n ", " \r\n", "", StringVec()); - ensure_getTokens("sequence of delims", - ",,, one ,,,", ", ", "", list_of("one")); - // Note contrast with the case in the previous method - ensure_getTokens("noncontiguous tokens", - ", ,, , one ,,,", ", ", "", list_of("one")); - ensure_getTokens("space-padded tokens", - ", one , two ,", ", ", "", + struct string_index + { + }; + typedef test_group string_index_t; + typedef string_index_t::object string_index_object_t; + tut::string_index_t tut_string_index("LLString"); + + template<> template<> + void string_index_object_t::test<1>() + { + std::string llstr1; + ensure("Empty std::string", (llstr1.size() == 0) && llstr1.empty()); + + std::string llstr2("Hello"); + ensure("std::string = Hello", (!strcmp(llstr2.c_str(), "Hello")) && (llstr2.size() == 5) && !llstr2.empty()); + + std::string llstr3(llstr2); + ensure("std::string = std::string(std::string)", (!strcmp(llstr3.c_str(), "Hello")) && (llstr3.size() == 5) && !llstr3.empty()); + + std::string str("Hello World"); + std::string llstr4(str, 6); + ensure("std::string = std::string(s, size_type pos, size_type n = npos)", (!strcmp(llstr4.c_str(), "World")) && (llstr4.size() == 5) && !llstr4.empty()); + + std::string llstr5(str, str.size()); + ensure("std::string = std::string(s, size_type pos, size_type n = npos)", (llstr5.size() == 0) && llstr5.empty()); + + std::string llstr6(5, 'A'); + ensure("std::string = std::string(count, c)", (!strcmp(llstr6.c_str(), "AAAAA")) && (llstr6.size() == 5) && !llstr6.empty()); + + std::string llstr7("Hello World", 5); + ensure("std::string(s, n)", (!strcmp(llstr7.c_str(), "Hello")) && (llstr7.size() == 5) && !llstr7.empty()); + + std::string llstr8("Hello World", 6, 5); + ensure("std::string(s, n, count)", (!strcmp(llstr8.c_str(), "World")) && (llstr8.size() == 5) && !llstr8.empty()); + + std::string llstr9("Hello World", sizeof("Hello World")-1, 5); // go past end + ensure("std::string(s, n, count) goes past end", (llstr9.size() == 0) && llstr9.empty()); + } + + template<> template<> + void string_index_object_t::test<3>() + { + std::string str("Len=5"); + ensure("isValidIndex failed", LLStringUtil::isValidIndex(str, 0) == TRUE && + LLStringUtil::isValidIndex(str, 5) == TRUE && + LLStringUtil::isValidIndex(str, 6) == FALSE); + + std::string str1; + ensure("isValidIndex failed fo rempty string", LLStringUtil::isValidIndex(str1, 0) == FALSE); + } + + template<> template<> + void string_index_object_t::test<4>() + { + std::string str_val(" Testing the extra whitespaces "); + LLStringUtil::trimHead(str_val); + ensure_equals("1: trimHead failed", str_val, "Testing the extra whitespaces "); + + std::string str_val1("\n\t\r\n Testing the extra whitespaces "); + LLStringUtil::trimHead(str_val1); + ensure_equals("2: trimHead failed", str_val1, "Testing the extra whitespaces "); + } + + template<> template<> + void string_index_object_t::test<5>() + { + std::string str_val(" Testing the extra whitespaces "); + LLStringUtil::trimTail(str_val); + ensure_equals("1: trimTail failed", str_val, " Testing the extra whitespaces"); + + std::string str_val1("\n Testing the extra whitespaces \n\t\r\n "); + LLStringUtil::trimTail(str_val1); + ensure_equals("2: trimTail failed", str_val1, "\n Testing the extra whitespaces"); + } + + + template<> template<> + void string_index_object_t::test<6>() + { + std::string str_val(" \t \r Testing the extra \r\n whitespaces \n \t "); + LLStringUtil::trim(str_val); + ensure_equals("1: trim failed", str_val, "Testing the extra \r\n whitespaces"); + } + + template<> template<> + void string_index_object_t::test<7>() + { + std::string str("Second LindenLabs"); + LLStringUtil::truncate(str, 6); + ensure_equals("1: truncate", str, "Second"); + + // further truncate more than the length + LLStringUtil::truncate(str, 0); + ensure_equals("2: truncate", str, ""); + } + + template<> template<> + void string_index_object_t::test<8>() + { + std::string str_val("SecondLife Source"); + LLStringUtil::toUpper(str_val); + ensure_equals("toUpper failed", str_val, "SECONDLIFE SOURCE"); + } + + template<> template<> + void string_index_object_t::test<9>() + { + std::string str_val("SecondLife Source"); + LLStringUtil::toLower(str_val); + ensure_equals("toLower failed", str_val, "secondlife source"); + } + + template<> template<> + void string_index_object_t::test<10>() + { + std::string str_val("Second"); + ensure("1. isHead failed", LLStringUtil::isHead(str_val, "SecondLife Source") == TRUE); + ensure("2. isHead failed", LLStringUtil::isHead(str_val, " SecondLife Source") == FALSE); + std::string str_val2(""); + ensure("3. isHead failed", LLStringUtil::isHead(str_val2, "") == FALSE); + } + + template<> template<> + void string_index_object_t::test<11>() + { + std::string str_val("Hello.\n\n Lindenlabs. \n This is \na simple test.\n"); + std::string orig_str_val(str_val); + LLStringUtil::addCRLF(str_val); + ensure_equals("addCRLF failed", str_val, "Hello.\r\n\r\n Lindenlabs. \r\n This is \r\na simple test.\r\n"); + LLStringUtil::removeCRLF(str_val); + ensure_equals("removeCRLF failed", str_val, orig_str_val); + } + + template<> template<> + void string_index_object_t::test<12>() + { + std::string str_val("Hello.\n\n\t \t Lindenlabs. \t\t"); + std::string orig_str_val(str_val); + LLStringUtil::replaceTabsWithSpaces(str_val, 1); + ensure_equals("replaceTabsWithSpaces failed", str_val, "Hello.\n\n Lindenlabs. "); + LLStringUtil::replaceTabsWithSpaces(orig_str_val, 0); + ensure_equals("replaceTabsWithSpaces failed for 0", orig_str_val, "Hello.\n\n Lindenlabs. "); + + str_val = "\t\t\t\t"; + LLStringUtil::replaceTabsWithSpaces(str_val, 0); + ensure_equals("replaceTabsWithSpaces failed for all tabs", str_val, ""); + } + + template<> template<> + void string_index_object_t::test<13>() + { + std::string str_val("Hello.\n\n\t\t\r\nLindenlabsX."); + LLStringUtil::replaceNonstandardASCII(str_val, 'X'); + ensure_equals("replaceNonstandardASCII failed", str_val, "Hello.\n\nXXX\nLindenlabsX."); + } + + template<> template<> + void string_index_object_t::test<14>() + { + std::string str_val("Hello.\n\t\r\nABCDEFGHIABABAB"); + LLStringUtil::replaceChar(str_val, 'A', 'X'); + ensure_equals("1: replaceChar failed", str_val, "Hello.\n\t\r\nXBCDEFGHIXBXBXB"); + std::string str_val1("Hello.\n\t\r\nABCDEFGHIABABAB"); + } + + template<> template<> + void string_index_object_t::test<15>() + { + std::string str_val("Hello.\n\r\t"); + ensure("containsNonprintable failed", LLStringUtil::containsNonprintable(str_val) == TRUE); + + str_val = "ABC "; + ensure("containsNonprintable failed", LLStringUtil::containsNonprintable(str_val) == FALSE); + } + + template<> template<> + void string_index_object_t::test<16>() + { + std::string str_val("Hello.\n\r\t Again!"); + LLStringUtil::stripNonprintable(str_val); + ensure_equals("stripNonprintable failed", str_val, "Hello. Again!"); + + str_val = "\r\n\t\t"; + LLStringUtil::stripNonprintable(str_val); + ensure_equals("stripNonprintable resulting in empty string failed", str_val, ""); + + str_val = ""; + LLStringUtil::stripNonprintable(str_val); + ensure_equals("stripNonprintable of empty string resulting in empty string failed", str_val, ""); + } + + template<> template<> + void string_index_object_t::test<17>() + { + BOOL value; + std::string str_val("1"); + ensure("convertToBOOL 1 failed", LLStringUtil::convertToBOOL(str_val, value) && value); + str_val = "T"; + ensure("convertToBOOL T failed", LLStringUtil::convertToBOOL(str_val, value) && value); + str_val = "t"; + ensure("convertToBOOL t failed", LLStringUtil::convertToBOOL(str_val, value) && value); + str_val = "TRUE"; + ensure("convertToBOOL TRUE failed", LLStringUtil::convertToBOOL(str_val, value) && value); + str_val = "True"; + ensure("convertToBOOL True failed", LLStringUtil::convertToBOOL(str_val, value) && value); + str_val = "true"; + ensure("convertToBOOL true failed", LLStringUtil::convertToBOOL(str_val, value) && value); + + str_val = "0"; + ensure("convertToBOOL 0 failed", LLStringUtil::convertToBOOL(str_val, value) && !value); + str_val = "F"; + ensure("convertToBOOL F failed", LLStringUtil::convertToBOOL(str_val, value) && !value); + str_val = "f"; + ensure("convertToBOOL f failed", LLStringUtil::convertToBOOL(str_val, value) && !value); + str_val = "FALSE"; + ensure("convertToBOOL FASLE failed", LLStringUtil::convertToBOOL(str_val, value) && !value); + str_val = "False"; + ensure("convertToBOOL False failed", LLStringUtil::convertToBOOL(str_val, value) && !value); + str_val = "false"; + ensure("convertToBOOL false failed", LLStringUtil::convertToBOOL(str_val, value) && !value); + + str_val = "Tblah"; + ensure("convertToBOOL false failed", !LLStringUtil::convertToBOOL(str_val, value)); + } + + template<> template<> + void string_index_object_t::test<18>() + { + U8 value; + std::string str_val("255"); + ensure("1: convertToU8 failed", LLStringUtil::convertToU8(str_val, value) && value == 255); + + str_val = "0"; + ensure("2: convertToU8 failed", LLStringUtil::convertToU8(str_val, value) && value == 0); + + str_val = "-1"; + ensure("3: convertToU8 failed", !LLStringUtil::convertToU8(str_val, value)); + + str_val = "256"; // bigger than MAX_U8 + ensure("4: convertToU8 failed", !LLStringUtil::convertToU8(str_val, value)); + } + + template<> template<> + void string_index_object_t::test<19>() + { + S8 value; + std::string str_val("127"); + ensure("1: convertToS8 failed", LLStringUtil::convertToS8(str_val, value) && value == 127); + + str_val = "0"; + ensure("2: convertToS8 failed", LLStringUtil::convertToS8(str_val, value) && value == 0); + + str_val = "-128"; + ensure("3: convertToS8 failed", LLStringUtil::convertToS8(str_val, value) && value == -128); + + str_val = "128"; // bigger than MAX_S8 + ensure("4: convertToS8 failed", !LLStringUtil::convertToS8(str_val, value)); + + str_val = "-129"; + ensure("5: convertToS8 failed", !LLStringUtil::convertToS8(str_val, value)); + } + + template<> template<> + void string_index_object_t::test<20>() + { + S16 value; + std::string str_val("32767"); + ensure("1: convertToS16 failed", LLStringUtil::convertToS16(str_val, value) && value == 32767); + + str_val = "0"; + ensure("2: convertToS16 failed", LLStringUtil::convertToS16(str_val, value) && value == 0); + + str_val = "-32768"; + ensure("3: convertToS16 failed", LLStringUtil::convertToS16(str_val, value) && value == -32768); + + str_val = "32768"; + ensure("4: convertToS16 failed", !LLStringUtil::convertToS16(str_val, value)); + + str_val = "-32769"; + ensure("5: convertToS16 failed", !LLStringUtil::convertToS16(str_val, value)); + } + + template<> template<> + void string_index_object_t::test<21>() + { + U16 value; + std::string str_val("65535"); //0xFFFF + ensure("1: convertToU16 failed", LLStringUtil::convertToU16(str_val, value) && value == 65535); + + str_val = "0"; + ensure("2: convertToU16 failed", LLStringUtil::convertToU16(str_val, value) && value == 0); + + str_val = "-1"; + ensure("3: convertToU16 failed", !LLStringUtil::convertToU16(str_val, value)); + + str_val = "65536"; + ensure("4: convertToU16 failed", !LLStringUtil::convertToU16(str_val, value)); + } + + template<> template<> + void string_index_object_t::test<22>() + { + U32 value; + std::string str_val("4294967295"); //0xFFFFFFFF + ensure("1: convertToU32 failed", LLStringUtil::convertToU32(str_val, value) && value == 4294967295UL); + + str_val = "0"; + ensure("2: convertToU32 failed", LLStringUtil::convertToU32(str_val, value) && value == 0); + + str_val = "4294967296"; + ensure("3: convertToU32 failed", !LLStringUtil::convertToU32(str_val, value)); + } + + template<> template<> + void string_index_object_t::test<23>() + { + S32 value; + std::string str_val("2147483647"); //0x7FFFFFFF + ensure("1: convertToS32 failed", LLStringUtil::convertToS32(str_val, value) && value == 2147483647); + + str_val = "0"; + ensure("2: convertToS32 failed", LLStringUtil::convertToS32(str_val, value) && value == 0); + + // Avoid "unary minus operator applied to unsigned type" warning on VC++. JC + S32 min_val = -2147483647 - 1; + str_val = "-2147483648"; + ensure("3: convertToS32 failed", LLStringUtil::convertToS32(str_val, value) && value == min_val); + + str_val = "2147483648"; + ensure("4: convertToS32 failed", !LLStringUtil::convertToS32(str_val, value)); + + str_val = "-2147483649"; + ensure("5: convertToS32 failed", !LLStringUtil::convertToS32(str_val, value)); + } + + template<> template<> + void string_index_object_t::test<24>() + { + F32 value; + std::string str_val("2147483647"); //0x7FFFFFFF + ensure("1: convertToF32 failed", LLStringUtil::convertToF32(str_val, value) && value == 2147483647); + + str_val = "0"; + ensure("2: convertToF32 failed", LLStringUtil::convertToF32(str_val, value) && value == 0); + + /* Need to find max/min F32 values + str_val = "-2147483648"; + ensure("3: convertToF32 failed", LLStringUtil::convertToF32(str_val, value) && value == -2147483648); + + str_val = "2147483648"; + ensure("4: convertToF32 failed", !LLStringUtil::convertToF32(str_val, value)); + + str_val = "-2147483649"; + ensure("5: convertToF32 failed", !LLStringUtil::convertToF32(str_val, value)); + */ + } + + template<> template<> + void string_index_object_t::test<25>() + { + F64 value; + std::string str_val("9223372036854775807"); //0x7FFFFFFFFFFFFFFF + ensure("1: convertToF64 failed", LLStringUtil::convertToF64(str_val, value) && value == 9223372036854775807LL); + + str_val = "0"; + ensure("2: convertToF64 failed", LLStringUtil::convertToF64(str_val, value) && value == 0.0F); + + /* Need to find max/min F64 values + str_val = "-2147483648"; + ensure("3: convertToF32 failed", LLStringUtil::convertToF32(str_val, value) && value == -2147483648); + + str_val = "2147483648"; + ensure("4: convertToF32 failed", !LLStringUtil::convertToF32(str_val, value)); + + str_val = "-2147483649"; + ensure("5: convertToF32 failed", !LLStringUtil::convertToF32(str_val, value)); + */ + } + + template<> template<> + void string_index_object_t::test<26>() + { + const char* str1 = NULL; + const char* str2 = NULL; + + ensure("1: compareStrings failed", LLStringUtil::compareStrings(str1, str2) == 0); + str2 = "A"; + ensure("2: compareStrings failed", LLStringUtil::compareStrings(str1, str2) > 0); + ensure("3: compareStrings failed", LLStringUtil::compareStrings(str2, str1) < 0); + + str1 = "A is smaller than B"; + str2 = "B is greater than A"; + ensure("4: compareStrings failed", LLStringUtil::compareStrings(str1, str2) < 0); + + str2 = "A is smaller than B"; + ensure("5: compareStrings failed", LLStringUtil::compareStrings(str1, str2) == 0); + } + + template<> template<> + void string_index_object_t::test<27>() + { + const char* str1 = NULL; + const char* str2 = NULL; + + ensure("1: compareInsensitive failed", LLStringUtil::compareInsensitive(str1, str2) == 0); + str2 = "A"; + ensure("2: compareInsensitive failed", LLStringUtil::compareInsensitive(str1, str2) > 0); + ensure("3: compareInsensitive failed", LLStringUtil::compareInsensitive(str2, str1) < 0); + + str1 = "A is equal to a"; + str2 = "a is EQUAL to A"; + ensure("4: compareInsensitive failed", LLStringUtil::compareInsensitive(str1, str2) == 0); + } + + template<> template<> + void string_index_object_t::test<28>() + { + std::string lhs_str("PROgraM12files"); + std::string rhs_str("PROgram12Files"); + ensure("compareDict 1 failed", LLStringUtil::compareDict(lhs_str, rhs_str) < 0); + ensure("precedesDict 1 failed", LLStringUtil::precedesDict(lhs_str, rhs_str) == TRUE); + + lhs_str = "PROgram12Files"; + rhs_str = "PROgram12Files"; + ensure("compareDict 2 failed", LLStringUtil::compareDict(lhs_str, rhs_str) == 0); + ensure("precedesDict 2 failed", LLStringUtil::precedesDict(lhs_str, rhs_str) == FALSE); + + lhs_str = "PROgram12Files"; + rhs_str = "PROgRAM12FILES"; + ensure("compareDict 3 failed", LLStringUtil::compareDict(lhs_str, rhs_str) > 0); + ensure("precedesDict 3 failed", LLStringUtil::precedesDict(lhs_str, rhs_str) == FALSE); + } + + template<> template<> + void string_index_object_t::test<29>() + { + char str1[] = "First String..."; + char str2[100]; + + LLStringUtil::copy(str2, str1, 100); + ensure("LLStringUtil::copy with enough dest length failed", strcmp(str2, str1) == 0); + LLStringUtil::copy(str2, str1, sizeof("First")); + ensure("LLStringUtil::copy with less dest length failed", strcmp(str2, "First") == 0); + } + + template<> template<> + void string_index_object_t::test<30>() + { + std::string str1 = "This is the sentence..."; + std::string str2 = "This is the "; + std::string str3 = "first "; + std::string str4 = "This is the first sentence..."; + std::string str5 = "This is the sentence...first "; + std::string dest; + + dest = str1; + LLStringUtil::copyInto(dest, str3, str2.length()); + ensure("LLStringUtil::copyInto insert failed", dest == str4); + + dest = str1; + LLStringUtil::copyInto(dest, str3, dest.length()); + ensure("LLStringUtil::copyInto append failed", dest == str5); + } + + template<> template<> + void string_index_object_t::test<31>() + { + std::string stripped; + + // Plain US ASCII text, including spaces and punctuation, + // should not be altered. + std::string simple_text = "Hello, world!"; + stripped = LLStringFn::strip_invalid_xml(simple_text); + ensure("Simple text passed unchanged", stripped == simple_text); + + // Control characters should be removed + // except for 0x09, 0x0a, 0x0d + std::string control_chars; + for (char c = 0x01; c < 0x20; c++) + { + control_chars.push_back(c); + } + std::string allowed_control_chars; + allowed_control_chars.push_back( (char)0x09 ); + allowed_control_chars.push_back( (char)0x0a ); + allowed_control_chars.push_back( (char)0x0d ); + + stripped = LLStringFn::strip_invalid_xml(control_chars); + ensure("Only tab, LF, CR control characters allowed", + stripped == allowed_control_chars); + + // UTF-8 should be passed intact, including high byte + // characters. Try Francais (with C squiggle cedilla) + std::string french = "Fran"; + french.push_back( (char)0xC3 ); + french.push_back( (char)0xA7 ); + french += "ais"; + stripped = LLStringFn::strip_invalid_xml( french ); + ensure("UTF-8 high byte text is allowed", french == stripped ); + } + + template<> template<> + void string_index_object_t::test<32>() + { + // Test LLStringUtil::format() string interpolation + LLStringUtil::format_map_t fmt_map; + std::string s; + int subcount; + + fmt_map["[TRICK1]"] = "[A]"; + fmt_map["[A]"] = "a"; + fmt_map["[B]"] = "b"; + fmt_map["[AAA]"] = "aaa"; + fmt_map["[BBB]"] = "bbb"; + fmt_map["[TRICK2]"] = "[A]"; + fmt_map["[EXPLOIT]"] = "!!!!!!!!!!!![EXPLOIT]!!!!!!!!!!!!"; + fmt_map["[KEYLONGER]"] = "short"; + fmt_map["[KEYSHORTER]"] = "Am I not a long string?"; + fmt_map["?"] = "?"; + fmt_map["[DELETE]"] = ""; + fmt_map["[]"] = "[]"; // doesn't do a substitution, but shouldn't crash either + + for (LLStringUtil::format_map_t::const_iterator iter = fmt_map.begin(); iter != fmt_map.end(); ++iter) + { + // Test when source string is entirely one key + std::string s1 = (std::string)iter->first; + std::string s2 = (std::string)iter->second; + subcount = LLStringUtil::format(s1, fmt_map); + ensure_equals("LLStringUtil::format: Raw interpolation result", s1, s2); + if (s1 == "?" || s1 == "[]") // no interp expected + { + ensure_equals("LLStringUtil::format: Raw interpolation result count", 0, subcount); + } + else + { + ensure_equals("LLStringUtil::format: Raw interpolation result count", 1, subcount); + } + } + + for (LLStringUtil::format_map_t::const_iterator iter = fmt_map.begin(); iter != fmt_map.end(); ++iter) + { + // Test when source string is one key, duplicated + std::string s1 = (std::string)iter->first; + std::string s2 = (std::string)iter->second; + s = s1 + s1 + s1 + s1; + subcount = LLStringUtil::format(s, fmt_map); + ensure_equals("LLStringUtil::format: Rawx4 interpolation result", s, s2 + s2 + s2 + s2); + if (s1 == "?" || s1 == "[]") // no interp expected + { + ensure_equals("LLStringUtil::format: Rawx4 interpolation result count", 0, subcount); + } + else + { + ensure_equals("LLStringUtil::format: Rawx4 interpolation result count", 4, subcount); + } + } + + // Test when source string has no keys + std::string srcs = "!!!!!!!!!!!!!!!!"; + s = srcs; + subcount = LLStringUtil::format(s, fmt_map); + ensure_equals("LLStringUtil::format: No key test result", s, srcs); + ensure_equals("LLStringUtil::format: No key test result count", 0, subcount); + + // Test when source string has no keys and is empty + std::string srcs3; + s = srcs3; + subcount = LLStringUtil::format(s, fmt_map); + ensure("LLStringUtil::format: No key test3 result", s.empty()); + ensure_equals("LLStringUtil::format: No key test3 result count", 0, subcount); + + // Test a substitution where a key is substituted with blankness + std::string srcs2 = "[DELETE]"; + s = srcs2; + subcount = LLStringUtil::format(s, fmt_map); + ensure("LLStringUtil::format: Delete key test2 result", s.empty()); + ensure_equals("LLStringUtil::format: Delete key test2 result count", 1, subcount); + + // Test an assorted substitution + std::string srcs4 = "[TRICK1][A][B][AAA][BBB][TRICK2][KEYLONGER][KEYSHORTER]?[DELETE]"; + s = srcs4; + subcount = LLStringUtil::format(s, fmt_map); + ensure_equals("LLStringUtil::format: Assorted Test1 result", s, "[A]abaaabbb[A]shortAm I not a long string??"); + ensure_equals("LLStringUtil::format: Assorted Test1 result count", 9, subcount); + + // Test an assorted substitution + std::string srcs5 = "[DELETE]?[KEYSHORTER][KEYLONGER][TRICK2][BBB][AAA][B][A][TRICK1]"; + s = srcs5; + subcount = LLStringUtil::format(s, fmt_map); + ensure_equals("LLStringUtil::format: Assorted Test2 result", s, "?Am I not a long string?short[A]bbbaaaba[A]"); + ensure_equals("LLStringUtil::format: Assorted Test2 result count", 9, subcount); + + // Test on nested brackets + std::string srcs6 = "[[TRICK1]][[A]][[B]][[AAA]][[BBB]][[TRICK2]][[KEYLONGER]][[KEYSHORTER]]?[[DELETE]]"; + s = srcs6; + subcount = LLStringUtil::format(s, fmt_map); + ensure_equals("LLStringUtil::format: Assorted Test2 result", s, "[[A]][a][b][aaa][bbb][[A]][short][Am I not a long string?]?[]"); + ensure_equals("LLStringUtil::format: Assorted Test2 result count", 9, subcount); + + + // Test an assorted substitution + std::string srcs8 = "foo[DELETE]bar?"; + s = srcs8; + subcount = LLStringUtil::format(s, fmt_map); + ensure_equals("LLStringUtil::format: Assorted Test3 result", s, "foobar?"); + ensure_equals("LLStringUtil::format: Assorted Test3 result count", 1, subcount); + } + + template<> template<> + void string_index_object_t::test<33>() + { + // Test LLStringUtil::format() string interpolation + LLStringUtil::format_map_t blank_fmt_map; + std::string s; + int subcount; + + // Test substituting out of a blank format_map + std::string srcs6 = "12345"; + s = srcs6; + subcount = LLStringUtil::format(s, blank_fmt_map); + ensure_equals("LLStringUtil::format: Blankfmt Test1 result", s, "12345"); + ensure_equals("LLStringUtil::format: Blankfmt Test1 result count", 0, subcount); + + // Test substituting a blank string out of a blank format_map + std::string srcs7; + s = srcs7; + subcount = LLStringUtil::format(s, blank_fmt_map); + ensure("LLStringUtil::format: Blankfmt Test2 result", s.empty()); + ensure_equals("LLStringUtil::format: Blankfmt Test2 result count", 0, subcount); + } + + template<> template<> + void string_index_object_t::test<34>() + { + // Test that incorrect LLStringUtil::format() use does not explode. + LLStringUtil::format_map_t nasty_fmt_map; + std::string s; + int subcount; + + nasty_fmt_map[""] = "never used"; // see, this is nasty. + + // Test substituting out of a nasty format_map + std::string srcs6 = "12345"; + s = srcs6; + subcount = LLStringUtil::format(s, nasty_fmt_map); + ensure_equals("LLStringUtil::format: Nastyfmt Test1 result", s, "12345"); + ensure_equals("LLStringUtil::format: Nastyfmt Test1 result count", 0, subcount); + + // Test substituting a blank string out of a nasty format_map + std::string srcs7; + s = srcs7; + subcount = LLStringUtil::format(s, nasty_fmt_map); + ensure("LLStringUtil::format: Nastyfmt Test2 result", s.empty()); + ensure_equals("LLStringUtil::format: Nastyfmt Test2 result count", 0, subcount); + } + + template<> template<> + void string_index_object_t::test<35>() + { + // Make sure startsWith works + std::string string("anybody in there?"); + std::string substr("anybody"); + ensure("startsWith works.", LLStringUtil::startsWith(string, substr)); + } + + template<> template<> + void string_index_object_t::test<36>() + { + // Make sure startsWith correctly fails + std::string string("anybody in there?"); + std::string substr("there"); + ensure("startsWith fails.", !LLStringUtil::startsWith(string, substr)); + } + + template<> template<> + void string_index_object_t::test<37>() + { + // startsWith fails on empty strings + std::string value("anybody in there?"); + std::string empty; + ensure("empty string.", !LLStringUtil::startsWith(value, empty)); + ensure("empty substr.", !LLStringUtil::startsWith(empty, value)); + ensure("empty everything.", !LLStringUtil::startsWith(empty, empty)); + } + + template<> template<> + void string_index_object_t::test<38>() + { + // Make sure endsWith works correctly + std::string string("anybody in there?"); + std::string substr("there?"); + ensure("endsWith works.", LLStringUtil::endsWith(string, substr)); + } + + template<> template<> + void string_index_object_t::test<39>() + { + // Make sure endsWith correctly fails + std::string string("anybody in there?"); + std::string substr("anybody"); + ensure("endsWith fails.", !LLStringUtil::endsWith(string, substr)); + substr = "there"; + ensure("endsWith fails.", !LLStringUtil::endsWith(string, substr)); + substr = "ther?"; + ensure("endsWith fails.", !LLStringUtil::endsWith(string, substr)); + } + + template<> template<> + void string_index_object_t::test<40>() + { + // endsWith fails on empty strings + std::string value("anybody in there?"); + std::string empty; + ensure("empty string.", !LLStringUtil::endsWith(value, empty)); + ensure("empty substr.", !LLStringUtil::endsWith(empty, value)); + ensure("empty everything.", !LLStringUtil::endsWith(empty, empty)); + } + + template<> template<> + void string_index_object_t::test<41>() + { + set_test_name("getTokens(\"delims\")"); + ensure_equals("empty string", LLStringUtil::getTokens("", " "), StringVec()); + ensure_equals("only delims", + LLStringUtil::getTokens(" \r\n ", " \r\n"), StringVec()); + ensure_equals("sequence of delims", + LLStringUtil::getTokens(",,, one ,,,", ","), list_of("one")); + // nat considers this a dubious implementation side effect, but I'd + // hate to change it now... + ensure_equals("noncontiguous tokens", + LLStringUtil::getTokens(", ,, , one ,,,", ","), list_of("")("")("one")); + ensure_equals("space-padded tokens", + LLStringUtil::getTokens(", one , two ,", ","), list_of("one")("two")); + ensure_equals("no delims", LLStringUtil::getTokens("one", ","), list_of("one")); + } + + // Shorthand for verifying that getTokens() behaves the same when you + // don't pass a string of escape characters, when you pass an empty string + // (different overloads), and when you pass a string of characters that + // aren't actually present. + void ensure_getTokens(const std::string& desc, + const std::string& string, + const std::string& drop_delims, + const std::string& keep_delims, + const std::string& quotes, + const std::vector& expect) + { + ensure_equals(desc + " - no esc", + LLStringUtil::getTokens(string, drop_delims, keep_delims, quotes), + expect); + ensure_equals(desc + " - empty esc", + LLStringUtil::getTokens(string, drop_delims, keep_delims, quotes, ""), + expect); + ensure_equals(desc + " - unused esc", + LLStringUtil::getTokens(string, drop_delims, keep_delims, quotes, "!"), + expect); + } + + void ensure_getTokens(const std::string& desc, + const std::string& string, + const std::string& drop_delims, + const std::string& keep_delims, + const std::vector& expect) + { + ensure_getTokens(desc, string, drop_delims, keep_delims, "", expect); + } + + template<> template<> + void string_index_object_t::test<42>() + { + set_test_name("getTokens(\"delims\", etc.)"); + // Signatures to test in this method: + // getTokens(string, drop_delims, keep_delims [, quotes [, escapes]]) + // If you omit keep_delims, you get the older function (test above). + + // cases like the getTokens(string, delims) tests above + ensure_getTokens("empty string", "", " ", "", StringVec()); + ensure_getTokens("only delims", + " \r\n ", " \r\n", "", StringVec()); + ensure_getTokens("sequence of delims", + ",,, one ,,,", ", ", "", list_of("one")); + // Note contrast with the case in the previous method + ensure_getTokens("noncontiguous tokens", + ", ,, , one ,,,", ", ", "", list_of("one")); + ensure_getTokens("space-padded tokens", + ", one , two ,", ", ", "", list_of("one")("two")); - ensure_getTokens("no delims", "one", ",", "", list_of("one")); - - // drop_delims vs. keep_delims - ensure_getTokens("arithmetic", - " ab+def / xx* yy ", " ", "+-*/", - list_of("ab")("+")("def")("/")("xx")("*")("yy")); - - // quotes - ensure_getTokens("no quotes", - "She said, \"Don't go.\"", " ", ",", "", - list_of("She")("said")(",")("\"Don't")("go.\"")); - ensure_getTokens("quotes", - "She said, \"Don't go.\"", " ", ",", "\"", - list_of("She")("said")(",")("Don't go.")); - ensure_getTokens("quotes and delims", - "run c:/'Documents and Settings'/someone", " ", "", "'", - list_of("run")("c:/Documents and Settings/someone")); - ensure_getTokens("unmatched quote", - "baby don't leave", " ", "", "'", - list_of("baby")("don't")("leave")); - ensure_getTokens("adjacent quoted", - "abc'def \"ghi'\"jkl' mno\"pqr", " ", "", "\"'", - list_of("abcdef \"ghijkl' mnopqr")); - ensure_getTokens("quoted empty string", - "--set SomeVar ''", " ", "", "'", - list_of("--set")("SomeVar")("")); - - // escapes - // Don't use backslash as an escape for these tests -- you'll go nuts - // between the C++ string scanner and getTokens() escapes. Test with - // something else! - ensure_equals("escaped delims", - LLStringUtil::getTokens("^ a - dog^-gone^ phrase", " ", "-", "", "^"), - list_of(" a")("-")("dog-gone phrase")); - ensure_equals("escaped quotes", - LLStringUtil::getTokens("say: 'this isn^'t w^orking'.", " ", "", "'", "^"), - list_of("say:")("this isn't working.")); - ensure_equals("escaped escape", - LLStringUtil::getTokens("want x^^2", " ", "", "", "^"), - list_of("want")("x^2")); - ensure_equals("escape at end", - LLStringUtil::getTokens("it's^ up there^", " ", "", "'", "^"), - list_of("it's up")("there^")); + ensure_getTokens("no delims", "one", ",", "", list_of("one")); + + // drop_delims vs. keep_delims + ensure_getTokens("arithmetic", + " ab+def / xx* yy ", " ", "+-*/", + list_of("ab")("+")("def")("/")("xx")("*")("yy")); + + // quotes + ensure_getTokens("no quotes", + "She said, \"Don't go.\"", " ", ",", "", + list_of("She")("said")(",")("\"Don't")("go.\"")); + ensure_getTokens("quotes", + "She said, \"Don't go.\"", " ", ",", "\"", + list_of("She")("said")(",")("Don't go.")); + ensure_getTokens("quotes and delims", + "run c:/'Documents and Settings'/someone", " ", "", "'", + list_of("run")("c:/Documents and Settings/someone")); + ensure_getTokens("unmatched quote", + "baby don't leave", " ", "", "'", + list_of("baby")("don't")("leave")); + ensure_getTokens("adjacent quoted", + "abc'def \"ghi'\"jkl' mno\"pqr", " ", "", "\"'", + list_of("abcdef \"ghijkl' mnopqr")); + ensure_getTokens("quoted empty string", + "--set SomeVar ''", " ", "", "'", + list_of("--set")("SomeVar")("")); + + // escapes + // Don't use backslash as an escape for these tests -- you'll go nuts + // between the C++ string scanner and getTokens() escapes. Test with + // something else! + ensure_equals("escaped delims", + LLStringUtil::getTokens("^ a - dog^-gone^ phrase", " ", "-", "", "^"), + list_of(" a")("-")("dog-gone phrase")); + ensure_equals("escaped quotes", + LLStringUtil::getTokens("say: 'this isn^'t w^orking'.", " ", "", "'", "^"), + list_of("say:")("this isn't working.")); + ensure_equals("escaped escape", + LLStringUtil::getTokens("want x^^2", " ", "", "", "^"), + list_of("want")("x^2")); + ensure_equals("escape at end", + LLStringUtil::getTokens("it's^ up there^", " ", "", "'", "^"), + list_of("it's up")("there^")); } } diff --git a/indra/llcommon/tests/lltrace_test.cpp b/indra/llcommon/tests/lltrace_test.cpp index 0a9d85ad00..8851f87b91 100644 --- a/indra/llcommon/tests/lltrace_test.cpp +++ b/indra/llcommon/tests/lltrace_test.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llsingleton_test.cpp * @date 2011-08-11 * @brief Unit test for the LLSingleton class @@ -34,14 +34,14 @@ namespace LLUnits { - // using powers of 2 to allow strict floating point equality - LL_DECLARE_BASE_UNIT(Ounces, "oz"); - LL_DECLARE_DERIVED_UNIT(TallCup, "", Ounces, / 12); - LL_DECLARE_DERIVED_UNIT(GrandeCup, "", Ounces, / 16); - LL_DECLARE_DERIVED_UNIT(VentiCup, "", Ounces, / 20); - - LL_DECLARE_BASE_UNIT(Grams, "g"); - LL_DECLARE_DERIVED_UNIT(Milligrams, "mg", Grams, * 1000); + // using powers of 2 to allow strict floating point equality + LL_DECLARE_BASE_UNIT(Ounces, "oz"); + LL_DECLARE_DERIVED_UNIT(TallCup, "", Ounces, / 12); + LL_DECLARE_DERIVED_UNIT(GrandeCup, "", Ounces, / 16); + LL_DECLARE_DERIVED_UNIT(VentiCup, "", Ounces, / 20); + + LL_DECLARE_BASE_UNIT(Grams, "g"); + LL_DECLARE_DERIVED_UNIT(Milligrams, "mg", Grams, * 1000); } LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Ounces); @@ -54,89 +54,89 @@ LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Milligrams); namespace tut { - using namespace LLTrace; - struct trace - { - ThreadRecorder mRecorder; - }; - - typedef test_group trace_t; - typedef trace_t::object trace_object_t; - tut::trace_t tut_singleton("LLTrace"); - - static CountStatHandle sCupsOfCoffeeConsumed("coffeeconsumed", "Delicious cup of dark roast."); - static SampleStatHandle sCaffeineLevelStat("caffeinelevel", "Coffee buzz quotient"); - static EventStatHandle sOuncesPerCup("cupsize", "Large, huge, or ginormous"); - - static F32 sCaffeineLevel(0.f); - const F32Milligrams sCaffeinePerOz(18.f); - - void drink_coffee(S32 num_cups, S32Ounces cup_size) - { - add(sCupsOfCoffeeConsumed, num_cups); - for (S32 i = 0; i < num_cups; i++) - { - record(sOuncesPerCup, cup_size); - } - - sCaffeineLevel += F32Ounces(num_cups * cup_size).value() * sCaffeinePerOz.value(); - sample(sCaffeineLevelStat, sCaffeineLevel); - } - - // basic data collection - template<> template<> - void trace_object_t::test<1>() - { - sample(sCaffeineLevelStat, sCaffeineLevel); - - Recording all_day; - Recording at_work; - Recording after_3pm; - - all_day.start(); - { - // warm up with one grande cup - drink_coffee(1, S32TallCup(1)); - - // go to work - at_work.start(); - { - // drink 3 tall cups, 1 after 3 pm - drink_coffee(2, S32GrandeCup(1)); - after_3pm.start(); - drink_coffee(1, S32GrandeCup(1)); - } - at_work.stop(); - drink_coffee(1, S32VentiCup(1)); - } - // don't need to stop recordings to get accurate values out of them - //after_3pm.stop(); - //all_day.stop(); - - ensure("count stats are counted when recording is active", - at_work.getSum(sCupsOfCoffeeConsumed) == 3 - && all_day.getSum(sCupsOfCoffeeConsumed) == 5 - && after_3pm.getSum(sCupsOfCoffeeConsumed) == 2); - ensure("measurement sums are counted when recording is active", - at_work.getSum(sOuncesPerCup) == S32Ounces(48) - && all_day.getSum(sOuncesPerCup) == S32Ounces(80) - && after_3pm.getSum(sOuncesPerCup) == S32Ounces(36)); - ensure("measurement min is specific to when recording is active", - at_work.getMin(sOuncesPerCup) == S32GrandeCup(1) - && all_day.getMin(sOuncesPerCup) == S32TallCup(1) - && after_3pm.getMin(sOuncesPerCup) == S32GrandeCup(1)); - ensure("measurement max is specific to when recording is active", - at_work.getMax(sOuncesPerCup) == S32GrandeCup(1) - && all_day.getMax(sOuncesPerCup) == S32VentiCup(1) - && after_3pm.getMax(sOuncesPerCup) == S32VentiCup(1)); - ensure("sample min is specific to when recording is active", - at_work.getMin(sCaffeineLevelStat) == sCaffeinePerOz * ((S32Ounces)S32TallCup(1)).value() - && all_day.getMin(sCaffeineLevelStat) == F32Milligrams(0.f) - && after_3pm.getMin(sCaffeineLevelStat) == sCaffeinePerOz * ((S32Ounces)S32TallCup(1) + (S32Ounces)S32GrandeCup(2)).value()); - ensure("sample max is specific to when recording is active", - at_work.getMax(sCaffeineLevelStat) == sCaffeinePerOz * ((S32Ounces)S32TallCup(1) + (S32Ounces)S32GrandeCup(3)).value() - && all_day.getMax(sCaffeineLevelStat) == sCaffeinePerOz * ((S32Ounces)S32TallCup(1) + (S32Ounces)S32GrandeCup(3) + (S32Ounces)S32VentiCup(1)).value() - && after_3pm.getMax(sCaffeineLevelStat) == sCaffeinePerOz * ((S32Ounces)S32TallCup(1) + (S32Ounces)S32GrandeCup(3) + (S32Ounces)S32VentiCup(1)).value()); - } + using namespace LLTrace; + struct trace + { + ThreadRecorder mRecorder; + }; + + typedef test_group trace_t; + typedef trace_t::object trace_object_t; + tut::trace_t tut_singleton("LLTrace"); + + static CountStatHandle sCupsOfCoffeeConsumed("coffeeconsumed", "Delicious cup of dark roast."); + static SampleStatHandle sCaffeineLevelStat("caffeinelevel", "Coffee buzz quotient"); + static EventStatHandle sOuncesPerCup("cupsize", "Large, huge, or ginormous"); + + static F32 sCaffeineLevel(0.f); + const F32Milligrams sCaffeinePerOz(18.f); + + void drink_coffee(S32 num_cups, S32Ounces cup_size) + { + add(sCupsOfCoffeeConsumed, num_cups); + for (S32 i = 0; i < num_cups; i++) + { + record(sOuncesPerCup, cup_size); + } + + sCaffeineLevel += F32Ounces(num_cups * cup_size).value() * sCaffeinePerOz.value(); + sample(sCaffeineLevelStat, sCaffeineLevel); + } + + // basic data collection + template<> template<> + void trace_object_t::test<1>() + { + sample(sCaffeineLevelStat, sCaffeineLevel); + + Recording all_day; + Recording at_work; + Recording after_3pm; + + all_day.start(); + { + // warm up with one grande cup + drink_coffee(1, S32TallCup(1)); + + // go to work + at_work.start(); + { + // drink 3 tall cups, 1 after 3 pm + drink_coffee(2, S32GrandeCup(1)); + after_3pm.start(); + drink_coffee(1, S32GrandeCup(1)); + } + at_work.stop(); + drink_coffee(1, S32VentiCup(1)); + } + // don't need to stop recordings to get accurate values out of them + //after_3pm.stop(); + //all_day.stop(); + + ensure("count stats are counted when recording is active", + at_work.getSum(sCupsOfCoffeeConsumed) == 3 + && all_day.getSum(sCupsOfCoffeeConsumed) == 5 + && after_3pm.getSum(sCupsOfCoffeeConsumed) == 2); + ensure("measurement sums are counted when recording is active", + at_work.getSum(sOuncesPerCup) == S32Ounces(48) + && all_day.getSum(sOuncesPerCup) == S32Ounces(80) + && after_3pm.getSum(sOuncesPerCup) == S32Ounces(36)); + ensure("measurement min is specific to when recording is active", + at_work.getMin(sOuncesPerCup) == S32GrandeCup(1) + && all_day.getMin(sOuncesPerCup) == S32TallCup(1) + && after_3pm.getMin(sOuncesPerCup) == S32GrandeCup(1)); + ensure("measurement max is specific to when recording is active", + at_work.getMax(sOuncesPerCup) == S32GrandeCup(1) + && all_day.getMax(sOuncesPerCup) == S32VentiCup(1) + && after_3pm.getMax(sOuncesPerCup) == S32VentiCup(1)); + ensure("sample min is specific to when recording is active", + at_work.getMin(sCaffeineLevelStat) == sCaffeinePerOz * ((S32Ounces)S32TallCup(1)).value() + && all_day.getMin(sCaffeineLevelStat) == F32Milligrams(0.f) + && after_3pm.getMin(sCaffeineLevelStat) == sCaffeinePerOz * ((S32Ounces)S32TallCup(1) + (S32Ounces)S32GrandeCup(2)).value()); + ensure("sample max is specific to when recording is active", + at_work.getMax(sCaffeineLevelStat) == sCaffeinePerOz * ((S32Ounces)S32TallCup(1) + (S32Ounces)S32GrandeCup(3)).value() + && all_day.getMax(sCaffeineLevelStat) == sCaffeinePerOz * ((S32Ounces)S32TallCup(1) + (S32Ounces)S32GrandeCup(3) + (S32Ounces)S32VentiCup(1)).value() + && after_3pm.getMax(sCaffeineLevelStat) == sCaffeinePerOz * ((S32Ounces)S32TallCup(1) + (S32Ounces)S32GrandeCup(3) + (S32Ounces)S32VentiCup(1)).value()); + } } diff --git a/indra/llcommon/tests/lltreeiterators_test.cpp b/indra/llcommon/tests/lltreeiterators_test.cpp index b9c7a70c07..7a2adfd8ba 100644 --- a/indra/llcommon/tests/lltreeiterators_test.cpp +++ b/indra/llcommon/tests/lltreeiterators_test.cpp @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2008-08-20 * @brief Test of lltreeiterators.h - * + * * $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$ */ @@ -1045,7 +1045,7 @@ bool LLTreeWalkIter_test(const std::string& itername, const std::string& nodenam { std::cout << itername << '<' << nodename << ">(NULL)\n"; return false; - } + } return true; } @@ -1107,7 +1107,7 @@ namespace tut TreeNodePtr tnroot(example_tree()); TreeNodePtr tnB2b(get_B2b (tnroot, boost::bind(&TreeNode::child_begin, _1))); - + std::string desc1("for (TreeNodePr : getRootRange(tnB2b))"); // std::cout << desc1 << "\n"; // Although we've commented out the output statement, ensure that the diff --git a/indra/llcommon/tests/llunits_test.cpp b/indra/llcommon/tests/llunits_test.cpp index 57cf9810af..49f2d3085a 100644 --- a/indra/llcommon/tests/llunits_test.cpp +++ b/indra/llcommon/tests/llunits_test.cpp @@ -1,4 +1,4 @@ -/** +/** * @file llsingleton_test.cpp * @date 2011-08-11 * @brief Unit test for the LLSingleton class @@ -32,10 +32,10 @@ namespace LLUnits { - // using powers of 2 to allow strict floating point equality - LL_DECLARE_BASE_UNIT(Quatloos, "Quat"); - LL_DECLARE_DERIVED_UNIT(Latinum, "Lat", Quatloos, / 4); - LL_DECLARE_DERIVED_UNIT(Solari, "Sol", Latinum, * 16); + // using powers of 2 to allow strict floating point equality + LL_DECLARE_BASE_UNIT(Quatloos, "Quat"); + LL_DECLARE_DERIVED_UNIT(Latinum, "Lat", Quatloos, / 4); + LL_DECLARE_DERIVED_UNIT(Solari, "Sol", Latinum, * 16); } LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Quatloos); @@ -44,9 +44,9 @@ LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Solari); namespace LLUnits { - LL_DECLARE_BASE_UNIT(Celcius, "c"); - LL_DECLARE_DERIVED_UNIT(Fahrenheit, "f", Celcius, * 9 / 5 + 32); - LL_DECLARE_DERIVED_UNIT(Kelvin, "k", Celcius, + 273.15f); + LL_DECLARE_BASE_UNIT(Celcius, "c"); + LL_DECLARE_DERIVED_UNIT(Fahrenheit, "f", Celcius, * 9 / 5 + 32); + LL_DECLARE_DERIVED_UNIT(Kelvin, "k", Celcius, + 273.15f); } LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Celcius); @@ -56,333 +56,333 @@ LL_DECLARE_UNIT_TYPEDEFS(LLUnits, Kelvin); namespace tut { - using namespace LLUnits; - struct units - { - }; - - typedef test_group units_t; - typedef units_t::object units_object_t; - tut::units_t tut_singleton("LLUnit"); - - // storage type conversions - template<> template<> - void units_object_t::test<1>() - { - LLUnit float_quatloos; - ensure("default float unit is zero", float_quatloos == F32Quatloos(0.f)); - - LLUnit float_initialize_quatloos(1); - ensure("non-zero initialized unit", float_initialize_quatloos == F32Quatloos(1.f)); - - LLUnit int_quatloos; - ensure("default int unit is zero", int_quatloos == S32Quatloos(0)); - - int_quatloos = S32Quatloos(42); - ensure("int assignment is preserved", int_quatloos == S32Quatloos(42)); - float_quatloos = int_quatloos; - ensure("float assignment from int preserves value", float_quatloos == F32Quatloos(42.f)); - - int_quatloos = float_quatloos; - ensure("int assignment from float preserves value", int_quatloos == S32Quatloos(42)); - - float_quatloos = F32Quatloos(42.1f); - int_quatloos = float_quatloos; - ensure("int units truncate float units on assignment", int_quatloos == S32Quatloos(42)); - - LLUnit unsigned_int_quatloos(float_quatloos); - ensure("unsigned int can be initialized from signed int", unsigned_int_quatloos == S32Quatloos(42)); - - S32Solari int_solari(1); - - float_quatloos = int_solari; - ensure("fractional units are preserved in conversion from integer to float type", float_quatloos == F32Quatloos(0.25f)); - - int_quatloos = S32Quatloos(1); - F32Solari float_solari = int_quatloos; - ensure("can convert with fractional intermediates from integer to float type", float_solari == F32Solari(4.f)); - } - - // conversions to/from base unit - template<> template<> - void units_object_t::test<2>() - { - LLUnit quatloos(1.f); - LLUnit latinum_bars(quatloos); - ensure("conversion between units is automatic via initialization", latinum_bars == F32Latinum(1.f / 4.f)); - - latinum_bars = S32Latinum(256); - quatloos = latinum_bars; - ensure("conversion between units is automatic via assignment, and bidirectional", quatloos == S32Quatloos(1024)); - - LLUnit single_quatloo(1); - LLUnit quarter_latinum = single_quatloo; - ensure("division of integer unit preserves fractional values when converted to float unit", quarter_latinum == F32Latinum(0.25f)); - } - - // conversions across non-base units - template<> template<> - void units_object_t::test<3>() - { - LLUnit quatloos(1024); - LLUnit solari(quatloos); - ensure("conversions can work between indirectly related units: Quatloos -> Latinum -> Solari", solari == S32Solari(4096)); - - LLUnit latinum_bars = solari; - ensure("Non base units can be converted between each other", latinum_bars == S32Latinum(256)); - } - - // math operations - template<> template<> - void units_object_t::test<4>() - { - // exercise math operations - LLUnit quatloos(1.f); - quatloos *= 4.f; - ensure(quatloos == S32Quatloos(4)); - quatloos = quatloos * 2; - ensure(quatloos == S32Quatloos(8)); - quatloos = 2.f * quatloos; - ensure(quatloos == S32Quatloos(16)); - - quatloos += F32Quatloos(4.f); - ensure(quatloos == S32Quatloos(20)); - quatloos += S32Quatloos(4); - ensure(quatloos == S32Quatloos(24)); - quatloos = quatloos + S32Quatloos(4); - ensure(quatloos == S32Quatloos(28)); - quatloos = S32Quatloos(4) + quatloos; - ensure(quatloos == S32Quatloos(32)); - quatloos += quatloos * 3; - ensure(quatloos == S32Quatloos(128)); - - quatloos -= quatloos / 4 * 3; - ensure(quatloos == S32Quatloos(32)); - quatloos = quatloos - S32Quatloos(8); - ensure(quatloos == S32Quatloos(24)); - quatloos -= S32Quatloos(4); - ensure(quatloos == S32Quatloos(20)); - quatloos -= F32Quatloos(4.f); - ensure(quatloos == S32Quatloos(16)); - - quatloos /= 2.f; - ensure(quatloos == S32Quatloos(8)); - quatloos = quatloos / 4; - ensure(quatloos == S32Quatloos(2)); - - F32 ratio = quatloos / LLUnit(2.f); - ensure(ratio == 1); - ratio = quatloos / LLUnit(8.f); - ensure(ratio == 1); - - quatloos += LLUnit(8.f); - ensure(quatloos == S32Quatloos(4)); - quatloos -= LLUnit(1.f); - ensure(quatloos == S32Quatloos(0)); - } - - // comparison operators - template<> template<> - void units_object_t::test<5>() - { - LLUnit quatloos(1); - ensure("can perform less than comparison against same type", quatloos < S32Quatloos(2)); - ensure("can perform less than comparison against different storage type", quatloos < F32Quatloos(2.f)); - ensure("can perform less than comparison against different units", quatloos < S32Latinum(5)); - ensure("can perform less than comparison against different storage type and units", quatloos < F32Latinum(5.f)); - - ensure("can perform greater than comparison against same type", quatloos > S32Quatloos(0)); - ensure("can perform greater than comparison against different storage type", quatloos > F32Quatloos(0.f)); - ensure("can perform greater than comparison against different units", quatloos > S32Latinum(0)); - ensure("can perform greater than comparison against different storage type and units", quatloos > F32Latinum(0.f)); - - } - - bool accept_explicit_quatloos(S32Quatloos q) - { - return true; - } - - bool accept_implicit_quatloos(S32Quatloos q) - { - return true; - } - - // signature compatibility - template<> template<> - void units_object_t::test<6>() - { - S32Quatloos quatloos(1); - ensure("can pass unit values as argument", accept_explicit_quatloos(S32Quatloos(1))); - ensure("can pass unit values as argument", accept_explicit_quatloos(quatloos)); - } - - // implicit units - template<> template<> - void units_object_t::test<7>() - { - LLUnit quatloos; - LLUnitImplicit quatloos_implicit = quatloos + S32Quatloos(1); - ensure("can initialize implicit unit from explicit", quatloos_implicit == 1); - - quatloos = quatloos_implicit; - ensure("can assign implicit unit to explicit unit", quatloos == S32Quatloos(1)); - quatloos += quatloos_implicit; - ensure("can perform math operation using mixture of implicit and explicit units", quatloos == S32Quatloos(2)); - - // math operations on implicits - quatloos_implicit = 1; - ensure(quatloos_implicit == 1); - - quatloos_implicit += 2; - ensure(quatloos_implicit == 3); - - quatloos_implicit *= 2; - ensure(quatloos_implicit == 6); - - quatloos_implicit -= 1; - ensure(quatloos_implicit == 5); - - quatloos_implicit /= 5; - ensure(quatloos_implicit == 1); - - quatloos_implicit = quatloos_implicit + 3 + quatloos_implicit; - ensure(quatloos_implicit == 5); - - quatloos_implicit = 10 - quatloos_implicit - 1; - ensure(quatloos_implicit == 4); - - quatloos_implicit = 2 * quatloos_implicit * 2; - ensure(quatloos_implicit == 16); - - F32 one_half = quatloos_implicit / (quatloos_implicit * 2); - ensure(one_half == 0.5f); - - // implicit conversion to POD - F32 float_val = quatloos_implicit; - ensure("implicit units convert implicitly to regular values", float_val == 16); - - S32 int_val = quatloos_implicit; - ensure("implicit units convert implicitly to regular values", int_val == 16); - - // conversion of implicits - LLUnitImplicit latinum_implicit(2); - ensure("implicit units of different types are comparable", latinum_implicit * 2 == quatloos_implicit); - - quatloos_implicit += F32Quatloos(10); - ensure("can add-assign explicit units", quatloos_implicit == 26); - - quatloos_implicit -= F32Quatloos(10); - ensure("can subtract-assign explicit units", quatloos_implicit == 16); - - // comparisons - ensure("can compare greater than implicit unit", quatloos_implicit > F32QuatloosImplicit(0.f)); - ensure("can compare greater than non-implicit unit", quatloos_implicit > F32Quatloos(0.f)); - ensure("can compare greater than or equal to implicit unit", quatloos_implicit >= F32QuatloosImplicit(0.f)); - ensure("can compare greater than or equal to non-implicit unit", quatloos_implicit >= F32Quatloos(0.f)); - ensure("can compare less than implicit unit", quatloos_implicit < F32QuatloosImplicit(20.f)); - ensure("can compare less than non-implicit unit", quatloos_implicit < F32Quatloos(20.f)); - ensure("can compare less than or equal to implicit unit", quatloos_implicit <= F32QuatloosImplicit(20.f)); - ensure("can compare less than or equal to non-implicit unit", quatloos_implicit <= F32Quatloos(20.f)); - } - - // precision tests - template<> template<> - void units_object_t::test<8>() - { - U32Bytes max_bytes(U32_MAX); - S32Megabytes mega_bytes = max_bytes; - ensure("max available precision is used when converting units", mega_bytes == (S32Megabytes)4095); - - mega_bytes = (S32Megabytes)-5 + (U32Megabytes)1; - ensure("can mix signed and unsigned in units addition", mega_bytes == (S32Megabytes)-4); - - mega_bytes = (U32Megabytes)5 + (S32Megabytes)-1; - ensure("can mix unsigned and signed in units addition", mega_bytes == (S32Megabytes)4); - } - - // default units - template<> template<> - void units_object_t::test<9>() - { - U32Gigabytes GB(1); - U32Megabytes MB(GB); - U32Kilobytes KB(GB); - U32Bytes B(GB); - - ensure("GB -> MB conversion", MB.value() == 1024); - ensure("GB -> KB conversion", KB.value() == 1024 * 1024); - ensure("GB -> B conversion", B.value() == 1024 * 1024 * 1024); - - KB = U32Kilobytes(1); - U32Kilobits Kb(KB); - U32Bits b(KB); - ensure("KB -> Kb conversion", Kb.value() == 8); - ensure("KB -> b conversion", b.value() == 8 * 1024); - - U32Days days(1); - U32Hours hours(days); - U32Minutes minutes(days); - U32Seconds seconds(days); - U32Milliseconds ms(days); - - ensure("days -> hours conversion", hours.value() == 24); - ensure("days -> minutes conversion", minutes.value() == 24 * 60); - ensure("days -> seconds conversion", seconds.value() == 24 * 60 * 60); - ensure("days -> ms conversion", ms.value() == 24 * 60 * 60 * 1000); - - U32Kilometers km(1); - U32Meters m(km); - U32Centimeters cm(km); - U32Millimeters mm(km); - - ensure("km -> m conversion", m.value() == 1000); - ensure("km -> cm conversion", cm.value() == 1000 * 100); - ensure("km -> mm conversion", mm.value() == 1000 * 1000); - - U32Gigahertz GHz(1); - U32Megahertz MHz(GHz); - U32Kilohertz KHz(GHz); - U32Hertz Hz(GHz); - - ensure("GHz -> MHz conversion", MHz.value() == 1000); - ensure("GHz -> KHz conversion", KHz.value() == 1000 * 1000); - ensure("GHz -> Hz conversion", Hz.value() == 1000 * 1000 * 1000); - - F32Radians rad(6.2831853071795f); - S32Degrees deg(rad); - ensure("radians -> degrees conversion", deg.value() == 360); - - F32Percent percent(50); - F32Ratio ratio(percent); - ensure("percent -> ratio conversion", ratio.value() == 0.5f); - - U32Kilotriangles ktris(1); - U32Triangles tris(ktris); - ensure("kilotriangles -> triangles conversion", tris.value() == 1000); - } - - bool value_near(F32 value, F32 target, F32 threshold) - { - return fabsf(value - target) < threshold; - } - - // linear transforms - template<> template<> - void units_object_t::test<10>() - { - F32Celcius float_celcius(100); - F32Fahrenheit float_fahrenheit(float_celcius); - ensure("floating point celcius -> fahrenheit conversion using linear transform", value_near(float_fahrenheit.value(), 212, 0.1f) ); - - float_celcius = float_fahrenheit; - ensure("floating point fahrenheit -> celcius conversion using linear transform (round trip)", value_near(float_celcius.value(), 100.f, 0.1f) ); - - S32Celcius int_celcius(100); - S32Fahrenheit int_fahrenheit(int_celcius); - ensure("integer celcius -> fahrenheit conversion using linear transform", int_fahrenheit.value() == 212); - - int_celcius = int_fahrenheit; - ensure("integer fahrenheit -> celcius conversion using linear transform (round trip)", int_celcius.value() == 100); - } + using namespace LLUnits; + struct units + { + }; + + typedef test_group units_t; + typedef units_t::object units_object_t; + tut::units_t tut_singleton("LLUnit"); + + // storage type conversions + template<> template<> + void units_object_t::test<1>() + { + LLUnit float_quatloos; + ensure("default float unit is zero", float_quatloos == F32Quatloos(0.f)); + + LLUnit float_initialize_quatloos(1); + ensure("non-zero initialized unit", float_initialize_quatloos == F32Quatloos(1.f)); + + LLUnit int_quatloos; + ensure("default int unit is zero", int_quatloos == S32Quatloos(0)); + + int_quatloos = S32Quatloos(42); + ensure("int assignment is preserved", int_quatloos == S32Quatloos(42)); + float_quatloos = int_quatloos; + ensure("float assignment from int preserves value", float_quatloos == F32Quatloos(42.f)); + + int_quatloos = float_quatloos; + ensure("int assignment from float preserves value", int_quatloos == S32Quatloos(42)); + + float_quatloos = F32Quatloos(42.1f); + int_quatloos = float_quatloos; + ensure("int units truncate float units on assignment", int_quatloos == S32Quatloos(42)); + + LLUnit unsigned_int_quatloos(float_quatloos); + ensure("unsigned int can be initialized from signed int", unsigned_int_quatloos == S32Quatloos(42)); + + S32Solari int_solari(1); + + float_quatloos = int_solari; + ensure("fractional units are preserved in conversion from integer to float type", float_quatloos == F32Quatloos(0.25f)); + + int_quatloos = S32Quatloos(1); + F32Solari float_solari = int_quatloos; + ensure("can convert with fractional intermediates from integer to float type", float_solari == F32Solari(4.f)); + } + + // conversions to/from base unit + template<> template<> + void units_object_t::test<2>() + { + LLUnit quatloos(1.f); + LLUnit latinum_bars(quatloos); + ensure("conversion between units is automatic via initialization", latinum_bars == F32Latinum(1.f / 4.f)); + + latinum_bars = S32Latinum(256); + quatloos = latinum_bars; + ensure("conversion between units is automatic via assignment, and bidirectional", quatloos == S32Quatloos(1024)); + + LLUnit single_quatloo(1); + LLUnit quarter_latinum = single_quatloo; + ensure("division of integer unit preserves fractional values when converted to float unit", quarter_latinum == F32Latinum(0.25f)); + } + + // conversions across non-base units + template<> template<> + void units_object_t::test<3>() + { + LLUnit quatloos(1024); + LLUnit solari(quatloos); + ensure("conversions can work between indirectly related units: Quatloos -> Latinum -> Solari", solari == S32Solari(4096)); + + LLUnit latinum_bars = solari; + ensure("Non base units can be converted between each other", latinum_bars == S32Latinum(256)); + } + + // math operations + template<> template<> + void units_object_t::test<4>() + { + // exercise math operations + LLUnit quatloos(1.f); + quatloos *= 4.f; + ensure(quatloos == S32Quatloos(4)); + quatloos = quatloos * 2; + ensure(quatloos == S32Quatloos(8)); + quatloos = 2.f * quatloos; + ensure(quatloos == S32Quatloos(16)); + + quatloos += F32Quatloos(4.f); + ensure(quatloos == S32Quatloos(20)); + quatloos += S32Quatloos(4); + ensure(quatloos == S32Quatloos(24)); + quatloos = quatloos + S32Quatloos(4); + ensure(quatloos == S32Quatloos(28)); + quatloos = S32Quatloos(4) + quatloos; + ensure(quatloos == S32Quatloos(32)); + quatloos += quatloos * 3; + ensure(quatloos == S32Quatloos(128)); + + quatloos -= quatloos / 4 * 3; + ensure(quatloos == S32Quatloos(32)); + quatloos = quatloos - S32Quatloos(8); + ensure(quatloos == S32Quatloos(24)); + quatloos -= S32Quatloos(4); + ensure(quatloos == S32Quatloos(20)); + quatloos -= F32Quatloos(4.f); + ensure(quatloos == S32Quatloos(16)); + + quatloos /= 2.f; + ensure(quatloos == S32Quatloos(8)); + quatloos = quatloos / 4; + ensure(quatloos == S32Quatloos(2)); + + F32 ratio = quatloos / LLUnit(2.f); + ensure(ratio == 1); + ratio = quatloos / LLUnit(8.f); + ensure(ratio == 1); + + quatloos += LLUnit(8.f); + ensure(quatloos == S32Quatloos(4)); + quatloos -= LLUnit(1.f); + ensure(quatloos == S32Quatloos(0)); + } + + // comparison operators + template<> template<> + void units_object_t::test<5>() + { + LLUnit quatloos(1); + ensure("can perform less than comparison against same type", quatloos < S32Quatloos(2)); + ensure("can perform less than comparison against different storage type", quatloos < F32Quatloos(2.f)); + ensure("can perform less than comparison against different units", quatloos < S32Latinum(5)); + ensure("can perform less than comparison against different storage type and units", quatloos < F32Latinum(5.f)); + + ensure("can perform greater than comparison against same type", quatloos > S32Quatloos(0)); + ensure("can perform greater than comparison against different storage type", quatloos > F32Quatloos(0.f)); + ensure("can perform greater than comparison against different units", quatloos > S32Latinum(0)); + ensure("can perform greater than comparison against different storage type and units", quatloos > F32Latinum(0.f)); + + } + + bool accept_explicit_quatloos(S32Quatloos q) + { + return true; + } + + bool accept_implicit_quatloos(S32Quatloos q) + { + return true; + } + + // signature compatibility + template<> template<> + void units_object_t::test<6>() + { + S32Quatloos quatloos(1); + ensure("can pass unit values as argument", accept_explicit_quatloos(S32Quatloos(1))); + ensure("can pass unit values as argument", accept_explicit_quatloos(quatloos)); + } + + // implicit units + template<> template<> + void units_object_t::test<7>() + { + LLUnit quatloos; + LLUnitImplicit quatloos_implicit = quatloos + S32Quatloos(1); + ensure("can initialize implicit unit from explicit", quatloos_implicit == 1); + + quatloos = quatloos_implicit; + ensure("can assign implicit unit to explicit unit", quatloos == S32Quatloos(1)); + quatloos += quatloos_implicit; + ensure("can perform math operation using mixture of implicit and explicit units", quatloos == S32Quatloos(2)); + + // math operations on implicits + quatloos_implicit = 1; + ensure(quatloos_implicit == 1); + + quatloos_implicit += 2; + ensure(quatloos_implicit == 3); + + quatloos_implicit *= 2; + ensure(quatloos_implicit == 6); + + quatloos_implicit -= 1; + ensure(quatloos_implicit == 5); + + quatloos_implicit /= 5; + ensure(quatloos_implicit == 1); + + quatloos_implicit = quatloos_implicit + 3 + quatloos_implicit; + ensure(quatloos_implicit == 5); + + quatloos_implicit = 10 - quatloos_implicit - 1; + ensure(quatloos_implicit == 4); + + quatloos_implicit = 2 * quatloos_implicit * 2; + ensure(quatloos_implicit == 16); + + F32 one_half = quatloos_implicit / (quatloos_implicit * 2); + ensure(one_half == 0.5f); + + // implicit conversion to POD + F32 float_val = quatloos_implicit; + ensure("implicit units convert implicitly to regular values", float_val == 16); + + S32 int_val = quatloos_implicit; + ensure("implicit units convert implicitly to regular values", int_val == 16); + + // conversion of implicits + LLUnitImplicit latinum_implicit(2); + ensure("implicit units of different types are comparable", latinum_implicit * 2 == quatloos_implicit); + + quatloos_implicit += F32Quatloos(10); + ensure("can add-assign explicit units", quatloos_implicit == 26); + + quatloos_implicit -= F32Quatloos(10); + ensure("can subtract-assign explicit units", quatloos_implicit == 16); + + // comparisons + ensure("can compare greater than implicit unit", quatloos_implicit > F32QuatloosImplicit(0.f)); + ensure("can compare greater than non-implicit unit", quatloos_implicit > F32Quatloos(0.f)); + ensure("can compare greater than or equal to implicit unit", quatloos_implicit >= F32QuatloosImplicit(0.f)); + ensure("can compare greater than or equal to non-implicit unit", quatloos_implicit >= F32Quatloos(0.f)); + ensure("can compare less than implicit unit", quatloos_implicit < F32QuatloosImplicit(20.f)); + ensure("can compare less than non-implicit unit", quatloos_implicit < F32Quatloos(20.f)); + ensure("can compare less than or equal to implicit unit", quatloos_implicit <= F32QuatloosImplicit(20.f)); + ensure("can compare less than or equal to non-implicit unit", quatloos_implicit <= F32Quatloos(20.f)); + } + + // precision tests + template<> template<> + void units_object_t::test<8>() + { + U32Bytes max_bytes(U32_MAX); + S32Megabytes mega_bytes = max_bytes; + ensure("max available precision is used when converting units", mega_bytes == (S32Megabytes)4095); + + mega_bytes = (S32Megabytes)-5 + (U32Megabytes)1; + ensure("can mix signed and unsigned in units addition", mega_bytes == (S32Megabytes)-4); + + mega_bytes = (U32Megabytes)5 + (S32Megabytes)-1; + ensure("can mix unsigned and signed in units addition", mega_bytes == (S32Megabytes)4); + } + + // default units + template<> template<> + void units_object_t::test<9>() + { + U32Gigabytes GB(1); + U32Megabytes MB(GB); + U32Kilobytes KB(GB); + U32Bytes B(GB); + + ensure("GB -> MB conversion", MB.value() == 1024); + ensure("GB -> KB conversion", KB.value() == 1024 * 1024); + ensure("GB -> B conversion", B.value() == 1024 * 1024 * 1024); + + KB = U32Kilobytes(1); + U32Kilobits Kb(KB); + U32Bits b(KB); + ensure("KB -> Kb conversion", Kb.value() == 8); + ensure("KB -> b conversion", b.value() == 8 * 1024); + + U32Days days(1); + U32Hours hours(days); + U32Minutes minutes(days); + U32Seconds seconds(days); + U32Milliseconds ms(days); + + ensure("days -> hours conversion", hours.value() == 24); + ensure("days -> minutes conversion", minutes.value() == 24 * 60); + ensure("days -> seconds conversion", seconds.value() == 24 * 60 * 60); + ensure("days -> ms conversion", ms.value() == 24 * 60 * 60 * 1000); + + U32Kilometers km(1); + U32Meters m(km); + U32Centimeters cm(km); + U32Millimeters mm(km); + + ensure("km -> m conversion", m.value() == 1000); + ensure("km -> cm conversion", cm.value() == 1000 * 100); + ensure("km -> mm conversion", mm.value() == 1000 * 1000); + + U32Gigahertz GHz(1); + U32Megahertz MHz(GHz); + U32Kilohertz KHz(GHz); + U32Hertz Hz(GHz); + + ensure("GHz -> MHz conversion", MHz.value() == 1000); + ensure("GHz -> KHz conversion", KHz.value() == 1000 * 1000); + ensure("GHz -> Hz conversion", Hz.value() == 1000 * 1000 * 1000); + + F32Radians rad(6.2831853071795f); + S32Degrees deg(rad); + ensure("radians -> degrees conversion", deg.value() == 360); + + F32Percent percent(50); + F32Ratio ratio(percent); + ensure("percent -> ratio conversion", ratio.value() == 0.5f); + + U32Kilotriangles ktris(1); + U32Triangles tris(ktris); + ensure("kilotriangles -> triangles conversion", tris.value() == 1000); + } + + bool value_near(F32 value, F32 target, F32 threshold) + { + return fabsf(value - target) < threshold; + } + + // linear transforms + template<> template<> + void units_object_t::test<10>() + { + F32Celcius float_celcius(100); + F32Fahrenheit float_fahrenheit(float_celcius); + ensure("floating point celcius -> fahrenheit conversion using linear transform", value_near(float_fahrenheit.value(), 212, 0.1f) ); + + float_celcius = float_fahrenheit; + ensure("floating point fahrenheit -> celcius conversion using linear transform (round trip)", value_near(float_celcius.value(), 100.f, 0.1f) ); + + S32Celcius int_celcius(100); + S32Fahrenheit int_fahrenheit(int_celcius); + ensure("integer celcius -> fahrenheit conversion using linear transform", int_fahrenheit.value() == 212); + + int_celcius = int_fahrenheit; + ensure("integer fahrenheit -> celcius conversion using linear transform (round trip)", int_celcius.value() == 100); + } } diff --git a/indra/llcommon/tests/lluri_test.cpp b/indra/llcommon/tests/lluri_test.cpp index 1a4c6641b9..b48dd3ef1b 100644 --- a/indra/llcommon/tests/lluri_test.cpp +++ b/indra/llcommon/tests/lluri_test.cpp @@ -6,21 +6,21 @@ * $LicenseInfo:firstyear=2006&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -34,359 +34,359 @@ namespace tut { - struct URITestData { - void checkParts(const LLURI& u, - const char* expectedScheme, - const char* expectedOpaque, - const char* expectedAuthority, - const char* expectedPath, - const char* expectedQuery = "") - { - ensure_equals("scheme", u.scheme(), expectedScheme); - ensure_equals("opaque", u.opaque(), expectedOpaque); - ensure_equals("authority", u.authority(), expectedAuthority); - ensure_equals("path", u.path(), expectedPath); - ensure_equals("query", u.query(), expectedQuery); - } - - void escapeRoundTrip(const std::string& uri_raw_1) - { - std::string uri_esc_1(LLURI::escape(uri_raw_1)); - std::string uri_raw_2(LLURI::unescape(uri_esc_1)); - ensure_equals("escape/unescape raw", uri_raw_2, uri_raw_1); - std::string uri_esc_2(LLURI::escape(uri_raw_2)); - ensure_equals("escape/unescape escaped", uri_esc_2, uri_esc_1); - } - }; - - typedef test_group URITestGroup; - typedef URITestGroup::object URITestObject; - - URITestGroup uriTestGroup("LLURI"); - - template<> template<> - void URITestObject::test<1>() - { - LLURI u("http://abc.com/def/ghi?x=37&y=hello"); - - ensure_equals("scheme", u.scheme(), "http"); - ensure_equals("authority", u.authority(), "abc.com"); - ensure_equals("path", u.path(), "/def/ghi"); - ensure_equals("query", u.query(), "x=37&y=hello"); - - ensure_equals("host name", u.hostName(), "abc.com"); - ensure_equals("host port", u.hostPort(), 80); - - LLSD query = u.queryMap(); - ensure_equals("query x", query["x"].asInteger(), 37); - ensure_equals("query y", query["y"].asString(), "hello"); - - query = LLURI::queryMap("x=22.23&y=https://lindenlab.com/"); - ensure_equals("query x", query["x"].asReal(), 22.23); - ensure_equals("query y", query["y"].asURI().asString(), "https://lindenlab.com/"); - } - - template<> template<> - void URITestObject::test<2>() - { - set_test_name("empty string"); - checkParts(LLURI(""), "", "", "", ""); - } - - template<> template<> - void URITestObject::test<3>() - { - set_test_name("no scheme"); - checkParts(LLURI("foo"), "", "foo", "", ""); - checkParts(LLURI("foo%3A"), "", "foo:", "", ""); - } - - template<> template<> - void URITestObject::test<4>() - { - set_test_name("scheme w/o paths"); - checkParts(LLURI("mailto:zero@ll.com"), - "mailto", "zero@ll.com", "", ""); - checkParts(LLURI("silly://abc/def?foo"), - "silly", "//abc/def?foo", "", ""); - } - - template<> template<> - void URITestObject::test<5>() - { - set_test_name("authority section"); - checkParts(LLURI("http:///"), - "http", "///", "", "/"); - - checkParts(LLURI("http://abc"), - "http", "//abc", "abc", ""); - - checkParts(LLURI("http://a%2Fb/cd"), - "http", "//a/b/cd", "a/b", "/cd"); - - checkParts(LLURI("http://host?"), - "http", "//host?", "host", ""); - } - - template<> template<> - void URITestObject::test<6>() - { - set_test_name("path section"); - checkParts(LLURI("http://host/a/b/"), - "http", "//host/a/b/", "host", "/a/b/"); - - checkParts(LLURI("http://host/a%3Fb/"), - "http", "//host/a?b/", "host", "/a?b/"); - - checkParts(LLURI("http://host/a:b/"), - "http", "//host/a:b/", "host", "/a:b/"); - } - - template<> template<> - void URITestObject::test<7>() - { - set_test_name("query string"); - checkParts(LLURI("http://host/?"), - "http", "//host/?", "host", "/", ""); - - checkParts(LLURI("http://host/?x"), - "http", "//host/?x", "host", "/", "x"); - - checkParts(LLURI("http://host/??"), - "http", "//host/??", "host", "/", "?"); - - checkParts(LLURI("http://host/?%3F"), - "http", "//host/??", "host", "/", "?"); - } - - template<> template<> - void URITestObject::test<8>() - { - LLSD path; - path.append("x"); - path.append("123"); - checkParts(LLURI::buildHTTP("host", path), - "http", "//host/x/123", "host", "/x/123"); - - LLSD query; - query["123"] = "12"; - query["abcd"] = "abc"; - checkParts(LLURI::buildHTTP("host", path, query), - "http", "//host/x/123?123=12&abcd=abc", - "host", "/x/123", "123=12&abcd=abc"); - - ensure_equals(LLURI::buildHTTP("host", "").asString(), - "http://host"); - ensure_equals(LLURI::buildHTTP("host", "/").asString(), - "http://host/"); - ensure_equals(LLURI::buildHTTP("host", "//").asString(), - "http://host/"); - ensure_equals(LLURI::buildHTTP("host", "dir name").asString(), - "http://host/dir%20name"); - ensure_equals(LLURI::buildHTTP("host", "dir name/").asString(), - "http://host/dir%20name/"); - ensure_equals(LLURI::buildHTTP("host", "/dir name").asString(), - "http://host/dir%20name"); - ensure_equals(LLURI::buildHTTP("host", "/dir name/").asString(), - "http://host/dir%20name/"); - ensure_equals(LLURI::buildHTTP("host", "dir name/subdir name").asString(), - "http://host/dir%20name/subdir%20name"); - ensure_equals(LLURI::buildHTTP("host", "dir name/subdir name/").asString(), - "http://host/dir%20name/subdir%20name/"); - ensure_equals(LLURI::buildHTTP("host", "/dir name/subdir name").asString(), - "http://host/dir%20name/subdir%20name"); - ensure_equals(LLURI::buildHTTP("host", "/dir name/subdir name/").asString(), - "http://host/dir%20name/subdir%20name/"); - ensure_equals(LLURI::buildHTTP("host", "//dir name//subdir name//").asString(), - "http://host/dir%20name/subdir%20name/"); - } - - template<> template<> - void URITestObject::test<9>() - { - set_test_name("test unescaped path components"); - LLSD path; - path.append("x@*//*$&^"); - path.append("123"); - checkParts(LLURI::buildHTTP("host", path), - "http", "//host/x@*//*$&^/123", "host", "/x@*//*$&^/123"); - } - - template<> template<> - void URITestObject::test<10>() - { - set_test_name("test unescaped query components"); - LLSD path; - path.append("x"); - path.append("123"); - LLSD query; - query["123"] = "?&*#//"; - query["**@&?//"] = "abc"; - checkParts(LLURI::buildHTTP("host", path, query), - "http", "//host/x/123?**@&?//=abc&123=?&*#//", - "host", "/x/123", "**@&?//=abc&123=?&*#//"); - } - - template<> template<> - void URITestObject::test<11>() - { - set_test_name("test unescaped host components"); - LLSD path; - path.append("x"); - path.append("123"); - LLSD query; - query["123"] = "12"; - query["abcd"] = "abc"; - checkParts(LLURI::buildHTTP("hi123*33--}{:portstuffs", path, query), - "http", "//hi123*33--}{:portstuffs/x/123?123=12&abcd=abc", - "hi123*33--}{:portstuffs", "/x/123", "123=12&abcd=abc"); - } - - template<> template<> - void URITestObject::test<12>() - { - set_test_name("test funky host_port values that are actually prefixes"); - - checkParts(LLURI::buildHTTP("http://example.com:8080", LLSD()), - "http", "//example.com:8080", - "example.com:8080", ""); - - checkParts(LLURI::buildHTTP("http://example.com:8080/", LLSD()), - "http", "//example.com:8080/", - "example.com:8080", "/"); - - checkParts(LLURI::buildHTTP("http://example.com:8080/a/b", LLSD()), - "http", "//example.com:8080/a/b", - "example.com:8080", "/a/b"); - } - - template<> template<> - void URITestObject::test<13>() - { - const std::string unreserved = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" - "0123456789" - "-._~"; - set_test_name("test escape"); - ensure_equals("escaping", LLURI::escape("abcdefg", "abcdef"), "abcdef%67"); - ensure_equals("escaping", LLURI::escape("|/&\\+-_!@", ""), "%7C%2F%26%5C%2B%2D%5F%21%40"); - ensure_equals("escaping as query variable", - LLURI::escape("http://10.0.1.4:12032/agent/god/agent-id/map/layer/?resume=http://station3.ll.com:12032/agent/203ad6df-b522-491d-ba48-4e24eb57aeff/send-postcard", unreserved + ":@!$'()*+,="), - "http:%2F%2F10.0.1.4:12032%2Fagent%2Fgod%2Fagent-id%2Fmap%2Flayer%2F%3Fresume=http:%2F%2Fstation3.ll.com:12032%2Fagent%2F203ad6df-b522-491d-ba48-4e24eb57aeff%2Fsend-postcard"); - // French cedilla (C with squiggle, like in the word Francais) is UTF-8 C3 A7 + struct URITestData { + void checkParts(const LLURI& u, + const char* expectedScheme, + const char* expectedOpaque, + const char* expectedAuthority, + const char* expectedPath, + const char* expectedQuery = "") + { + ensure_equals("scheme", u.scheme(), expectedScheme); + ensure_equals("opaque", u.opaque(), expectedOpaque); + ensure_equals("authority", u.authority(), expectedAuthority); + ensure_equals("path", u.path(), expectedPath); + ensure_equals("query", u.query(), expectedQuery); + } + + void escapeRoundTrip(const std::string& uri_raw_1) + { + std::string uri_esc_1(LLURI::escape(uri_raw_1)); + std::string uri_raw_2(LLURI::unescape(uri_esc_1)); + ensure_equals("escape/unescape raw", uri_raw_2, uri_raw_1); + std::string uri_esc_2(LLURI::escape(uri_raw_2)); + ensure_equals("escape/unescape escaped", uri_esc_2, uri_esc_1); + } + }; + + typedef test_group URITestGroup; + typedef URITestGroup::object URITestObject; + + URITestGroup uriTestGroup("LLURI"); + + template<> template<> + void URITestObject::test<1>() + { + LLURI u("http://abc.com/def/ghi?x=37&y=hello"); + + ensure_equals("scheme", u.scheme(), "http"); + ensure_equals("authority", u.authority(), "abc.com"); + ensure_equals("path", u.path(), "/def/ghi"); + ensure_equals("query", u.query(), "x=37&y=hello"); + + ensure_equals("host name", u.hostName(), "abc.com"); + ensure_equals("host port", u.hostPort(), 80); + + LLSD query = u.queryMap(); + ensure_equals("query x", query["x"].asInteger(), 37); + ensure_equals("query y", query["y"].asString(), "hello"); + + query = LLURI::queryMap("x=22.23&y=https://lindenlab.com/"); + ensure_equals("query x", query["x"].asReal(), 22.23); + ensure_equals("query y", query["y"].asURI().asString(), "https://lindenlab.com/"); + } + + template<> template<> + void URITestObject::test<2>() + { + set_test_name("empty string"); + checkParts(LLURI(""), "", "", "", ""); + } + + template<> template<> + void URITestObject::test<3>() + { + set_test_name("no scheme"); + checkParts(LLURI("foo"), "", "foo", "", ""); + checkParts(LLURI("foo%3A"), "", "foo:", "", ""); + } + + template<> template<> + void URITestObject::test<4>() + { + set_test_name("scheme w/o paths"); + checkParts(LLURI("mailto:zero@ll.com"), + "mailto", "zero@ll.com", "", ""); + checkParts(LLURI("silly://abc/def?foo"), + "silly", "//abc/def?foo", "", ""); + } + + template<> template<> + void URITestObject::test<5>() + { + set_test_name("authority section"); + checkParts(LLURI("http:///"), + "http", "///", "", "/"); + + checkParts(LLURI("http://abc"), + "http", "//abc", "abc", ""); + + checkParts(LLURI("http://a%2Fb/cd"), + "http", "//a/b/cd", "a/b", "/cd"); + + checkParts(LLURI("http://host?"), + "http", "//host?", "host", ""); + } + + template<> template<> + void URITestObject::test<6>() + { + set_test_name("path section"); + checkParts(LLURI("http://host/a/b/"), + "http", "//host/a/b/", "host", "/a/b/"); + + checkParts(LLURI("http://host/a%3Fb/"), + "http", "//host/a?b/", "host", "/a?b/"); + + checkParts(LLURI("http://host/a:b/"), + "http", "//host/a:b/", "host", "/a:b/"); + } + + template<> template<> + void URITestObject::test<7>() + { + set_test_name("query string"); + checkParts(LLURI("http://host/?"), + "http", "//host/?", "host", "/", ""); + + checkParts(LLURI("http://host/?x"), + "http", "//host/?x", "host", "/", "x"); + + checkParts(LLURI("http://host/??"), + "http", "//host/??", "host", "/", "?"); + + checkParts(LLURI("http://host/?%3F"), + "http", "//host/??", "host", "/", "?"); + } + + template<> template<> + void URITestObject::test<8>() + { + LLSD path; + path.append("x"); + path.append("123"); + checkParts(LLURI::buildHTTP("host", path), + "http", "//host/x/123", "host", "/x/123"); + + LLSD query; + query["123"] = "12"; + query["abcd"] = "abc"; + checkParts(LLURI::buildHTTP("host", path, query), + "http", "//host/x/123?123=12&abcd=abc", + "host", "/x/123", "123=12&abcd=abc"); + + ensure_equals(LLURI::buildHTTP("host", "").asString(), + "http://host"); + ensure_equals(LLURI::buildHTTP("host", "/").asString(), + "http://host/"); + ensure_equals(LLURI::buildHTTP("host", "//").asString(), + "http://host/"); + ensure_equals(LLURI::buildHTTP("host", "dir name").asString(), + "http://host/dir%20name"); + ensure_equals(LLURI::buildHTTP("host", "dir name/").asString(), + "http://host/dir%20name/"); + ensure_equals(LLURI::buildHTTP("host", "/dir name").asString(), + "http://host/dir%20name"); + ensure_equals(LLURI::buildHTTP("host", "/dir name/").asString(), + "http://host/dir%20name/"); + ensure_equals(LLURI::buildHTTP("host", "dir name/subdir name").asString(), + "http://host/dir%20name/subdir%20name"); + ensure_equals(LLURI::buildHTTP("host", "dir name/subdir name/").asString(), + "http://host/dir%20name/subdir%20name/"); + ensure_equals(LLURI::buildHTTP("host", "/dir name/subdir name").asString(), + "http://host/dir%20name/subdir%20name"); + ensure_equals(LLURI::buildHTTP("host", "/dir name/subdir name/").asString(), + "http://host/dir%20name/subdir%20name/"); + ensure_equals(LLURI::buildHTTP("host", "//dir name//subdir name//").asString(), + "http://host/dir%20name/subdir%20name/"); + } + + template<> template<> + void URITestObject::test<9>() + { + set_test_name("test unescaped path components"); + LLSD path; + path.append("x@*//*$&^"); + path.append("123"); + checkParts(LLURI::buildHTTP("host", path), + "http", "//host/x@*//*$&^/123", "host", "/x@*//*$&^/123"); + } + + template<> template<> + void URITestObject::test<10>() + { + set_test_name("test unescaped query components"); + LLSD path; + path.append("x"); + path.append("123"); + LLSD query; + query["123"] = "?&*#//"; + query["**@&?//"] = "abc"; + checkParts(LLURI::buildHTTP("host", path, query), + "http", "//host/x/123?**@&?//=abc&123=?&*#//", + "host", "/x/123", "**@&?//=abc&123=?&*#//"); + } + + template<> template<> + void URITestObject::test<11>() + { + set_test_name("test unescaped host components"); + LLSD path; + path.append("x"); + path.append("123"); + LLSD query; + query["123"] = "12"; + query["abcd"] = "abc"; + checkParts(LLURI::buildHTTP("hi123*33--}{:portstuffs", path, query), + "http", "//hi123*33--}{:portstuffs/x/123?123=12&abcd=abc", + "hi123*33--}{:portstuffs", "/x/123", "123=12&abcd=abc"); + } + + template<> template<> + void URITestObject::test<12>() + { + set_test_name("test funky host_port values that are actually prefixes"); + + checkParts(LLURI::buildHTTP("http://example.com:8080", LLSD()), + "http", "//example.com:8080", + "example.com:8080", ""); + + checkParts(LLURI::buildHTTP("http://example.com:8080/", LLSD()), + "http", "//example.com:8080/", + "example.com:8080", "/"); + + checkParts(LLURI::buildHTTP("http://example.com:8080/a/b", LLSD()), + "http", "//example.com:8080/a/b", + "example.com:8080", "/a/b"); + } + + template<> template<> + void URITestObject::test<13>() + { + const std::string unreserved = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + "0123456789" + "-._~"; + set_test_name("test escape"); + ensure_equals("escaping", LLURI::escape("abcdefg", "abcdef"), "abcdef%67"); + ensure_equals("escaping", LLURI::escape("|/&\\+-_!@", ""), "%7C%2F%26%5C%2B%2D%5F%21%40"); + ensure_equals("escaping as query variable", + LLURI::escape("http://10.0.1.4:12032/agent/god/agent-id/map/layer/?resume=http://station3.ll.com:12032/agent/203ad6df-b522-491d-ba48-4e24eb57aeff/send-postcard", unreserved + ":@!$'()*+,="), + "http:%2F%2F10.0.1.4:12032%2Fagent%2Fgod%2Fagent-id%2Fmap%2Flayer%2F%3Fresume=http:%2F%2Fstation3.ll.com:12032%2Fagent%2F203ad6df-b522-491d-ba48-4e24eb57aeff%2Fsend-postcard"); + // French cedilla (C with squiggle, like in the word Francais) is UTF-8 C3 A7 #if LL_WINDOWS #pragma warning(disable: 4309) #endif - std::string cedilla; - cedilla.push_back( (char)0xC3 ); - cedilla.push_back( (char)0xA7 ); - ensure_equals("escape UTF8", LLURI::escape( cedilla, unreserved), "%C3%A7"); - } - - - template<> template<> - void URITestObject::test<14>() - { - set_test_name("make sure escape and unescape of empty strings return empty strings."); - std::string uri_esc(LLURI::escape("")); - ensure("escape string empty", uri_esc.empty()); - std::string uri_raw(LLURI::unescape("")); - ensure("unescape string empty", uri_raw.empty()); - } - - template<> template<> - void URITestObject::test<15>() - { - set_test_name("do some round-trip tests"); - escapeRoundTrip("http://secondlife.com"); - escapeRoundTrip("http://secondlife.com/url with spaces"); - escapeRoundTrip("http://bad[domain]name.com/"); - escapeRoundTrip("ftp://bill.gates@ms/micro$oft.com/c:\\autoexec.bat"); - escapeRoundTrip(""); - } - - template<> template<> - void URITestObject::test<16>() - { - set_test_name("Test the default escaping"); - // yes -- this mangles the url. This is expected behavior - std::string simple("http://secondlife.com"); - ensure_equals( - "simple http", - LLURI::escape(simple), - "http%3A%2F%2Fsecondlife.com"); - ensure_equals( - "needs escape", - LLURI::escape("http://get.secondlife.com/windows viewer"), - "http%3A%2F%2Fget.secondlife.com%2Fwindows%20viewer"); - } - - template<> template<> - void URITestObject::test<17>() - { - set_test_name("do some round-trip tests with very long strings."); - escapeRoundTrip("Welcome to Second Life.We hope you'll have a richly rewarding experience, filled with creativity, self expression and fun.The goals of the Community Standards are simple: treat each other with respect and without harassment, adhere to local standards as indicated by simulator ratings, and refrain from any hate activity which slurs a real-world individual or real-world community. Behavioral Guidelines - The Big Six"); - escapeRoundTrip( - "'asset_data':b(12100){'task_id':ucc706f2d-0b68-68f8-11a4-f1043ff35ca0}\n{\n\tname\tObject|\n\tpermissions 0\n\t{\n\t\tbase_mask\t7fffffff\n\t\towner_mask\t7fffffff\n\t\tgroup_mask\t00000000\n\t\teveryone_mask\t00000000\n\t\tnext_owner_mask\t7fffffff\n\t\tcreator_id\t13fd9595-a47b-4d64-a5fb-6da645f038e0\n\t\towner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tlast_owner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tgroup_id\t00000000-0000-0000-0000-000000000000\n\t}\n\tlocal_id\t217444921\n\ttotal_crc\t323\n\ttype\t2\n\ttask_valid\t2\n\ttravel_access\t13\n\tdisplayopts\t2\n\tdisplaytype\tv\n\tpos\t-0.368634403\t0.00781063363\t-0.569040775\n\toldpos\t150.117996\t25.8658009\t8.19664001\n\trotation\t-0.06293071806430816650390625\t-0.6995697021484375\t-0.7002241611480712890625\t0.1277817934751510620117188\n\tchildpos\t-0.00499999989\t-0.0359999985\t0.307999998\n\tchildrot\t-0.515492737293243408203125\t-0.46601200103759765625\t0.529055416584014892578125\t0.4870323240756988525390625\n\tscale" - "\t0.074629\t0.289956\t0.01\n\tsit_offset\t0\t0\t0\n\tcamera_eye_offset\t0\t0\t0\n\tcamera_at_offset\t0\t0\t0\n\tsit_quat\t0\t0\t0\t1\n\tsit_hint\t0\n\tstate\t160\n\tmaterial\t3\n\tsoundid\t00000000-0000-0000-0000-000000000000\n\tsoundgain\t0\n\tsoundradius\t0\n\tsoundflags\t0\n\ttextcolor\t0 0 0 1\n\tselected\t0\n\tselector\t00000000-0000-0000-0000-000000000000\n\tusephysics\t0\n\trotate_x\t1\n\trotate_y\t1\n\trotate_z\t1\n\tphantom\t0\n\tremote_script_access_pin\t0\n\tvolume_detect\t0\n\tblock_grabs\t0\n\tdie_at_edge\t0\n\treturn_at_edge\t0\n\ttemporary\t0\n\tsandbox\t0\n\tsandboxhome\t0\t0\t0\n\tshape 0\n\t{\n\t\tpath 0\n\t\t{\n\t\t\tcurve\t16\n\t\t\tbegin\t0\n\t\t\tend\t1\n\t\t\tscale_x\t1\n\t\t\tscale_y\t1\n\t\t\tshear_x\t0\n\t\t\tshear_y\t0\n\t\t\ttwist\t0\n\t\t\ttwist_begin\t0\n\t\t\tradius_offset\t0\n\t\t\ttaper_x\t0\n\t\t\ttaper_y\t0\n\t\t\trevolutions\t1\n\t\t\tskew\t0\n\t\t}\n\t\tprofile 0\n\t\t{\n\t\t\tcurve\t1\n\t\t\tbegin\t0\n\t\t\tend\t1\n\t\t\thollow\t0\n\t\t}\n\t}\n\tf" - "aces\t6\n\t{\n\t\timageid\tddde1ffc-678b-3cda-1748-513086bdf01b\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204" - "\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tddde1ffc-678b-3cda-1748-513086bdf01b\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t-1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\tps_next_crc\t1\n\tgpw_bias\t1\n\tip\t0\n\tcomplete\tTRUE\n\tdelay\t50000\n\tnextstart\t0\n\tbirthtime\t1061088050622956\n\treztime\t1094866329019785\n\tparceltime\t1133568981980596\n\ttax_rate\t1.00084\n\tscratchpad\t0\n\t{\n\t\n\t}\n\tsale_info\t0\n\t{\n\t\tsale_type\tnot\n\t\tsale_price\t10\n\t}\n\tcorrect_family_id\t00000000-0000-0000-0000-000000000000\n\thas_rezzed\t0\n\tpre_link_base_mask\t7fffffff\n\tlinked \tchild\n\tdefault_pay_price\t-2\t1\t5\t10\t20\n}\n{'task_id':u61fa7364-e151-0597-774c-523312dae31b}\n{\n\tname\tObject|\n\tpermissions 0\n\t{\n\t\tbase_mask\t7fffff" - "ff\n\t\towner_mask\t7fffffff\n\t\tgroup_mask\t00000000\n\t\teveryone_mask\t00000000\n\t\tnext_owner_mask\t7fffffff\n\t\tcreator_id\t13fd9595-a47b-4d64-a5fb-6da645f038e0\n\t\towner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tlast_owner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tgroup_id\t00000000-0000-0000-0000-000000000000\n\t}\n\tlocal_id\t217444922\n\ttotal_crc\t324\n\ttype\t2\n\ttask_valid\t2\n\ttravel_access\t13\n\tdisplayopts\t2\n\tdisplaytype\tv\n\tpos\t-0.367110789\t0.00780026987\t-0.566269755\n\toldpos\t150.115005\t25.8479004\t8.18669987\n\trotation\t0.47332942485809326171875\t-0.380102097988128662109375\t-0.5734078884124755859375\t0.550168216228485107421875\n\tchildpos\t-0.00499999989\t-0.0370000005\t0.305000007\n\tchildrot\t-0.736649334430694580078125\t-0.03042060509324073791503906\t-0.02784589119255542755126953\t0.67501628398895263671875\n\tscale\t0.074629\t0.289956\t0.01\n\tsit_offset\t0\t0\t0\n\tcamera_eye_offset\t0\t0\t0\n\tcamera_at_offset\t0\t0\t0\n\tsit_quat\t0\t" - "0\t0\t1\n\tsit_hint\t0\n\tstate\t160\n\tmaterial\t3\n\tsoundid\t00000000-0000-0000-0000-000000000000\n\tsoundgain\t0\n\tsoundradius\t0\n\tsoundflags\t0\n\ttextcolor\t0 0 0 1\n\tselected\t0\n\tselector\t00000000-0000-0000-0000-000000000000\n\tusephysics\t0\n\trotate_x\t1\n\trotate_y\t1\n\trotate_z\t1\n\tphantom\t0\n\tremote_script_access_pin\t0\n\tvolume_detect\t0\n\tblock_grabs\t0\n\tdie_at_edge\t0\n\treturn_at_edge\t0\n\ttemporary\t0\n\tsandbox\t0\n\tsandboxhome\t0\t0\t0\n\tshape 0\n\t{\n\t\tpath 0\n\t\t{\n\t\t\tcurve\t16\n\t\t\tbegin\t0\n\t\t\tend\t1\n\t\t\tscale_x\t1\n\t\t\tscale_y\t1\n\t\t\tshear_x\t0\n\t\t\tshear_y\t0\n\t\t\ttwist\t0\n\t\t\ttwist_begin\t0\n\t\t\tradius_offset\t0\n\t\t\ttaper_x\t0\n\t\t\ttaper_y\t0\n\t\t\trevolutions\t1\n\t\t\tskew\t0\n\t\t}\n\t\tprofile 0\n\t\t{\n\t\t\tcurve\t1\n\t\t\tbegin\t0\n\t\t\tend\t1\n\t\t\thollow\t0\n\t\t}\n\t}\n\tfaces\t6\n\t{\n\t\timageid\tddde1ffc-678b-3cda-1748-513086bdf01b\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t" - "\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t" - "\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tddde1ffc-678b-3cda-1748-513086bdf01b\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t-1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\tps_next_crc\t1\n\tgpw_bias\t1\n\tip\t0\n\tcomplete\tTRUE\n\tdelay\t50000\n\tnextstart\t0\n\tbirthtime\t1061087839248891\n\treztime\t1094866329020800\n\tparceltime\t1133568981981983\n\ttax_rate\t1.00084\n\tscratchpad\t0\n\t{\n\t\n\t}\n\tsale_info\t0\n\t{\n\t\tsale_type\tnot\n\t\tsale_price\t10\n\t}\n\tcorrect_family_id\t00000000-0000-0000-0000-000000000000\n\thas_rezzed\t0\n\tpre_link_base_mask\t7fffffff\n\tlinked \tchild\n\tdefault_pay_price\t-2\t1\t5\t10\t20\n}\n{'task_id':ub8d68643-7dd8-57af-0d24-8790032aed0c}\n{\n\tname\tObject|\n\tpermissions 0\n\t{\n\t\tbase_mask\t7fffffff\n\t\towner_mask\t7fffffff\n\t\tgroup_mask\t00000000\n\t\teveryone_mask\t00000000\n\t\tnext_owner_mask\t7fffffff\n\t\tcreat" - "or_id\t13fd9595-a47b-4d64-a5fb-6da645f038e0\n\t\towner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tlast_owner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tgroup_id\t00000000-0000-0000-0000-000000000000\n\t}\n\tlocal_id\t217444923\n\ttotal_crc\t235\n\ttype\t2\n\ttask_valid\t2\n\ttravel_access\t13\n\tdisplayopts\t2\n\tdisplaytype\tv\n\tpos\t-0.120029509\t-0.00284469454\t-0.0302077383\n\toldpos\t150.710999\t25.8584995\t8.19172001\n\trotation\t0.145459949970245361328125\t-0.1646589934825897216796875\t0.659558117389678955078125\t-0.718826770782470703125\n\tchildpos\t0\t-0.182999998\t-0.26699999\n\tchildrot\t0.991444766521453857421875\t3.271923924330621957778931e-05\t-0.0002416197530692443251609802\t0.1305266767740249633789062\n\tscale\t0.0382982\t0.205957\t0.368276\n\tsit_offset\t0\t0\t0\n\tcamera_eye_offset\t0\t0\t0\n\tcamera_at_offset\t0\t0\t0\n\tsit_quat\t0\t0\t0\t1\n\tsit_hint\t0\n\tstate\t160\n\tmaterial\t3\n\tsoundid\t00000000-0000-0000-0000-000000000000\n\tsoundgain\t0\n\tsoundra" - "dius\t0\n\tsoundflags\t0\n\ttextcolor\t0 0 0 1\n\tselected\t0\n\tselector\t00000000-0000-0000-0000-000000000000\n\tusephysics\t0\n\trotate_x\t1\n\trotate_y\t1\n\trotate_z\t1\n\tphantom\t0\n\tremote_script_access_pin\t0\n\tvolume_detect\t0\n\tblock_grabs\t0\n\tdie_at_edge\t0\n\treturn_at_edge\t0\n\ttemporary\t0\n\tsandbox\t0\n\tsandboxhome\t0\t0\t0\n\tshape 0\n\t{\n\t\tpath 0\n\t\t{\n\t\t\tcurve\t32\n\t\t\tbegin\t0.3\n\t\t\tend\t0.65\n\t\t\tscale_x\t1\n\t\t\tscale_y\t0.05\n\t\t\tshear_x\t0\n\t\t\tshear_y\t0\n\t\t\ttwist\t0\n\t\t\ttwist_begin\t0\n\t\t\tradius_offset\t0\n\t\t\ttaper_x\t0\n\t\t\ttaper_y\t0\n\t\t\trevolutions\t1\n\t\t\tskew\t0\n\t\t}\n\t\tprofile 0\n\t\t{\n\t\t\tcurve\t0\n\t\t\tbegin\t0\n\t\t\tend\t1\n\t\t\thollow\t0\n\t\t}\n\t}\n\tfaces\t3\n\t{\n\t\timageid\te7150bed-3e3e-c698-eb15-d17b178148af\n\t\tcolors\t0.843137 0.156863 0.156863 1\n\t\tscales\t15\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t-1.57084\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0" - "\n\t}\n\t{\n\t\timageid\te7150bed-3e3e-c698-eb15-d17b178148af\n\t\tcolors\t0.843137 0.156863 0.156863 1\n\t\tscales\t15\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t-1.57084\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\te7150bed-3e3e-c698-eb15-d17b178148af\n\t\tcolors\t0.843137 0.156863 0.156863 1\n\t\tscales\t15\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t-1.57084\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\tps_next_crc\t1\n\tgpw_bias\t1\n\tip\t0\n\tcomplete\tTRUE\n\tdelay\t50000\n\tnextstart\t0\n\tbirthtime\t1061087534454174\n\treztime\t1094866329021741\n\tparceltime\t1133568981982889\n\ttax_rate\t1.00326\n\tscratchpad\t0\n\t{\n\t\n\t}\n\tsale_info\t0\n\t{\n\t\tsale_type\tnot\n\t\tsale_price\t10\n\t}\n\tcorrect_family_id\t00000000-0000-0000-0000-000000000000\n\thas_rezzed\t0\n\tpre_link_base_mask\t7fffffff\n\tlinked \tchild\n\tdefault_pay_price\t-2\t1\t5\t10\t20\n}\n{'task_id':ue4b19200-9d33-962f-c8c5-6f" - "25be3a3fd0}\n{\n\tname\tApotheosis_Immolaine_tail|\n\tpermissions 0\n\t{\n\t\tbase_mask\t7fffffff\n\t\towner_mask\t7fffffff\n\t\tgroup_mask\t00000000\n\t\teveryone_mask\t00000000\n\t\tnext_owner_mask\t7fffffff\n\t\tcreator_id\t13fd9595-a47b-4d64-a5fb-6da645f038e0\n\t\towner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tlast_owner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tgroup_id\t00000000-0000-0000-0000-000000000000\n\t}\n\tlocal_id\t217444924\n\ttotal_crc\t675\n\ttype\t1\n\ttask_valid\t2\n\ttravel_access\t13\n\tdisplayopts\t2\n\tdisplaytype\tv\n\tpos\t-0.34780401\t-0.00968400016\t-0.260098994\n\toldpos\t0\t0\t0\n\trotation\t0.73164522647857666015625\t-0.67541944980621337890625\t-0.07733880728483200073242188\t0.05022468417882919311523438\n\tvelocity\t0\t0\t0\n\tangvel\t0\t0\t0\n\tscale\t0.0382982\t0.32228\t0.383834\n\tsit_offset\t0\t0\t0\n\tcamera_eye_offset\t0\t0\t0\n\tcamera_at_offset\t0\t0\t0\n\tsit_quat\t0\t0\t0\t1\n\tsit_hint\t0\n\tstate\t160\n\tmaterial\t3\n\tsoundid\t00000" - "000-0000-0000-0000-000000000000\n\tsoundgain\t0\n\tsoundradius\t0\n\tsoundflags\t0\n\ttextcolor\t0 0 0 1\n\tselected\t0\n\tselector\t00000000-0000-0000-0000-000000000000\n\tusephysics\t0\n\trotate_x\t1\n\trotate_y\t1\n\trotate_z\t1\n\tphantom\t0\n\tremote_script_access_pin\t0\n\tvolume_detect\t0\n\tblock_grabs\t0\n\tdie_at_edge\t0\n\treturn_at_edge\t0\n\ttemporary\t0\n\tsandbox\t0\n\tsandboxhome\t0\t0\t0\n\tshape 0\n\t{\n\t\tpath 0\n\t\t{\n\t\t\tcurve\t32\n\t\t\tbegin\t0.3\n\t\t\tend\t0.65\n\t\t\tscale_x\t1\n\t\t\tscale_y\t0.05\n\t\t\tshear_x\t0\n\t\t\tshear_y\t0\n\t\t\ttwist\t0\n\t\t\ttwist_begin\t0\n\t\t\tradius_offset\t0\n\t\t\ttaper_x\t0\n\t\t\ttaper_y\t0\n\t\t\trevolutions\t1\n\t\t\tskew\t0\n\t\t}\n\t\tprofile 0\n\t\t{\n\t\t\tcurve\t0\n\t\t\tbegin\t0\n\t\t\tend\t1\n\t\t\thollow\t0\n\t\t}\n\t}\n\tfaces\t3\n\t{\n\t\timageid\te7150bed-3e3e-c698-eb15-d17b178148af\n\t\tcolors\t0.843137 0.156863 0.156863 1\n\t\tscales\t15\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t-1" - ".57084\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\te7150bed-3e3e-c698-eb15-d17b178148af\n\t\tcolors\t0.843137 0.156863 0.156863 1\n\t\tscales\t15\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t-1.57084\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\te7150bed-3e3e-c698-eb15-d17b178148af\n\t\tcolors\t0.843137 0.156863 0.156863 1\n\t\tscales\t15\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t-1.57084\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\tps_next_crc\t1\n\tgpw_bias\t1\n\tip\t0\n\tcomplete\tTRUE\n\tdelay\t50000\n\tnextstart\t0\n\tbirthtime\t1061087463950186\n\treztime\t1094866329022555\n\tparceltime\t1133568981984359\n\tdescription\t(No Description)|\n\ttax_rate\t1.01736\n\tnamevalue\tAttachPt U32 RW S 10\n\tnamevalue\tAttachmentOrientation VEC3 RW DS -3.110088, -0.182018, 1.493795\n\tnamevalue\tAttachmentOffset VEC3 RW DS -0.347804, -0.009684, -0.260099\n\tnamevalue\tAttachItemI" - "D STRING RW SV 20f36c3a-b44b-9bc7-87f3-018bfdfc8cda\n\tscratchpad\t0\n\t{\n\t\n\t}\n\tsale_info\t0\n\t{\n\t\tsale_type\tnot\n\t\tsale_price\t10\n\t}\n\torig_asset_id\t8747acbc-d391-1e59-69f1-41d06830e6c0\n\torig_item_id\t20f36c3a-b44b-9bc7-87f3-018bfdfc8cda\n\tfrom_task_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\tcorrect_family_id\t00000000-0000-0000-0000-000000000000\n\thas_rezzed\t0\n\tpre_link_base_mask\t7fffffff\n\tlinked \tlinked\n\tdefault_pay_price\t-2\t1\t5\t10\t20\n}\n"); - } - - - template<> template<> - void URITestObject::test<18>() - { - LLURI u("secondlife:///app/login?first_name=Testert4&last_name=Tester&web_login_key=test"); - // if secondlife is the scheme, LLURI should parse /app/login as path, with no authority - ensure_equals("scheme", u.scheme(), "secondlife"); - ensure_equals("authority", u.authority(), ""); - ensure_equals("path", u.path(), "/app/login"); - ensure_equals("pathmap", u.pathArray()[0].asString(), "app"); - ensure_equals("pathmap", u.pathArray()[1].asString(), "login"); - ensure_equals("query", u.query(), "first_name=Testert4&last_name=Tester&web_login_key=test"); - ensure_equals("query map element", u.queryMap()["last_name"].asString(), "Tester"); - - u = LLURI("secondlife://Da Boom/128/128/128"); - // if secondlife is the scheme, LLURI should parse /128/128/128 as path, with Da Boom as authority - ensure_equals("scheme", u.scheme(), "secondlife"); - ensure_equals("authority", u.authority(), "Da Boom"); - ensure_equals("path", u.path(), "/128/128/128"); - ensure_equals("pathmap", u.pathArray()[0].asString(), "128"); - ensure_equals("pathmap", u.pathArray()[1].asString(), "128"); - ensure_equals("pathmap", u.pathArray()[2].asString(), "128"); - ensure_equals("query", u.query(), ""); - } - - template<> template<> - void URITestObject::test<19>() - { - set_test_name("Parse about: schemes"); - LLURI u("about:blank?redirect-http-hack=secondlife%3A%2F%2F%2Fapp%2Flogin%3Ffirst_name%3DCallum%26last_name%3DLinden%26location%3Dspecify%26grid%3Dvaak%26region%3D%2FMorris%2F128%2F128%26web_login_key%3Defaa4795-c2aa-4c58-8966-763c27931e78"); - ensure_equals("scheme", u.scheme(), "about"); - ensure_equals("authority", u.authority(), ""); - ensure_equals("path", u.path(), "blank"); - ensure_equals("pathmap", u.pathArray()[0].asString(), "blank"); - ensure_equals("query", u.query(), "redirect-http-hack=secondlife:///app/login?first_name=Callum&last_name=Linden&location=specify&grid=vaak®ion=/Morris/128/128&web_login_key=efaa4795-c2aa-4c58-8966-763c27931e78"); - ensure_equals("query map element", u.queryMap()["redirect-http-hack"].asString(), "secondlife:///app/login?first_name=Callum&last_name=Linden&location=specify&grid=vaak®ion=/Morris/128/128&web_login_key=efaa4795-c2aa-4c58-8966-763c27931e78"); - } - - template<> template<> - void URITestObject::test<20>() - { + std::string cedilla; + cedilla.push_back( (char)0xC3 ); + cedilla.push_back( (char)0xA7 ); + ensure_equals("escape UTF8", LLURI::escape( cedilla, unreserved), "%C3%A7"); + } + + + template<> template<> + void URITestObject::test<14>() + { + set_test_name("make sure escape and unescape of empty strings return empty strings."); + std::string uri_esc(LLURI::escape("")); + ensure("escape string empty", uri_esc.empty()); + std::string uri_raw(LLURI::unescape("")); + ensure("unescape string empty", uri_raw.empty()); + } + + template<> template<> + void URITestObject::test<15>() + { + set_test_name("do some round-trip tests"); + escapeRoundTrip("http://secondlife.com"); + escapeRoundTrip("http://secondlife.com/url with spaces"); + escapeRoundTrip("http://bad[domain]name.com/"); + escapeRoundTrip("ftp://bill.gates@ms/micro$oft.com/c:\\autoexec.bat"); + escapeRoundTrip(""); + } + + template<> template<> + void URITestObject::test<16>() + { + set_test_name("Test the default escaping"); + // yes -- this mangles the url. This is expected behavior + std::string simple("http://secondlife.com"); + ensure_equals( + "simple http", + LLURI::escape(simple), + "http%3A%2F%2Fsecondlife.com"); + ensure_equals( + "needs escape", + LLURI::escape("http://get.secondlife.com/windows viewer"), + "http%3A%2F%2Fget.secondlife.com%2Fwindows%20viewer"); + } + + template<> template<> + void URITestObject::test<17>() + { + set_test_name("do some round-trip tests with very long strings."); + escapeRoundTrip("Welcome to Second Life.We hope you'll have a richly rewarding experience, filled with creativity, self expression and fun.The goals of the Community Standards are simple: treat each other with respect and without harassment, adhere to local standards as indicated by simulator ratings, and refrain from any hate activity which slurs a real-world individual or real-world community. Behavioral Guidelines - The Big Six"); + escapeRoundTrip( + "'asset_data':b(12100){'task_id':ucc706f2d-0b68-68f8-11a4-f1043ff35ca0}\n{\n\tname\tObject|\n\tpermissions 0\n\t{\n\t\tbase_mask\t7fffffff\n\t\towner_mask\t7fffffff\n\t\tgroup_mask\t00000000\n\t\teveryone_mask\t00000000\n\t\tnext_owner_mask\t7fffffff\n\t\tcreator_id\t13fd9595-a47b-4d64-a5fb-6da645f038e0\n\t\towner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tlast_owner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tgroup_id\t00000000-0000-0000-0000-000000000000\n\t}\n\tlocal_id\t217444921\n\ttotal_crc\t323\n\ttype\t2\n\ttask_valid\t2\n\ttravel_access\t13\n\tdisplayopts\t2\n\tdisplaytype\tv\n\tpos\t-0.368634403\t0.00781063363\t-0.569040775\n\toldpos\t150.117996\t25.8658009\t8.19664001\n\trotation\t-0.06293071806430816650390625\t-0.6995697021484375\t-0.7002241611480712890625\t0.1277817934751510620117188\n\tchildpos\t-0.00499999989\t-0.0359999985\t0.307999998\n\tchildrot\t-0.515492737293243408203125\t-0.46601200103759765625\t0.529055416584014892578125\t0.4870323240756988525390625\n\tscale" + "\t0.074629\t0.289956\t0.01\n\tsit_offset\t0\t0\t0\n\tcamera_eye_offset\t0\t0\t0\n\tcamera_at_offset\t0\t0\t0\n\tsit_quat\t0\t0\t0\t1\n\tsit_hint\t0\n\tstate\t160\n\tmaterial\t3\n\tsoundid\t00000000-0000-0000-0000-000000000000\n\tsoundgain\t0\n\tsoundradius\t0\n\tsoundflags\t0\n\ttextcolor\t0 0 0 1\n\tselected\t0\n\tselector\t00000000-0000-0000-0000-000000000000\n\tusephysics\t0\n\trotate_x\t1\n\trotate_y\t1\n\trotate_z\t1\n\tphantom\t0\n\tremote_script_access_pin\t0\n\tvolume_detect\t0\n\tblock_grabs\t0\n\tdie_at_edge\t0\n\treturn_at_edge\t0\n\ttemporary\t0\n\tsandbox\t0\n\tsandboxhome\t0\t0\t0\n\tshape 0\n\t{\n\t\tpath 0\n\t\t{\n\t\t\tcurve\t16\n\t\t\tbegin\t0\n\t\t\tend\t1\n\t\t\tscale_x\t1\n\t\t\tscale_y\t1\n\t\t\tshear_x\t0\n\t\t\tshear_y\t0\n\t\t\ttwist\t0\n\t\t\ttwist_begin\t0\n\t\t\tradius_offset\t0\n\t\t\ttaper_x\t0\n\t\t\ttaper_y\t0\n\t\t\trevolutions\t1\n\t\t\tskew\t0\n\t\t}\n\t\tprofile 0\n\t\t{\n\t\t\tcurve\t1\n\t\t\tbegin\t0\n\t\t\tend\t1\n\t\t\thollow\t0\n\t\t}\n\t}\n\tf" + "aces\t6\n\t{\n\t\timageid\tddde1ffc-678b-3cda-1748-513086bdf01b\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204" + "\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tddde1ffc-678b-3cda-1748-513086bdf01b\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t-1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\tps_next_crc\t1\n\tgpw_bias\t1\n\tip\t0\n\tcomplete\tTRUE\n\tdelay\t50000\n\tnextstart\t0\n\tbirthtime\t1061088050622956\n\treztime\t1094866329019785\n\tparceltime\t1133568981980596\n\ttax_rate\t1.00084\n\tscratchpad\t0\n\t{\n\t\n\t}\n\tsale_info\t0\n\t{\n\t\tsale_type\tnot\n\t\tsale_price\t10\n\t}\n\tcorrect_family_id\t00000000-0000-0000-0000-000000000000\n\thas_rezzed\t0\n\tpre_link_base_mask\t7fffffff\n\tlinked \tchild\n\tdefault_pay_price\t-2\t1\t5\t10\t20\n}\n{'task_id':u61fa7364-e151-0597-774c-523312dae31b}\n{\n\tname\tObject|\n\tpermissions 0\n\t{\n\t\tbase_mask\t7fffff" + "ff\n\t\towner_mask\t7fffffff\n\t\tgroup_mask\t00000000\n\t\teveryone_mask\t00000000\n\t\tnext_owner_mask\t7fffffff\n\t\tcreator_id\t13fd9595-a47b-4d64-a5fb-6da645f038e0\n\t\towner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tlast_owner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tgroup_id\t00000000-0000-0000-0000-000000000000\n\t}\n\tlocal_id\t217444922\n\ttotal_crc\t324\n\ttype\t2\n\ttask_valid\t2\n\ttravel_access\t13\n\tdisplayopts\t2\n\tdisplaytype\tv\n\tpos\t-0.367110789\t0.00780026987\t-0.566269755\n\toldpos\t150.115005\t25.8479004\t8.18669987\n\trotation\t0.47332942485809326171875\t-0.380102097988128662109375\t-0.5734078884124755859375\t0.550168216228485107421875\n\tchildpos\t-0.00499999989\t-0.0370000005\t0.305000007\n\tchildrot\t-0.736649334430694580078125\t-0.03042060509324073791503906\t-0.02784589119255542755126953\t0.67501628398895263671875\n\tscale\t0.074629\t0.289956\t0.01\n\tsit_offset\t0\t0\t0\n\tcamera_eye_offset\t0\t0\t0\n\tcamera_at_offset\t0\t0\t0\n\tsit_quat\t0\t" + "0\t0\t1\n\tsit_hint\t0\n\tstate\t160\n\tmaterial\t3\n\tsoundid\t00000000-0000-0000-0000-000000000000\n\tsoundgain\t0\n\tsoundradius\t0\n\tsoundflags\t0\n\ttextcolor\t0 0 0 1\n\tselected\t0\n\tselector\t00000000-0000-0000-0000-000000000000\n\tusephysics\t0\n\trotate_x\t1\n\trotate_y\t1\n\trotate_z\t1\n\tphantom\t0\n\tremote_script_access_pin\t0\n\tvolume_detect\t0\n\tblock_grabs\t0\n\tdie_at_edge\t0\n\treturn_at_edge\t0\n\ttemporary\t0\n\tsandbox\t0\n\tsandboxhome\t0\t0\t0\n\tshape 0\n\t{\n\t\tpath 0\n\t\t{\n\t\t\tcurve\t16\n\t\t\tbegin\t0\n\t\t\tend\t1\n\t\t\tscale_x\t1\n\t\t\tscale_y\t1\n\t\t\tshear_x\t0\n\t\t\tshear_y\t0\n\t\t\ttwist\t0\n\t\t\ttwist_begin\t0\n\t\t\tradius_offset\t0\n\t\t\ttaper_x\t0\n\t\t\ttaper_y\t0\n\t\t\trevolutions\t1\n\t\t\tskew\t0\n\t\t}\n\t\tprofile 0\n\t\t{\n\t\t\tcurve\t1\n\t\t\tbegin\t0\n\t\t\tend\t1\n\t\t\thollow\t0\n\t\t}\n\t}\n\tfaces\t6\n\t{\n\t\timageid\tddde1ffc-678b-3cda-1748-513086bdf01b\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t" + "\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tf54a0c32-3cd1-d49a-5b4f-7b792bebc204\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t" + "\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\tddde1ffc-678b-3cda-1748-513086bdf01b\n\t\tcolors\t0.937255 0.796078 0.494118 1\n\t\tscales\t1\n\t\tscalet\t-1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t0\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\tps_next_crc\t1\n\tgpw_bias\t1\n\tip\t0\n\tcomplete\tTRUE\n\tdelay\t50000\n\tnextstart\t0\n\tbirthtime\t1061087839248891\n\treztime\t1094866329020800\n\tparceltime\t1133568981981983\n\ttax_rate\t1.00084\n\tscratchpad\t0\n\t{\n\t\n\t}\n\tsale_info\t0\n\t{\n\t\tsale_type\tnot\n\t\tsale_price\t10\n\t}\n\tcorrect_family_id\t00000000-0000-0000-0000-000000000000\n\thas_rezzed\t0\n\tpre_link_base_mask\t7fffffff\n\tlinked \tchild\n\tdefault_pay_price\t-2\t1\t5\t10\t20\n}\n{'task_id':ub8d68643-7dd8-57af-0d24-8790032aed0c}\n{\n\tname\tObject|\n\tpermissions 0\n\t{\n\t\tbase_mask\t7fffffff\n\t\towner_mask\t7fffffff\n\t\tgroup_mask\t00000000\n\t\teveryone_mask\t00000000\n\t\tnext_owner_mask\t7fffffff\n\t\tcreat" + "or_id\t13fd9595-a47b-4d64-a5fb-6da645f038e0\n\t\towner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tlast_owner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tgroup_id\t00000000-0000-0000-0000-000000000000\n\t}\n\tlocal_id\t217444923\n\ttotal_crc\t235\n\ttype\t2\n\ttask_valid\t2\n\ttravel_access\t13\n\tdisplayopts\t2\n\tdisplaytype\tv\n\tpos\t-0.120029509\t-0.00284469454\t-0.0302077383\n\toldpos\t150.710999\t25.8584995\t8.19172001\n\trotation\t0.145459949970245361328125\t-0.1646589934825897216796875\t0.659558117389678955078125\t-0.718826770782470703125\n\tchildpos\t0\t-0.182999998\t-0.26699999\n\tchildrot\t0.991444766521453857421875\t3.271923924330621957778931e-05\t-0.0002416197530692443251609802\t0.1305266767740249633789062\n\tscale\t0.0382982\t0.205957\t0.368276\n\tsit_offset\t0\t0\t0\n\tcamera_eye_offset\t0\t0\t0\n\tcamera_at_offset\t0\t0\t0\n\tsit_quat\t0\t0\t0\t1\n\tsit_hint\t0\n\tstate\t160\n\tmaterial\t3\n\tsoundid\t00000000-0000-0000-0000-000000000000\n\tsoundgain\t0\n\tsoundra" + "dius\t0\n\tsoundflags\t0\n\ttextcolor\t0 0 0 1\n\tselected\t0\n\tselector\t00000000-0000-0000-0000-000000000000\n\tusephysics\t0\n\trotate_x\t1\n\trotate_y\t1\n\trotate_z\t1\n\tphantom\t0\n\tremote_script_access_pin\t0\n\tvolume_detect\t0\n\tblock_grabs\t0\n\tdie_at_edge\t0\n\treturn_at_edge\t0\n\ttemporary\t0\n\tsandbox\t0\n\tsandboxhome\t0\t0\t0\n\tshape 0\n\t{\n\t\tpath 0\n\t\t{\n\t\t\tcurve\t32\n\t\t\tbegin\t0.3\n\t\t\tend\t0.65\n\t\t\tscale_x\t1\n\t\t\tscale_y\t0.05\n\t\t\tshear_x\t0\n\t\t\tshear_y\t0\n\t\t\ttwist\t0\n\t\t\ttwist_begin\t0\n\t\t\tradius_offset\t0\n\t\t\ttaper_x\t0\n\t\t\ttaper_y\t0\n\t\t\trevolutions\t1\n\t\t\tskew\t0\n\t\t}\n\t\tprofile 0\n\t\t{\n\t\t\tcurve\t0\n\t\t\tbegin\t0\n\t\t\tend\t1\n\t\t\thollow\t0\n\t\t}\n\t}\n\tfaces\t3\n\t{\n\t\timageid\te7150bed-3e3e-c698-eb15-d17b178148af\n\t\tcolors\t0.843137 0.156863 0.156863 1\n\t\tscales\t15\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t-1.57084\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0" + "\n\t}\n\t{\n\t\timageid\te7150bed-3e3e-c698-eb15-d17b178148af\n\t\tcolors\t0.843137 0.156863 0.156863 1\n\t\tscales\t15\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t-1.57084\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\te7150bed-3e3e-c698-eb15-d17b178148af\n\t\tcolors\t0.843137 0.156863 0.156863 1\n\t\tscales\t15\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t-1.57084\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\tps_next_crc\t1\n\tgpw_bias\t1\n\tip\t0\n\tcomplete\tTRUE\n\tdelay\t50000\n\tnextstart\t0\n\tbirthtime\t1061087534454174\n\treztime\t1094866329021741\n\tparceltime\t1133568981982889\n\ttax_rate\t1.00326\n\tscratchpad\t0\n\t{\n\t\n\t}\n\tsale_info\t0\n\t{\n\t\tsale_type\tnot\n\t\tsale_price\t10\n\t}\n\tcorrect_family_id\t00000000-0000-0000-0000-000000000000\n\thas_rezzed\t0\n\tpre_link_base_mask\t7fffffff\n\tlinked \tchild\n\tdefault_pay_price\t-2\t1\t5\t10\t20\n}\n{'task_id':ue4b19200-9d33-962f-c8c5-6f" + "25be3a3fd0}\n{\n\tname\tApotheosis_Immolaine_tail|\n\tpermissions 0\n\t{\n\t\tbase_mask\t7fffffff\n\t\towner_mask\t7fffffff\n\t\tgroup_mask\t00000000\n\t\teveryone_mask\t00000000\n\t\tnext_owner_mask\t7fffffff\n\t\tcreator_id\t13fd9595-a47b-4d64-a5fb-6da645f038e0\n\t\towner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tlast_owner_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\t\tgroup_id\t00000000-0000-0000-0000-000000000000\n\t}\n\tlocal_id\t217444924\n\ttotal_crc\t675\n\ttype\t1\n\ttask_valid\t2\n\ttravel_access\t13\n\tdisplayopts\t2\n\tdisplaytype\tv\n\tpos\t-0.34780401\t-0.00968400016\t-0.260098994\n\toldpos\t0\t0\t0\n\trotation\t0.73164522647857666015625\t-0.67541944980621337890625\t-0.07733880728483200073242188\t0.05022468417882919311523438\n\tvelocity\t0\t0\t0\n\tangvel\t0\t0\t0\n\tscale\t0.0382982\t0.32228\t0.383834\n\tsit_offset\t0\t0\t0\n\tcamera_eye_offset\t0\t0\t0\n\tcamera_at_offset\t0\t0\t0\n\tsit_quat\t0\t0\t0\t1\n\tsit_hint\t0\n\tstate\t160\n\tmaterial\t3\n\tsoundid\t00000" + "000-0000-0000-0000-000000000000\n\tsoundgain\t0\n\tsoundradius\t0\n\tsoundflags\t0\n\ttextcolor\t0 0 0 1\n\tselected\t0\n\tselector\t00000000-0000-0000-0000-000000000000\n\tusephysics\t0\n\trotate_x\t1\n\trotate_y\t1\n\trotate_z\t1\n\tphantom\t0\n\tremote_script_access_pin\t0\n\tvolume_detect\t0\n\tblock_grabs\t0\n\tdie_at_edge\t0\n\treturn_at_edge\t0\n\ttemporary\t0\n\tsandbox\t0\n\tsandboxhome\t0\t0\t0\n\tshape 0\n\t{\n\t\tpath 0\n\t\t{\n\t\t\tcurve\t32\n\t\t\tbegin\t0.3\n\t\t\tend\t0.65\n\t\t\tscale_x\t1\n\t\t\tscale_y\t0.05\n\t\t\tshear_x\t0\n\t\t\tshear_y\t0\n\t\t\ttwist\t0\n\t\t\ttwist_begin\t0\n\t\t\tradius_offset\t0\n\t\t\ttaper_x\t0\n\t\t\ttaper_y\t0\n\t\t\trevolutions\t1\n\t\t\tskew\t0\n\t\t}\n\t\tprofile 0\n\t\t{\n\t\t\tcurve\t0\n\t\t\tbegin\t0\n\t\t\tend\t1\n\t\t\thollow\t0\n\t\t}\n\t}\n\tfaces\t3\n\t{\n\t\timageid\te7150bed-3e3e-c698-eb15-d17b178148af\n\t\tcolors\t0.843137 0.156863 0.156863 1\n\t\tscales\t15\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t-1" + ".57084\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\te7150bed-3e3e-c698-eb15-d17b178148af\n\t\tcolors\t0.843137 0.156863 0.156863 1\n\t\tscales\t15\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t-1.57084\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\t{\n\t\timageid\te7150bed-3e3e-c698-eb15-d17b178148af\n\t\tcolors\t0.843137 0.156863 0.156863 1\n\t\tscales\t15\n\t\tscalet\t1\n\t\toffsets\t0\n\t\toffsett\t0\n\t\timagerot\t-1.57084\n\t\tbump\t0\n\t\tfullbright\t0\n\t\tmedia_flags\t0\n\t}\n\tps_next_crc\t1\n\tgpw_bias\t1\n\tip\t0\n\tcomplete\tTRUE\n\tdelay\t50000\n\tnextstart\t0\n\tbirthtime\t1061087463950186\n\treztime\t1094866329022555\n\tparceltime\t1133568981984359\n\tdescription\t(No Description)|\n\ttax_rate\t1.01736\n\tnamevalue\tAttachPt U32 RW S 10\n\tnamevalue\tAttachmentOrientation VEC3 RW DS -3.110088, -0.182018, 1.493795\n\tnamevalue\tAttachmentOffset VEC3 RW DS -0.347804, -0.009684, -0.260099\n\tnamevalue\tAttachItemI" + "D STRING RW SV 20f36c3a-b44b-9bc7-87f3-018bfdfc8cda\n\tscratchpad\t0\n\t{\n\t\n\t}\n\tsale_info\t0\n\t{\n\t\tsale_type\tnot\n\t\tsale_price\t10\n\t}\n\torig_asset_id\t8747acbc-d391-1e59-69f1-41d06830e6c0\n\torig_item_id\t20f36c3a-b44b-9bc7-87f3-018bfdfc8cda\n\tfrom_task_id\t3c115e51-04f4-523c-9fa6-98aff1034730\n\tcorrect_family_id\t00000000-0000-0000-0000-000000000000\n\thas_rezzed\t0\n\tpre_link_base_mask\t7fffffff\n\tlinked \tlinked\n\tdefault_pay_price\t-2\t1\t5\t10\t20\n}\n"); + } + + + template<> template<> + void URITestObject::test<18>() + { + LLURI u("secondlife:///app/login?first_name=Testert4&last_name=Tester&web_login_key=test"); + // if secondlife is the scheme, LLURI should parse /app/login as path, with no authority + ensure_equals("scheme", u.scheme(), "secondlife"); + ensure_equals("authority", u.authority(), ""); + ensure_equals("path", u.path(), "/app/login"); + ensure_equals("pathmap", u.pathArray()[0].asString(), "app"); + ensure_equals("pathmap", u.pathArray()[1].asString(), "login"); + ensure_equals("query", u.query(), "first_name=Testert4&last_name=Tester&web_login_key=test"); + ensure_equals("query map element", u.queryMap()["last_name"].asString(), "Tester"); + + u = LLURI("secondlife://Da Boom/128/128/128"); + // if secondlife is the scheme, LLURI should parse /128/128/128 as path, with Da Boom as authority + ensure_equals("scheme", u.scheme(), "secondlife"); + ensure_equals("authority", u.authority(), "Da Boom"); + ensure_equals("path", u.path(), "/128/128/128"); + ensure_equals("pathmap", u.pathArray()[0].asString(), "128"); + ensure_equals("pathmap", u.pathArray()[1].asString(), "128"); + ensure_equals("pathmap", u.pathArray()[2].asString(), "128"); + ensure_equals("query", u.query(), ""); + } + + template<> template<> + void URITestObject::test<19>() + { + set_test_name("Parse about: schemes"); + LLURI u("about:blank?redirect-http-hack=secondlife%3A%2F%2F%2Fapp%2Flogin%3Ffirst_name%3DCallum%26last_name%3DLinden%26location%3Dspecify%26grid%3Dvaak%26region%3D%2FMorris%2F128%2F128%26web_login_key%3Defaa4795-c2aa-4c58-8966-763c27931e78"); + ensure_equals("scheme", u.scheme(), "about"); + ensure_equals("authority", u.authority(), ""); + ensure_equals("path", u.path(), "blank"); + ensure_equals("pathmap", u.pathArray()[0].asString(), "blank"); + ensure_equals("query", u.query(), "redirect-http-hack=secondlife:///app/login?first_name=Callum&last_name=Linden&location=specify&grid=vaak®ion=/Morris/128/128&web_login_key=efaa4795-c2aa-4c58-8966-763c27931e78"); + ensure_equals("query map element", u.queryMap()["redirect-http-hack"].asString(), "secondlife:///app/login?first_name=Callum&last_name=Linden&location=specify&grid=vaak®ion=/Morris/128/128&web_login_key=efaa4795-c2aa-4c58-8966-763c27931e78"); + } + + template<> template<> + void URITestObject::test<20>() + { set_test_name("escapePathAndData uri test"); // Basics scheme:[//authority]path[?query][#fragment] diff --git a/indra/llcommon/tests/stringize_test.cpp b/indra/llcommon/tests/stringize_test.cpp index 2a4ed44a67..a3ce7f8e3d 100644 --- a/indra/llcommon/tests/stringize_test.cpp +++ b/indra/llcommon/tests/stringize_test.cpp @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2008-09-12 * @brief Test of stringize.h - * + * * $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$ */ @@ -78,7 +78,7 @@ namespace tut float f; double d; std::string abc; - std::wstring def; + std::wstring def; LLSD llsd; }; typedef test_group stringize_group; diff --git a/indra/llcommon/tests/threadsafeschedule_test.cpp b/indra/llcommon/tests/threadsafeschedule_test.cpp index 8851590189..f2f17dd2e6 100644 --- a/indra/llcommon/tests/threadsafeschedule_test.cpp +++ b/indra/llcommon/tests/threadsafeschedule_test.cpp @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2021-10-04 * @brief Test for threadsafeschedule. - * + * * $LicenseInfo:firstyear=2021&license=viewerlgpl$ * Copyright (c) 2021, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/tests/tuple_test.cpp b/indra/llcommon/tests/tuple_test.cpp index af94e2086c..aff129753f 100644 --- a/indra/llcommon/tests/tuple_test.cpp +++ b/indra/llcommon/tests/tuple_test.cpp @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2021-10-04 * @brief Test for tuple. - * + * * $LicenseInfo:firstyear=2021&license=viewerlgpl$ * Copyright (c) 2021, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/tests/workqueue_test.cpp b/indra/llcommon/tests/workqueue_test.cpp index df16f4a46e..209b6b868c 100644 --- a/indra/llcommon/tests/workqueue_test.cpp +++ b/indra/llcommon/tests/workqueue_test.cpp @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2021-10-07 * @brief Test for workqueue. - * + * * $LicenseInfo:firstyear=2021&license=viewerlgpl$ * Copyright (c) 2021, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/tests/wrapllerrs.h b/indra/llcommon/tests/wrapllerrs.h index 6978c296b3..9cd2c69b11 100644 --- a/indra/llcommon/tests/wrapllerrs.h +++ b/indra/llcommon/tests/wrapllerrs.h @@ -3,25 +3,25 @@ * @author Nat Goodspeed * @date 2009-03-11 * @brief Define a class useful for unit tests that engage llerrs (LL_ERRS) functionality - * + * * $LicenseInfo:firstyear=2009&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -117,9 +117,9 @@ class CaptureLogRecorder : public LLError::Recorder, public boost::noncopyable { public: CaptureLogRecorder() - : LLError::Recorder(), - boost::noncopyable(), - mMessages() + : LLError::Recorder(), + boost::noncopyable(), + mMessages() { } diff --git a/indra/llcommon/threadpool.cpp b/indra/llcommon/threadpool.cpp index c48989358e..302bbe6f8d 100644 --- a/indra/llcommon/threadpool.cpp +++ b/indra/llcommon/threadpool.cpp @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2021-10-21 * @brief Implementation for threadpool. - * + * * $LicenseInfo:firstyear=2021&license=viewerlgpl$ * Copyright (c) 2021, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/threadpool.h b/indra/llcommon/threadpool.h index 74056aea17..0eb1891754 100644 --- a/indra/llcommon/threadpool.h +++ b/indra/llcommon/threadpool.h @@ -4,7 +4,7 @@ * @date 2021-10-21 * @brief ThreadPool configures a WorkQueue along with a pool of threads to * service it. - * + * * $LicenseInfo:firstyear=2021&license=viewerlgpl$ * Copyright (c) 2021, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/threadpool_fwd.h b/indra/llcommon/threadpool_fwd.h index 1aa3c4a0e2..50e212ef05 100644 --- a/indra/llcommon/threadpool_fwd.h +++ b/indra/llcommon/threadpool_fwd.h @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2022-12-09 * @brief Forward declarations for ThreadPool et al. - * + * * $LicenseInfo:firstyear=2022&license=viewerlgpl$ * Copyright (c) 2022, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/threadsafeschedule.h b/indra/llcommon/threadsafeschedule.h index 92bc7da940..0c7f583819 100644 --- a/indra/llcommon/threadsafeschedule.h +++ b/indra/llcommon/threadsafeschedule.h @@ -4,7 +4,7 @@ * @date 2021-10-02 * @brief ThreadSafeSchedule is an ordered queue in which every item has an * associated timestamp. - * + * * $LicenseInfo:firstyear=2021&license=viewerlgpl$ * Copyright (c) 2021, Linden Research, Inc. * $/LicenseInfo$ @@ -18,7 +18,7 @@ #include "llthreadsafequeue.h" #include "tuple.h" #include -#include +#include namespace LL { diff --git a/indra/llcommon/timer.h b/indra/llcommon/timer.h index 82d19c2d32..aaa0cf0775 100644 --- a/indra/llcommon/timer.h +++ b/indra/llcommon/timer.h @@ -1,25 +1,25 @@ -/** +/** * @file timer.h * @brief Legacy wrapper header. * * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcommon/tuple.h b/indra/llcommon/tuple.h index bfe7e3c2ba..21337650ef 100644 --- a/indra/llcommon/tuple.h +++ b/indra/llcommon/tuple.h @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2021-10-04 * @brief A couple tuple utilities - * + * * $LicenseInfo:firstyear=2021&license=viewerlgpl$ * Copyright (c) 2021, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/u64.cpp b/indra/llcommon/u64.cpp index 02c2c15d26..1d39d3c3e5 100644 --- a/indra/llcommon/u64.cpp +++ b/indra/llcommon/u64.cpp @@ -1,25 +1,25 @@ -/** +/** * @file u64.cpp * @brief Utilities to deal with U64s. * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -31,75 +31,75 @@ U64 str_to_U64(const std::string& str) { - U64 result = 0; - const char *aptr = strpbrk(str.c_str(),"0123456789"); + U64 result = 0; + const char *aptr = strpbrk(str.c_str(),"0123456789"); - if (!aptr) - { - LL_WARNS() << "str_to_U64: Bad string to U64 conversion attempt: format\n" << LL_ENDL; - } - else - { - while ((*aptr >= '0') && (*aptr <= '9')) - { - result = result*10 + (*aptr++ - '0'); - } - } - return (result); + if (!aptr) + { + LL_WARNS() << "str_to_U64: Bad string to U64 conversion attempt: format\n" << LL_ENDL; + } + else + { + while ((*aptr >= '0') && (*aptr <= '9')) + { + result = result*10 + (*aptr++ - '0'); + } + } + return (result); } -std::string U64_to_str(U64 value) +std::string U64_to_str(U64 value) { - std::string res; - U32 part1,part2,part3; - - part3 = (U32)(value % (U64)10000000); - - value /= 10000000; - part2 = (U32)(value % (U64)10000000); - - value /= 10000000; - part1 = (U32)(value % (U64)10000000); - - // three cases to avoid leading zeroes unless necessary - - if (part1) - { - res = llformat("%u%07u%07u",part1,part2,part3); - } - else if (part2) - { - res = llformat("%u%07u",part2,part3); - } - else - { - res = llformat("%u",part3); - } - return res; -} + std::string res; + U32 part1,part2,part3; + + part3 = (U32)(value % (U64)10000000); + + value /= 10000000; + part2 = (U32)(value % (U64)10000000); + + value /= 10000000; + part1 = (U32)(value % (U64)10000000); + + // three cases to avoid leading zeroes unless necessary + + if (part1) + { + res = llformat("%u%07u%07u",part1,part2,part3); + } + else if (part2) + { + res = llformat("%u%07u",part2,part3); + } + else + { + res = llformat("%u",part3); + } + return res; +} -char* U64_to_str(U64 value, char* result, S32 result_size) +char* U64_to_str(U64 value, char* result, S32 result_size) { - std::string res = U64_to_str(value); - LLStringUtil::copy(result, res.c_str(), result_size); - return result; + std::string res = U64_to_str(value); + LLStringUtil::copy(result, res.c_str(), result_size); + return result; } F64 U64_to_F64(const U64 value) { - S64 top_bits = (S64)(value >> 1); - F64 result = (F64)top_bits; - result *= 2.f; - result += (U32)(value & 0x01); - return result; + S64 top_bits = (S64)(value >> 1); + F64 result = (F64)top_bits; + result *= 2.f; + result += (U32)(value & 0x01); + return result; } -U64 llstrtou64(const char* str, char** end, S32 base) +U64 llstrtou64(const char* str, char** end, S32 base) { #ifdef LL_WINDOWS - return _strtoui64(str,end,base); + return _strtoui64(str,end,base); #else - return strtoull(str,end,base); + return strtoull(str,end,base); #endif } diff --git a/indra/llcommon/u64.h b/indra/llcommon/u64.h index 75c8a59136..d70477feb0 100644 --- a/indra/llcommon/u64.h +++ b/indra/llcommon/u64.h @@ -1,25 +1,25 @@ -/** +/** * @file u64.h * @brief Utilities to deal with U64s. * * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code * Copyright (C) 2010, Linden Research, Inc. - * + * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License only. - * + * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. - * + * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - * + * * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ diff --git a/indra/llcommon/workqueue.cpp b/indra/llcommon/workqueue.cpp index cf80ce0656..6066e74fb5 100644 --- a/indra/llcommon/workqueue.cpp +++ b/indra/llcommon/workqueue.cpp @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2021-10-06 * @brief Implementation for WorkQueue. - * + * * $LicenseInfo:firstyear=2021&license=viewerlgpl$ * Copyright (c) 2021, Linden Research, Inc. * $/LicenseInfo$ diff --git a/indra/llcommon/workqueue.h b/indra/llcommon/workqueue.h index ec0700a718..9d7bbfbf7a 100644 --- a/indra/llcommon/workqueue.h +++ b/indra/llcommon/workqueue.h @@ -3,7 +3,7 @@ * @author Nat Goodspeed * @date 2021-09-30 * @brief Queue used for inter-thread work passing. - * + * * $LicenseInfo:firstyear=2021&license=viewerlgpl$ * Copyright (c) 2021, Linden Research, Inc. * $/LicenseInfo$ -- cgit v1.2.3 From 9deeec22b7348f56b1d32ab6aff73c59e002ff21 Mon Sep 17 00:00:00 2001 From: Nat Goodspeed Date: Wed, 8 May 2024 15:26:00 -0400 Subject: Bump up coroutine stack size: saw C00000FD test termination. (cherry picked from commit dc0b3aed4782e4e4835fd6b9d59d1d70b78be4a7) --- indra/llcommon/llcoros.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'indra/llcommon') diff --git a/indra/llcommon/llcoros.cpp b/indra/llcommon/llcoros.cpp index c13900f74a..8612f9353f 100644 --- a/indra/llcommon/llcoros.cpp +++ b/indra/llcommon/llcoros.cpp @@ -123,7 +123,7 @@ LLCoros::LLCoros(): // Previously we used // boost::context::guarded_stack_allocator::default_stacksize(); // empirically this is insufficient. - mStackSize(900*1024), + mStackSize(1024*1024), // mCurrent does NOT own the current CoroData instance -- it simply // points to it. So initialize it with a no-op deleter. mCurrent{ [](CoroData*){} } -- cgit v1.2.3