diff options
Diffstat (limited to 'indra/llcommon')
44 files changed, 764 insertions, 446 deletions
diff --git a/indra/llcommon/CMakeLists.txt b/indra/llcommon/CMakeLists.txt index 95e991c246..8e43627a5f 100644 --- a/indra/llcommon/CMakeLists.txt +++ b/indra/llcommon/CMakeLists.txt @@ -10,7 +10,6 @@ include(Boost) include(LLSharedLibs) include(Copy3rdPartyLibs) include(ZLIBNG) -include(URIPARSER) include(Tracy) @@ -278,7 +277,6 @@ target_link_libraries( ll::expat ll::zlib-ng ll::boost - ll::uriparser ll::oslibraries ll::tracy ) diff --git a/indra/llcommon/llapp.cpp b/indra/llcommon/llapp.cpp index b85bd2573b..6da764f94c 100644 --- a/indra/llcommon/llapp.cpp +++ b/indra/llcommon/llapp.cpp @@ -90,7 +90,7 @@ bool LLApp::sDisableCrashlogger = false; // Local flag for whether or not to do logging in signal handlers. //static -bool LLApp::sLogInSignal = false; +bool LLApp::sLogInSignal = true; // static // Keeps track of application status @@ -373,6 +373,9 @@ static std::map<LLApp::EAppStatus, const char*> statusDesc // static void LLApp::setStatus(EAppStatus status) { + auto status_it = statusDesc.find(status); + std::string status_text = status_it != statusDesc.end() ? std::string(status_it->second) : std::to_string(status); + LL_INFOS() << "status: " << status_text << LL_ENDL; // notify everyone waiting on sStatus any time its value changes sStatus.set_all(status); @@ -381,18 +384,7 @@ void LLApp::setStatus(EAppStatus status) if (! LLEventPumps::wasDeleted()) { // notify interested parties of status change - LLSD statsd; - auto found = statusDesc.find(status); - if (found != statusDesc.end()) - { - statsd = found->second; - } - else - { - // unknown status? at least report value - statsd = LLSD::Integer(status); - } - LLEventPumps::instance().obtain("LLApp").post(llsd::map("status", statsd)); + LLEventPumps::instance().obtain("LLApp").post(llsd::map("status", status_text)); } } @@ -487,6 +479,33 @@ int LLApp::getPid() #endif } +// static +void LLApp::notifyOutOfDiskSpace() +{ + static const U32Seconds min_interval = U32Seconds(60); + static U32Seconds min_time_to_send = U32Seconds(0); + U32Seconds now = LLTimer::getTotalTime(); + if (now < min_time_to_send) + return; + + min_time_to_send = now + min_interval; + + if (LLApp* app = instance()) + { + app->sendOutOfDiskSpaceNotification(); + } + else + { + LL_WARNS() << "No app instance" << LL_ENDL; + } +} + +// virtual +void LLApp::sendOutOfDiskSpaceNotification() +{ + LL_WARNS() << "Should never be called" << LL_ENDL; // Should be overridden +} + #ifndef LL_WINDOWS void setup_signals() { @@ -654,6 +673,7 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *) { LL_WARNS() << "Signal handler - Handling fatal signal!" << LL_ENDL; } + if (LLApp::isError()) { // Received second fatal signal while handling first, just die right now @@ -691,11 +711,11 @@ void default_unix_signal_handler(int signum, siginfo_t *info, void *) clear_signals(); raise(signum); return; - } else { - if (LLApp::sLogInSignal) - { - LL_INFOS() << "Signal handler - Unhandled signal " << signum << ", ignoring!" << LL_ENDL; - } + } + + if (LLApp::sLogInSignal) + { + LL_INFOS() << "Signal handler - Unhandled signal " << signum << ", ignoring!" << LL_ENDL; } } } diff --git a/indra/llcommon/llapp.h b/indra/llcommon/llapp.h index ad8912ca88..d90ecdf661 100644 --- a/indra/llcommon/llapp.h +++ b/indra/llcommon/llapp.h @@ -202,6 +202,8 @@ public: static bool isExiting(); // Either quitting or error (app is exiting, cleanly or not) static int getPid(); + static void notifyOutOfDiskSpace(); + // // Sleep for specified time while still running // @@ -301,6 +303,8 @@ protected: */ void stepFrame(); + virtual void sendOutOfDiskSpaceNotification(); + private: // Contains the filename of the minidump file after a crash. char mMinidumpPath[MAX_MINDUMP_PATH_LENGTH]; diff --git a/indra/llcommon/llapr.cpp b/indra/llcommon/llapr.cpp index b085f8f5dc..01763c49aa 100644 --- a/indra/llcommon/llapr.cpp +++ b/indra/llcommon/llapr.cpp @@ -28,6 +28,7 @@ #include "linden_common.h" #include "llapr.h" +#include "llapp.h" #include "llmutex.h" #include "apr_dso.h" @@ -606,7 +607,11 @@ S32 LLAPRFile::writeEx(const std::string& filename, const void *buf, S32 offset, 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_WARNS("APR") << "Attempting to write filename: " << filename << LL_ENDL; + if (APR_STATUS_IS_ENOSPC(s)) + { + LLApp::notifyOutOfDiskSpace(); + } ll_apr_warn_status(s); bytes_written = 0; } diff --git a/indra/llcommon/llcoros.h b/indra/llcommon/llcoros.h index 369d65407e..c3820ae987 100644 --- a/indra/llcommon/llcoros.h +++ b/indra/llcommon/llcoros.h @@ -31,8 +31,9 @@ #include "llexception.h" #include <boost/fiber/fss.hpp> -#include <boost/fiber/future/promise.hpp> #include <boost/fiber/future/future.hpp> +#include <boost/fiber/future/promise.hpp> +#include <boost/fiber/recursive_mutex.hpp> #include "mutex.h" #include "llsingleton.h" #include "llinstancetracker.h" @@ -307,6 +308,12 @@ public: // use mutex, lock, condition_variable suitable for coroutines using Mutex = boost::fibers::mutex; + using RMutex = boost::fibers::recursive_mutex; + // With C++17, LockType is deprecated: at this point we can directly + // declare 'std::unique_lock lk(some_mutex)' without explicitly stating + // the mutex type. Sadly, making LockType an alias template for + // std::unique_lock doesn't work the same way: Class Template Argument + // Deduction only works for class templates, not alias templates. using LockType = std::unique_lock<Mutex>; using cv_status = boost::fibers::cv_status; using ConditionVariable = boost::fibers::condition_variable; diff --git a/indra/llcommon/lldate.cpp b/indra/llcommon/lldate.cpp index c63c7012d1..b38864688d 100644 --- a/indra/llcommon/lldate.cpp +++ b/indra/llcommon/lldate.cpp @@ -41,20 +41,11 @@ #include "llstring.h" #include "llfasttimer.h" -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 -LLDate::LLDate() : mSecondsSinceEpoch(DATE_EPOCH) -{} - -LLDate::LLDate(const LLDate& date) : - mSecondsSinceEpoch(date.mSecondsSinceEpoch) -{} - LLDate::LLDate(F64SecondsImplicit seconds_since_epoch) : mSecondsSinceEpoch(seconds_since_epoch.value()) {} diff --git a/indra/llcommon/lldate.h b/indra/llcommon/lldate.h index 81f2dd0d1c..1a69a04232 100644 --- a/indra/llcommon/lldate.h +++ b/indra/llcommon/lldate.h @@ -43,16 +43,13 @@ */ class LL_COMMON_API LLDate { + static constexpr F64 DATE_EPOCH = 0.0; public: /** * @brief Construct a date equal to epoch. */ - LLDate(); - - /** - * @brief Construct a date equal to the source date. - */ - LLDate(const LLDate& date); + constexpr LLDate() : mSecondsSinceEpoch(DATE_EPOCH) + {} /** * @brief Construct a date from a seconds since epoch value. diff --git a/indra/llcommon/llerror.cpp b/indra/llcommon/llerror.cpp index fa24987d1c..6c3b9c9542 100644 --- a/indra/llcommon/llerror.cpp +++ b/indra/llcommon/llerror.cpp @@ -55,7 +55,6 @@ #include "llsingleton.h" #include "llstl.h" #include "lltimer.h" -#include <boost/fiber/recursive_mutex.hpp> // On Mac, got: // #error "Boost.Stacktrace requires `_Unwind_Backtrace` function. Define @@ -168,7 +167,7 @@ namespace { virtual void recordMessage(LLError::ELevel level, const std::string& message) override { - LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING + LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING; if (LLError::getAlwaysFlush()) { mFile << message << std::endl; @@ -235,7 +234,7 @@ namespace { virtual void recordMessage(LLError::ELevel level, const std::string& message) override { - LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING + 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 // now have the option to set the color of each via an environment variables: @@ -275,7 +274,7 @@ namespace { LL_FORCE_INLINE void writeANSI(const std::string& ansi_code, const std::string& message) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING + 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 @@ -312,7 +311,7 @@ namespace { virtual void recordMessage(LLError::ELevel level, const std::string& message) override { - LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING + LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING; mBuffer->addLine(message); } @@ -339,7 +338,7 @@ namespace { virtual void recordMessage(LLError::ELevel level, const std::string& message) override { - LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING + LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING; debugger_print(message); } }; @@ -507,7 +506,7 @@ namespace LLError::TimeFunction mTimeFunction; Recorders mRecorders; - boost::fibers::recursive_mutex mRecorderMutex; + LLCoros::RMutex mRecorderMutex; int mShouldLogCallCounter; @@ -1216,7 +1215,7 @@ namespace void writeToRecorders(const LLError::CallSite& site, const std::string& message) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING + LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING; LLError::ELevel level = site.mLevel; SettingsConfigPtr s = Globals::getInstance()->getSettingsConfig(); @@ -1347,7 +1346,7 @@ namespace LLError bool Log::shouldLog(CallSite& site) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING + LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING; LLMutexTrylock lock(getMutex<LOG_MUTEX>(), 5); if (!lock.isLocked()) { @@ -1392,7 +1391,7 @@ namespace LLError void Log::flush(const std::ostringstream& out, const CallSite& site) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING + LL_PROFILE_ZONE_SCOPED_CATEGORY_LOGGING; LLMutexTrylock lock(getMutex<LOG_MUTEX>(),5); if (!lock.isLocked()) { diff --git a/indra/llcommon/llerrorcontrol.h b/indra/llcommon/llerrorcontrol.h index bf5a6df556..2be443ca37 100644 --- a/indra/llcommon/llerrorcontrol.h +++ b/indra/llcommon/llerrorcontrol.h @@ -190,7 +190,7 @@ namespace LLError {} void recordMessage(LLError::ELevel level, const std::string& message) override { - LL_PROFILE_ZONE_SCOPED + LL_PROFILE_ZONE_SCOPED; mCallable(level, message); } private: diff --git a/indra/llcommon/lleventfilter.h b/indra/llcommon/lleventfilter.h index 5c45144fad..d8c7e15a27 100644 --- a/indra/llcommon/lleventfilter.h +++ b/indra/llcommon/lleventfilter.h @@ -429,7 +429,7 @@ public: // path, then stores it to mTarget. virtual bool post(const LLSD& event) { - LL_PROFILE_ZONE_SCOPED + LL_PROFILE_ZONE_SCOPED; // Extract the element specified by 'mPath' from 'event'. To perform a // generic type-appropriate store through mTarget, construct an diff --git a/indra/llcommon/llfile.cpp b/indra/llcommon/llfile.cpp index ddf239f306..9045324bf2 100644 --- a/indra/llcommon/llfile.cpp +++ b/indra/llcommon/llfile.cpp @@ -248,6 +248,24 @@ int LLFile::close(LLFILE * file) return ret_value; } +std::string LLFile::getContents(const std::string& filename) +{ + LLFILE* fp = fopen(filename, "rb"); /* Flawfinder: ignore */ + if (fp) + { + fseek(fp, 0, SEEK_END); + U32 length = ftell(fp); + fseek(fp, 0, SEEK_SET); + + std::vector<char> buffer(length); + size_t nread = fread(buffer.data(), 1, length, fp); + fclose(fp); + + return std::string(buffer.data(), nread); + } + + return LLStringUtil::null; +} int LLFile::remove(const std::string& filename, int supress_error) { diff --git a/indra/llcommon/llfile.h b/indra/llcommon/llfile.h index 2564671b13..74110343fc 100644 --- a/indra/llcommon/llfile.h +++ b/indra/llcommon/llfile.h @@ -67,6 +67,8 @@ public: static int close(LLFILE * file); + static std::string getContents(const std::string& filename); + // 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. diff --git a/indra/llcommon/llmemory.cpp b/indra/llcommon/llmemory.cpp index 4b7d60d654..99c803e46f 100644 --- a/indra/llcommon/llmemory.cpp +++ b/indra/llcommon/llmemory.cpp @@ -39,6 +39,7 @@ #elif LL_LINUX # include <unistd.h> # include <sys/resource.h> +# include <sys/sysinfo.h> #endif #include "llmemory.h" @@ -50,13 +51,28 @@ //---------------------------------------------------------------------------- //static + +// most important memory metric for texture streaming +// On Windows, this should agree with resource monitor -> performance -> memory -> available +// On OS X, this should be activity monitor -> memory -> (physical memory - memory used) +// NOTE: this number MAY be less than the actual available memory on systems with more than MaxHeapSize64 GB of physical memory (default 16GB) +// In that case, should report min(available, sMaxHeapSizeInKB-sAllocateMemInKB) U32Kilobytes LLMemory::sAvailPhysicalMemInKB(U32_MAX); + +// Installed physical memory U32Kilobytes LLMemory::sMaxPhysicalMemInKB(0); -static LLTrace::SampleStatHandle<F64Megabytes> sAllocatedMem("allocated_mem", "active memory in use by application"); -static LLTrace::SampleStatHandle<F64Megabytes> sVirtualMem("virtual_mem", "virtual memory assigned to application"); + +// Maximimum heap size according to the user's settings (default 16GB) +U32Kilobytes LLMemory::sMaxHeapSizeInKB(U32_MAX); + +// Current memory usage U32Kilobytes LLMemory::sAllocatedMemInKB(0); + U32Kilobytes LLMemory::sAllocatedPageSizeInKB(0); -U32Kilobytes LLMemory::sMaxHeapSizeInKB(U32_MAX); + + +static LLTrace::SampleStatHandle<F64Megabytes> sAllocatedMem("allocated_mem", "active memory in use by application"); +static LLTrace::SampleStatHandle<F64Megabytes> sVirtualMem("virtual_mem", "virtual memory assigned to application"); void ll_assert_aligned_func(uintptr_t ptr,U32 alignment) { @@ -84,7 +100,14 @@ void LLMemory::initMaxHeapSizeGB(F32Gigabytes max_heap_size) //static void LLMemory::updateMemoryInfo() { - LL_PROFILE_ZONE_SCOPED + LL_PROFILE_ZONE_SCOPED; + + sMaxPhysicalMemInKB = gSysMemory.getPhysicalMemoryKB(); + + U32Kilobytes avail_mem; + LLMemoryInfo::getAvailableMemoryKB(avail_mem); + sAvailPhysicalMemInKB = avail_mem; + #if LL_WINDOWS PROCESS_MEMORY_COUNTERS counters; @@ -95,23 +118,9 @@ void LLMemory::updateMemoryInfo() } 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; mach_msg_type_number_t infoCount = TASK_VM_INFO_COUNT; @@ -136,31 +145,19 @@ void LLMemory::updateMemoryInfo() { LL_WARNS() << "task_info failed" << LL_ENDL; } - - // Total installed and available physical memory are properties of the host, not just our process. - vm_statistics64_data_t vmstat; - mach_msg_type_number_t count = HOST_VM_INFO64_COUNT; - mach_port_t host = mach_host_self(); - vm_size_t page_size; - host_page_size(host, &page_size); - kern_return_t result = host_statistics64(host, HOST_VM_INFO64, reinterpret_cast<host_info_t>(&vmstat), &count); - if (result == KERN_SUCCESS) { - // This is what Chrome reports as 'the "Physical Memory Free" value reported by the Memory Monitor in Instruments.' - // Note though that inactive pages are not included here and not yet free, but could become so under memory pressure. - sAvailPhysicalMemInKB = U32Bytes(vmstat.free_count * page_size); - sMaxPhysicalMemInKB = LLMemoryInfo::getHardwareMemSize(); - } - else - { - LL_WARNS() << "task_info failed" << LL_ENDL; - } - +#elif defined(LL_LINUX) + // Use sysinfo() to get the total physical memory. + struct sysinfo info; + sysinfo(&info); + sAllocatedMemInKB = U32Kilobytes::convert(U64Bytes(LLMemory::getCurrentRSS())); // represents the RAM allocated by this process only (in line with the windows implementation) #else //not valid for other systems for now. + LL_WARNS() << "LLMemory::updateMemoryInfo() not implemented for this platform." << LL_ENDL; sAllocatedMemInKB = U64Bytes(LLMemory::getCurrentRSS()); - sMaxPhysicalMemInKB = U64Bytes(U32_MAX); - sAvailPhysicalMemInKB = U64Bytes(U32_MAX); #endif + sample(sAllocatedMem, sAllocatedMemInKB); + + sAvailPhysicalMemInKB = llmin(sAvailPhysicalMemInKB, sMaxHeapSizeInKB - sAllocatedMemInKB); return ; } @@ -192,16 +189,16 @@ void* LLMemory::tryToAlloc(void* address, U32 size) //static void LLMemory::logMemoryInfo(bool update) { - LL_PROFILE_ZONE_SCOPED + 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_INFOS() << llformat("Current allocated physical memory: %.2f MB", sAllocatedMemInKB / 1024.0) << LL_ENDL; + LL_INFOS() << llformat("Current allocated page size: %.2f MB", sAllocatedPageSizeInKB / 1024.0) << LL_ENDL; + LL_INFOS() << llformat("Current available physical memory: %.2f MB", sAvailPhysicalMemInKB / 1024.0) << LL_ENDL; + LL_INFOS() << llformat("Current max usable memory: %.2f MB", sMaxPhysicalMemInKB / 1024.0) << LL_ENDL; } //static diff --git a/indra/llcommon/llmutex.cpp b/indra/llcommon/llmutex.cpp index 40c651d9c1..be1ae89a25 100644 --- a/indra/llcommon/llmutex.cpp +++ b/indra/llcommon/llmutex.cpp @@ -100,7 +100,7 @@ void LLMutex::unlock() bool LLMutex::isLocked() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; if (!mMutex.try_lock()) { return true; @@ -124,7 +124,7 @@ LLThread::id_t LLMutex::lockingThread() const bool LLMutex::trylock() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; if (isSelfLocked()) { //redundant lock mCount++; @@ -161,7 +161,7 @@ LLSharedMutex::LLSharedMutex() bool LLSharedMutex::isLocked() const { - LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; std::lock_guard<std::mutex> lock(mLockMutex); return !mLockingThreads.empty(); @@ -169,7 +169,7 @@ bool LLSharedMutex::isLocked() const bool LLSharedMutex::isThreadLocked() const { - LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; LLThread::id_t current_thread = LLThread::currentID(); std::lock_guard<std::mutex> lock(mLockMutex); @@ -179,7 +179,7 @@ bool LLSharedMutex::isThreadLocked() const void LLSharedMutex::lockShared() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; LLThread::id_t current_thread = LLThread::currentID(); mLockMutex.lock(); @@ -204,7 +204,7 @@ void LLSharedMutex::lockShared() void LLSharedMutex::lockExclusive() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; LLThread::id_t current_thread = LLThread::currentID(); mLockMutex.lock(); @@ -237,7 +237,7 @@ void LLSharedMutex::lockExclusive() bool LLSharedMutex::trylockShared() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; LLThread::id_t current_thread = LLThread::currentID(); std::lock_guard<std::mutex> lock(mLockMutex); @@ -260,7 +260,7 @@ bool LLSharedMutex::trylockShared() bool LLSharedMutex::trylockExclusive() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; LLThread::id_t current_thread = LLThread::currentID(); std::lock_guard<std::mutex> lock(mLockMutex); @@ -282,7 +282,7 @@ bool LLSharedMutex::trylockExclusive() void LLSharedMutex::unlockShared() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; LLThread::id_t current_thread = LLThread::currentID(); std::lock_guard<std::mutex> lock(mLockMutex); @@ -303,7 +303,7 @@ void LLSharedMutex::unlockShared() void LLSharedMutex::unlockExclusive() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; LLThread::id_t current_thread = LLThread::currentID(); std::lock_guard<std::mutex> lock(mLockMutex); @@ -338,20 +338,20 @@ LLCondition::~LLCondition() void LLCondition::wait() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; std::unique_lock< std::mutex > lock(mMutex); mCond.wait(lock); } void LLCondition::signal() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; mCond.notify_one(); } void LLCondition::broadcast() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; mCond.notify_all(); } @@ -364,7 +364,7 @@ LLMutexTrylock::LLMutexTrylock(LLMutex* mutex) : mMutex(mutex), mLocked(false) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; if (mMutex) mLocked = mMutex->trylock(); } @@ -373,7 +373,7 @@ LLMutexTrylock::LLMutexTrylock(LLMutex* mutex, U32 aTries, U32 delay_ms) : mMutex(mutex), mLocked(false) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; if (!mMutex) return; @@ -388,7 +388,7 @@ LLMutexTrylock::LLMutexTrylock(LLMutex* mutex, U32 aTries, U32 delay_ms) LLMutexTrylock::~LLMutexTrylock() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; if (mMutex && mLocked) mMutex->unlock(); } @@ -400,7 +400,7 @@ LLMutexTrylock::~LLMutexTrylock() // LLScopedLock::LLScopedLock(std::mutex* mutex) : mMutex(mutex) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; if(mutex) { mutex->lock(); @@ -419,7 +419,7 @@ LLScopedLock::~LLScopedLock() void LLScopedLock::unlock() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; if(mLocked) { mMutex->unlock(); diff --git a/indra/llcommon/llpointer.h b/indra/llcommon/llpointer.h index f5916f9d58..6edff9fa5e 100644 --- a/indra/llcommon/llpointer.h +++ b/indra/llcommon/llpointer.h @@ -46,8 +46,11 @@ template <class Type> class LLPointer { public: + template<typename Subclass> + friend class LLPointer; + LLPointer() : - mPointer(NULL) + mPointer(nullptr) { } @@ -63,6 +66,12 @@ public: ref(); } + LLPointer(LLPointer<Type>&& ptr) noexcept + { + mPointer = ptr.mPointer; + ptr.mPointer = nullptr; + } + // Support conversion up the type hierarchy. See Item 45 in Effective C++, 3rd Ed. template<typename Subclass> LLPointer(const LLPointer<Subclass>& ptr) : @@ -71,6 +80,13 @@ public: ref(); } + template<typename Subclass> + LLPointer(LLPointer<Subclass>&& ptr) noexcept : + mPointer(ptr.get()) + { + ptr.mPointer = nullptr; + } + ~LLPointer() { unref(); @@ -82,11 +98,11 @@ public: 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 BOOL() const { return (mPointer != nullptr); } + operator bool() const { return (mPointer != nullptr); } + bool operator!() const { return (mPointer == nullptr); } + bool isNull() const { return (mPointer == nullptr); } + bool notNull() const { return (mPointer != nullptr); } operator Type*() const { return mPointer; } bool operator !=(Type* ptr) const { return (mPointer != ptr); } @@ -107,6 +123,17 @@ public: return *this; } + LLPointer<Type>& operator =(LLPointer<Type>&& ptr) + { + if (mPointer != ptr.mPointer) + { + unref(); + mPointer = ptr.mPointer; + ptr.mPointer = nullptr; + } + return *this; + } + // support assignment up the type hierarchy. See Item 45 in Effective C++, 3rd Ed. template<typename Subclass> LLPointer<Type>& operator =(const LLPointer<Subclass>& ptr) @@ -115,6 +142,18 @@ public: return *this; } + template<typename Subclass> + LLPointer<Type>& operator =(LLPointer<Subclass>&& ptr) + { + if (mPointer != ptr.mPointer) + { + unref(); + mPointer = ptr.mPointer; + ptr.mPointer = nullptr; + } + return *this; + } + // Just exchange the pointers, which will not change the reference counts. static void swap(LLPointer<Type>& a, LLPointer<Type>& b) { @@ -141,9 +180,9 @@ protected: if (mPointer) { Type *temp = mPointer; - mPointer = NULL; + mPointer = nullptr; temp->unref(); - if (mPointer != NULL) + if (mPointer != nullptr) { LL_WARNS() << "Unreference did assignment to non-NULL because of destructor" << LL_ENDL; unref(); @@ -168,9 +207,11 @@ protected: template <class Type> class LLConstPointer { + template<typename Subclass> + friend class LLConstPointer; public: LLConstPointer() : - mPointer(NULL) + mPointer(nullptr) { } @@ -186,6 +227,12 @@ public: ref(); } + LLConstPointer(LLConstPointer<Type>&& ptr) noexcept + { + mPointer = ptr.mPointer; + ptr.mPointer = nullptr; + } + // support conversion up the type hierarchy. See Item 45 in Effective C++, 3rd Ed. template<typename Subclass> LLConstPointer(const LLConstPointer<Subclass>& ptr) : @@ -194,6 +241,13 @@ public: ref(); } + template<typename Subclass> + LLConstPointer(LLConstPointer<Subclass>&& ptr) noexcept : + mPointer(ptr.get()) + { + ptr.mPointer = nullptr; + } + ~LLConstPointer() { unref(); @@ -203,11 +257,11 @@ public: 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 BOOL() const { return (mPointer != nullptr); } + operator bool() const { return (mPointer != nullptr); } + bool operator!() const { return (mPointer == nullptr); } + bool isNull() const { return (mPointer == nullptr); } + bool notNull() const { return (mPointer != nullptr); } operator const Type*() const { return mPointer; } bool operator !=(const Type* ptr) const { return (mPointer != ptr); } @@ -239,6 +293,17 @@ public: return *this; } + LLConstPointer<Type>& operator =(LLConstPointer<Type>&& ptr) + { + if (mPointer != ptr.mPointer) + { + unref(); + mPointer = ptr.mPointer; + ptr.mPointer = nullptr; + } + return *this; + } + // support assignment up the type hierarchy. See Item 45 in Effective C++, 3rd Ed. template<typename Subclass> LLConstPointer<Type>& operator =(const LLConstPointer<Subclass>& ptr) @@ -252,6 +317,18 @@ public: return *this; } + template<typename Subclass> + LLConstPointer<Type>& operator =(LLConstPointer<Subclass>&& ptr) + { + if (mPointer != ptr.mPointer) + { + unref(); + mPointer = ptr.mPointer; + ptr.mPointer = nullptr; + } + return *this; + } + // Just exchange the pointers, which will not change the reference counts. static void swap(LLConstPointer<Type>& a, LLConstPointer<Type>& b) { @@ -278,9 +355,9 @@ protected: if (mPointer) { const Type *temp = mPointer; - mPointer = NULL; + mPointer = nullptr; temp->unref(); - if (mPointer != NULL) + if (mPointer != nullptr) { LL_WARNS() << "Unreference did assignment to non-NULL because of destructor" << LL_ENDL; unref(); @@ -313,7 +390,7 @@ public: : LLPointer<Type>(ptr), mStayUnique(false) { - if (ptr.mForceUnique) + if (ptr.mStayUnique) { makeUnique(); } diff --git a/indra/llcommon/llpreprocessor.h b/indra/llcommon/llpreprocessor.h index 0248e8f8b9..a528cc7fd8 100644 --- a/indra/llcommon/llpreprocessor.h +++ b/indra/llcommon/llpreprocessor.h @@ -74,9 +74,6 @@ #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. @@ -130,8 +127,6 @@ #endif // level 4 warnings that we need to disable: -#pragma warning (disable : 4244) // possible loss of data on conversions -#pragma warning (disable : 4396) // the inline specifier cannot be used when a friend declaration refers to a specialization of a function template #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 #endif // LL_MSVC diff --git a/indra/llcommon/llprofiler.h b/indra/llcommon/llprofiler.h index 722d9afca2..732436cc4f 100644 --- a/indra/llcommon/llprofiler.h +++ b/indra/llcommon/llprofiler.h @@ -84,7 +84,7 @@ extern thread_local bool gProfilerEnabled; // #define TRACY_NO_BROADCAST 1 // #define TRACY_ONLY_LOCALHOST 1 #define TRACY_ONLY_IPV4 1 - #include "Tracy.hpp" + #include "tracy/Tracy.hpp" // Enable OpenGL profiling #define LL_PROFILER_ENABLE_TRACY_OPENGL 0 diff --git a/indra/llcommon/llqueuedthread.cpp b/indra/llcommon/llqueuedthread.cpp index 7d77f6f6a9..1c4ac5a7bf 100644 --- a/indra/llcommon/llqueuedthread.cpp +++ b/indra/llcommon/llqueuedthread.cpp @@ -483,7 +483,7 @@ void LLQueuedThread::processRequest(LLQueuedThread::QueuedRequest* req) if (sleep_time.count() > 0) { - ms_sleep(sleep_time.count()); + ms_sleep((U32)sleep_time.count()); } } processRequest(req); diff --git a/indra/llcommon/llrand.cpp b/indra/llcommon/llrand.cpp index 25d75af568..2c51e6f07f 100644 --- a/indra/llcommon/llrand.cpp +++ b/indra/llcommon/llrand.cpp @@ -85,7 +85,7 @@ inline F32 ll_internal_random<F32>() // 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<F32>(gRandomGenerator()) }; + F32 rv{ narrow<F64>(gRandomGenerator()) }; if(!((rv >= 0.0f) && (rv < 1.0f))) return fmodf(rv, 1.0f); return rv; } diff --git a/indra/llcommon/llsd.cpp b/indra/llcommon/llsd.cpp index 663ceac22b..77fe545c3f 100644 --- a/indra/llcommon/llsd.cpp +++ b/indra/llcommon/llsd.cpp @@ -30,6 +30,7 @@ #include "linden_common.h" #include "llsd.h" +#include "llbase64.h" #include "llerror.h" #include "../llmath/llmath.h" #include "llformat.h" @@ -105,6 +106,9 @@ public: static void reset(Impl*& var, Impl* impl); ///< safely set var to refer to the new impl (possibly shared) + static void move(Impl*& var, Impl*& impl); + ///< safely move impl from one object to another + static Impl& safe( Impl*); static const Impl& safe(const Impl*); ///< since a NULL Impl* is used for undefined, this ensures there is @@ -122,11 +126,17 @@ public: 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 char*); 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&); + virtual void assign(Impl*& var, LLSD::String&&); + virtual void assign(Impl*& var, LLSD::UUID&&); + virtual void assign(Impl*& var, LLSD::Date&&); + virtual void assign(Impl*& var, LLSD::URI&&); + virtual void assign(Impl*& var, 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 @@ -142,11 +152,13 @@ public: 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 String asXMLRPCValue() const { return "<nil/>"; } + + virtual bool has(std::string_view) const { return false; } + virtual LLSD get(std::string_view) 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 const LLSD& ref(std::string_view) const{ return undef(); } virtual size_t size() const { return 0; } virtual LLSD get(size_t) const { return LLSD(); } @@ -182,7 +194,7 @@ namespace LLSDUnnamedNamespace namespace #endif { - template<LLSD::Type T, class Data, class DataRef = Data> + template<LLSD::Type T, class Data, class DataRef = Data, class DataMove = Data> 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 @@ -195,6 +207,7 @@ namespace public: ImplBase(DataRef value) : mValue(value) { } + ImplBase(DataMove value) : mValue(std::move(value)) { } virtual LLSD::Type type() const { return T; } @@ -209,11 +222,21 @@ namespace mValue = value; } } + virtual void assign(LLSD::Impl*& var, DataMove value) { + if (shared()) + { + Impl::assign(var, std::move(value)); + } + else + { + mValue = std::move(value); + } + } }; - class ImplBoolean - : public ImplBase<LLSD::TypeBoolean, LLSD::Boolean> + class ImplBoolean final + : public ImplBase<LLSD::TypeBoolean, LLSD::Boolean, LLSD::Boolean, LLSD::Boolean&&> { public: ImplBoolean(LLSD::Boolean v) : Base(v) { } @@ -222,6 +245,8 @@ namespace virtual LLSD::Integer asInteger() const { return mValue ? 1 : 0; } virtual LLSD::Real asReal() const { return mValue ? 1 : 0; } virtual LLSD::String asString() const; + + virtual LLSD::String asXMLRPCValue() const { return mValue ? "<boolean>1</boolean>" : "<boolean>0</boolean>"; } }; LLSD::String ImplBoolean::asString() const @@ -233,8 +258,8 @@ namespace { return mValue ? "true" : ""; } - class ImplInteger - : public ImplBase<LLSD::TypeInteger, LLSD::Integer> + class ImplInteger final + : public ImplBase<LLSD::TypeInteger, LLSD::Integer, LLSD::Integer, LLSD::Integer&&> { public: ImplInteger(LLSD::Integer v) : Base(v) { } @@ -243,14 +268,16 @@ namespace virtual LLSD::Integer asInteger() const { return mValue; } virtual LLSD::Real asReal() const { return mValue; } virtual LLSD::String asString() const; + + virtual LLSD::String asXMLRPCValue() const { return "<int>" + std::to_string(mValue) + "</int>"; } }; LLSD::String ImplInteger::asString() const { return llformat("%d", mValue); } - class ImplReal - : public ImplBase<LLSD::TypeReal, LLSD::Real> + class ImplReal final + : public ImplBase<LLSD::TypeReal, LLSD::Real, LLSD::Real, LLSD::Real&&> { public: ImplReal(LLSD::Real v) : Base(v) { } @@ -259,6 +286,8 @@ namespace virtual LLSD::Integer asInteger() const; virtual LLSD::Real asReal() const { return mValue; } virtual LLSD::String asString() const; + + virtual LLSD::String asXMLRPCValue() const { return "<double>" + std::to_string(mValue) + "</double>"; } }; LLSD::Boolean ImplReal::asBoolean() const @@ -271,11 +300,12 @@ namespace { return llformat("%lg", mValue); } - class ImplString - : public ImplBase<LLSD::TypeString, LLSD::String, const LLSD::String&> + class ImplString final + : public ImplBase<LLSD::TypeString, LLSD::String, const LLSD::String&, LLSD::String&&> { public: ImplString(const LLSD::String& v) : Base(v) { } + ImplString(LLSD::String&& v) : Base(std::move(v)) {} virtual LLSD::Boolean asBoolean() const { return !mValue.empty(); } virtual LLSD::Integer asInteger() const; @@ -286,9 +316,24 @@ namespace virtual LLSD::URI asURI() const { return LLURI(mValue); } virtual size_t size() const { return mValue.size(); } virtual const LLSD::String& asStringRef() const { return mValue; } + + virtual LLSD::String asXMLRPCValue() const { return "<string>" + LLStringFn::xml_encode(mValue) + "</string>"; } + + using LLSD::Impl::assign; // Unhiding base class virtuals... + virtual void assign(LLSD::Impl*& var, const char* value) + { + if (shared()) + { + Impl::assign(var, value); + } + else + { + mValue = value; + } + } }; - LLSD::Integer ImplString::asInteger() const + 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 @@ -298,7 +343,7 @@ namespace return (int)asReal(); } - LLSD::Real ImplString::asReal() const + LLSD::Real ImplString::asReal() const { F64 v = 0.0; std::istringstream i_stream(mValue); @@ -315,25 +360,32 @@ namespace } - class ImplUUID - : public ImplBase<LLSD::TypeUUID, LLSD::UUID, const LLSD::UUID&> + class ImplUUID final + : public ImplBase<LLSD::TypeUUID, LLSD::UUID, const LLSD::UUID&, LLSD::UUID&&> { public: ImplUUID(const LLSD::UUID& v) : Base(v) { } + ImplUUID(LLSD::UUID&& v) : Base(std::move(v)) { } virtual LLSD::String asString() const{ return mValue.asString(); } virtual LLSD::UUID asUUID() const { return mValue; } + + virtual LLSD::String asXMLRPCValue() const { return "<string>" + mValue.asString() + "</string>"; } }; - class ImplDate - : public ImplBase<LLSD::TypeDate, LLSD::Date, const LLSD::Date&> + class ImplDate final + : public ImplBase<LLSD::TypeDate, LLSD::Date, const LLSD::Date&, LLSD::Date&&> { public: ImplDate(const LLSD::Date& v) - : ImplBase<LLSD::TypeDate, LLSD::Date, const LLSD::Date&>(v) + : ImplBase(v) { } + ImplDate(LLSD::Date&& v) + : ImplBase(std::move(v)) + { } + virtual LLSD::Integer asInteger() const { return (LLSD::Integer)(mValue.secondsSinceEpoch()); @@ -344,34 +396,42 @@ namespace } virtual LLSD::String asString() const{ return mValue.asString(); } virtual LLSD::Date asDate() const { return mValue; } + + virtual LLSD::String asXMLRPCValue() const { return "<dateTime.iso8601>" + mValue.toHTTPDateString("%FT%T") + "</dateTime.iso8601>"; } }; - class ImplURI - : public ImplBase<LLSD::TypeURI, LLSD::URI, const LLSD::URI&> + class ImplURI final + : public ImplBase<LLSD::TypeURI, LLSD::URI, const LLSD::URI&, LLSD::URI&&> { public: ImplURI(const LLSD::URI& v) : Base(v) { } + ImplURI(LLSD::URI&& v) : Base(std::move(v)) { } virtual LLSD::String asString() const{ return mValue.asString(); } virtual LLSD::URI asURI() const { return mValue; } + + virtual LLSD::String asXMLRPCValue() const { return "<string>" + LLStringFn::xml_encode(mValue.asString()) + "</string>"; } }; - class ImplBinary - : public ImplBase<LLSD::TypeBinary, LLSD::Binary, const LLSD::Binary&> + class ImplBinary final + : public ImplBase<LLSD::TypeBinary, LLSD::Binary, const LLSD::Binary&, LLSD::Binary&&> { public: ImplBinary(const LLSD::Binary& v) : Base(v) { } + ImplBinary(LLSD::Binary&& v) : Base(std::move(v)) { } virtual const LLSD::Binary& asBinary() const{ return mValue; } + + virtual LLSD::String asXMLRPCValue() const { return "<base64>" + LLBase64::encode(mValue.data(), mValue.size()) + "</base64>"; } }; - class ImplMap : public LLSD::Impl + class ImplMap final : public LLSD::Impl { private: - typedef std::map<LLSD::String, LLSD> DataMap; + typedef std::map<LLSD::String, LLSD, std::less<>> DataMap; DataMap mData; @@ -387,17 +447,30 @@ namespace virtual LLSD::Boolean asBoolean() const { return !mData.empty(); } - virtual bool has(const LLSD::String&) const; + virtual LLSD::String asXMLRPCValue() const + { + std::ostringstream os; + os << "<struct>"; + for (const auto& it : mData) + { + os << "<member><name>" << LLStringFn::xml_encode(it.first) << "</name>" + << it.second.asXMLRPCValue() << "</member>"; + } + os << "</struct>"; + return os.str(); + } + + virtual bool has(std::string_view) 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 get(std::string_view) const; virtual LLSD getKeys() const; - void insert(const LLSD::String& k, const LLSD& v); + void insert(std::string_view k, const LLSD& v); virtual void erase(const LLSD::String&); - LLSD& ref(const LLSD::String&); - virtual const LLSD& ref(const LLSD::String&) const; + LLSD& ref(std::string_view); + virtual const LLSD& ref(std::string_view) const; virtual size_t size() const { return mData.size(); } @@ -425,14 +498,14 @@ namespace } } - bool ImplMap::has(const LLSD::String& k) const + bool ImplMap::has(const std::string_view 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 + LLSD ImplMap::get(const std::string_view k) const { LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD; DataMap::const_iterator i = mData.find(k); @@ -452,10 +525,10 @@ namespace return keys; } - void ImplMap::insert(const LLSD::String& k, const LLSD& v) + void ImplMap::insert(std::string_view k, const LLSD& v) { LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD; - mData.insert(DataMap::value_type(k, v)); + mData.emplace(k, v); } void ImplMap::erase(const LLSD::String& k) @@ -464,15 +537,21 @@ namespace mData.erase(k); } - LLSD& ImplMap::ref(const LLSD::String& k) + LLSD& ImplMap::ref(std::string_view k) { - return mData[k]; + DataMap::iterator i = mData.lower_bound(k); + if (i == mData.end() || mData.key_comp()(k, i->first)) + { + return mData.emplace_hint(i, std::make_pair(k, LLSD()))->second; + } + + return i->second; } - const LLSD& ImplMap::ref(const LLSD::String& k) const + const LLSD& ImplMap::ref(std::string_view k) const { DataMap::const_iterator i = mData.lower_bound(k); - if (i == mData.end() || mData.key_comp()(k, i->first)) + if (i == mData.end() || mData.key_comp()(k, i->first)) { return undef(); } @@ -500,7 +579,7 @@ namespace { //std::cout << " " << (*iter).first << ": " << (*iter).second << std::endl; Impl::calcStats((*iter).second, type_counts, share_counts); - iter++; + ++iter; } // Add in the values for this map @@ -511,7 +590,7 @@ namespace class ImplArray : public LLSD::Impl { private: - typedef std::vector<LLSD> DataVector; + typedef std::vector<LLSD> DataVector; DataVector mData; @@ -527,6 +606,18 @@ namespace virtual LLSD::Boolean asBoolean() const { return !mData.empty(); } + virtual LLSD::String asXMLRPCValue() const + { + std::ostringstream os; + os << "<array><data>"; + for (const auto& it : mData) + { + os << it.asXMLRPCValue(); + } + os << "</data></array>"; + return os.str(); + } + using LLSD::Impl::get; // Unhiding get(LLSD::String) using LLSD::Impl::erase; // Unhiding erase(LLSD::String) using LLSD::Impl::ref; // Unhiding ref(LLSD::String) @@ -647,7 +738,7 @@ namespace while (iter != endArray()) { // Add values for all items held in the array Impl::calcStats((*iter), type_counts, share_counts); - iter++; + ++iter; } // Add in the values for this array @@ -685,6 +776,16 @@ void LLSD::Impl::reset(Impl*& var, Impl* impl) var = impl; } +void LLSD::Impl::move(Impl*& var, Impl*& impl) +{ + if (var && var->mUseCount != STATIC_USAGE_COUNT && --var->mUseCount == 0) + { + delete var; // destroy var if usage falls to 0 and not static + } + var = impl; // Steal impl to var without incrementing use since this is a move + impl = nullptr; // null out old-impl pointer +} + LLSD::Impl& LLSD::Impl::safe(Impl* impl) { static Impl theUndefined(STATIC_USAGE_COUNT); @@ -738,6 +839,11 @@ void LLSD::Impl::assign(Impl*& var, LLSD::Real v) reset(var, new ImplReal(v)); } +void LLSD::Impl::assign(Impl*& var, const char* v) +{ + reset(var, new ImplString(v)); +} + void LLSD::Impl::assign(Impl*& var, const LLSD::String& v) { reset(var, new ImplString(v)); @@ -763,6 +869,31 @@ void LLSD::Impl::assign(Impl*& var, const LLSD::Binary& v) reset(var, new ImplBinary(v)); } +void LLSD::Impl::assign(Impl*& var, LLSD::String&& v) +{ + reset(var, new ImplString(std::move(v))); +} + +void LLSD::Impl::assign(Impl*& var, LLSD::UUID&& v) +{ + reset(var, new ImplUUID(std::move(v))); +} + +void LLSD::Impl::assign(Impl*& var, LLSD::Date&& v) +{ + reset(var, new ImplDate(std::move(v))); +} + +void LLSD::Impl::assign(Impl*& var, LLSD::URI&& v) +{ + reset(var, new ImplURI(std::move(v))); +} + +void LLSD::Impl::assign(Impl*& var, LLSD::Binary&& v) +{ + reset(var, new ImplBinary(std::move(v))); +} + const LLSD& LLSD::Impl::undef() { @@ -835,6 +966,9 @@ 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); } +LLSD::LLSD(LLSD&& other) noexcept : impl(nullptr) { ALLOC_LLSD_OBJECT; Impl::move(impl, other.impl); } +void LLSD::assign(LLSD&& other) { Impl::move(impl, other.impl); } +LLSD& LLSD::operator=(LLSD&& other) noexcept { Impl::move(impl, other.impl); return *this; } void LLSD::clear() { Impl::assignUndefined(impl); } @@ -849,6 +983,11 @@ 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(UUID&& v) : impl(0) { ALLOC_LLSD_OBJECT; assign(std::move(v)); } +LLSD::LLSD(String&& v) : impl(0) { ALLOC_LLSD_OBJECT; assign(std::move(v)); } +LLSD::LLSD(Date&& v) : impl(0) { ALLOC_LLSD_OBJECT; assign(std::move(v)); } +LLSD::LLSD(URI&& v) : impl(0) { ALLOC_LLSD_OBJECT; assign(std::move(v)); } +LLSD::LLSD(Binary&& v) : impl(0) { ALLOC_LLSD_OBJECT; assign(std::move(v)); } // Scalar Assignment void LLSD::assign(Boolean v) { safe(impl).assign(impl, v); } @@ -859,6 +998,11 @@ 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(String&& v) { safe(impl).assign(impl, std::move(v)); } +void LLSD::assign(UUID&& v) { safe(impl).assign(impl, std::move(v)); } +void LLSD::assign(Date&& v) { safe(impl).assign(impl, std::move(v)); } +void LLSD::assign(URI&& v) { safe(impl).assign(impl, std::move(v)); } +void LLSD::assign(Binary&& v) { safe(impl).assign(impl, std::move(v)); } // Scalar Accessors LLSD::Boolean LLSD::asBoolean() const { return safe(impl).asBoolean(); } @@ -872,11 +1016,13 @@ const LLSD::Binary& LLSD::asBinary() const { return safe(impl).asBinary(); } const LLSD::String& LLSD::asStringRef() const { return safe(impl).asStringRef(); } +LLSD::String LLSD::asXMLRPCValue() const { return "<value>" + safe(impl).asXMLRPCValue() + "</value>"; } + // const char * helpers LLSD::LLSD(const char* v) : impl(0) { ALLOC_LLSD_OBJECT; assign(v); } void LLSD::assign(const char* v) { - if(v) assign(std::string(v)); + if(v) safe(impl).assign(impl, v); else assign(std::string()); } @@ -888,24 +1034,24 @@ LLSD LLSD::emptyMap() 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); } +bool LLSD::has(const std::string_view k) const { return safe(impl).has(k); } +LLSD LLSD::get(const std::string_view 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); } +void LLSD::insert(std::string_view k, const LLSD& v) { makeMap(impl).insert(k, v); } -LLSD& LLSD::with(const String& k, const LLSD& v) +LLSD& LLSD::with(std::string_view k, const LLSD& v) { makeMap(impl).insert(k, v); return *this; } void LLSD::erase(const String& k) { makeMap(impl).erase(k); } -LLSD& LLSD::operator[](const String& k) +LLSD& LLSD::operator[](const std::string_view k) { LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD; return makeMap(impl).ref(k); } -const LLSD& LLSD::operator[](const String& k) const +const LLSD& LLSD::operator[](const std::string_view k) const { LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD; return safe(impl).ref(k); diff --git a/indra/llcommon/llsd.h b/indra/llcommon/llsd.h index a5e735b561..d2b3548831 100644 --- a/indra/llcommon/llsd.h +++ b/indra/llcommon/llsd.h @@ -161,6 +161,13 @@ public: //@} + /** @name Movable */ + //@{ + LLSD(LLSD&& other) noexcept; + void assign(LLSD&& other); + LLSD& operator=(LLSD&& other) noexcept; + //@} + void clear(); ///< resets to Undefined @@ -188,6 +195,11 @@ public: LLSD(const Date&); LLSD(const URI&); LLSD(const Binary&); + LLSD(String&&); + LLSD(UUID&&); + LLSD(Date&&); + LLSD(URI&&); + LLSD(Binary&&); //@} /** @name Convenience Constructors */ @@ -215,6 +227,11 @@ public: void assign(const Date&); void assign(const URI&); void assign(const Binary&); + void assign(String&&); + void assign(UUID&&); + void assign(Date&&); + void assign(URI&&); + void assign(Binary&&); LLSD& operator=(Boolean v) { assign(v); return *this; } LLSD& operator=(Integer v) { assign(v); return *this; } @@ -224,6 +241,11 @@ public: 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; } + LLSD& operator=(String&& v) { assign(std::move(v)); return *this; } + LLSD& operator=(UUID&& v) { assign(std::move(v)); return *this; } + LLSD& operator=(Date&& v) { assign(std::move(v)); return *this; } + LLSD& operator=(URI&& v) { assign(std::move(v)); return *this; } + LLSD& operator=(Binary&& v) { assign(std::move(v)); return *this; } //@} /** @@ -259,10 +281,14 @@ public: UUID asUUID() const; Date asDate() const; URI asURI() const; - const Binary& asBinary() const; + const Binary& asBinary() const; // asStringRef on any non-string type will return a ref to an empty string. - const String& asStringRef() const; + const String& asStringRef() const; + + // Return "<value><((type))>((scalar value or recursive calls))</((type))></value>" + // See http://xmlrpc.com/spec.md + String asXMLRPCValue() const; operator Boolean() const { return asBoolean(); } operator Integer() const { return asInteger(); } @@ -275,7 +301,7 @@ public: // 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();} + bool operator!() const { return !asBoolean(); } //@} /** @name Character Pointer Helpers @@ -292,24 +318,22 @@ public: //@{ static LLSD emptyMap(); - bool has(const String&) const; - LLSD get(const String&) const; + bool has(const std::string_view) const; + LLSD get(const std::string_view) const; LLSD getKeys() const; // Return an LLSD array with keys as strings - void insert(const String&, const LLSD&); + void insert(std::string_view, const LLSD&); void erase(const String&); - LLSD& with(const String&, const LLSD&); + LLSD& with(std::string_view, const LLSD&); - LLSD& operator[](const String&); + LLSD& operator[](const std::string_view); LLSD& operator[](const char* c) { - LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD; - return (*this)[String(c)]; + return c ? (*this)[std::string_view(c)] : *this; } - const LLSD& operator[](const String&) const; + const LLSD& operator[](const std::string_view) const; const LLSD& operator[](const char* c) const { - LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD; - return (*this)[String(c)]; + return c ? (*this)[std::string_view(c)] : *this; } //@} diff --git a/indra/llcommon/llsdparam.cpp b/indra/llcommon/llsdparam.cpp index b981be4d0a..3ae153a67c 100644 --- a/indra/llcommon/llsdparam.cpp +++ b/indra/llcommon/llsdparam.cpp @@ -149,7 +149,7 @@ bool LLParamSDParser::readF32(Parser& parser, void* val_ptr) { LLParamSDParser& self = static_cast<LLParamSDParser&>(parser); - *((F32*)val_ptr) = self.mCurReadSD->asReal(); + *((F32*)val_ptr) = (F32)self.mCurReadSD->asReal(); return true; } diff --git a/indra/llcommon/llsdserialize.cpp b/indra/llcommon/llsdserialize.cpp index 15002580c9..37af366a20 100644 --- a/indra/llcommon/llsdserialize.cpp +++ b/indra/llcommon/llsdserialize.cpp @@ -231,7 +231,7 @@ bool LLSDSerialize::deserialize(LLSD& sd, std::istream& str, llssize max_bytes) } // Since we've already read 'inbuf' bytes into 'hdr_buf', prepend that // data to whatever remains in 'str'. - LLMemoryStreamBuf already(reinterpret_cast<const U8*>(hdr_buf), inbuf); + LLMemoryStreamBuf already(reinterpret_cast<const U8*>(hdr_buf), (S32)inbuf); cat_streambuf prebuff(&already, str.rdbuf()); std::istream prepend(&prebuff); #if 1 @@ -475,7 +475,7 @@ LLSDNotationParser::~LLSDNotationParser() // virtual S32 LLSDNotationParser::doParse(std::istream& istr, LLSD& data, S32 max_depth) const { - LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD + LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD; // map: { string:object, string:object } // array: [ object, object, object ] // undef: ! @@ -566,7 +566,7 @@ S32 LLSDNotationParser::doParse(std::istream& istr, LLSD& data, S32 max_depth) c data, NOTATION_FALSE_SERIAL, false); - if(PARSE_FAILURE == cnt) parse_count = cnt; + if(PARSE_FAILURE == cnt) parse_count = (S32)cnt; else account(cnt); } else @@ -592,7 +592,7 @@ S32 LLSDNotationParser::doParse(std::istream& istr, LLSD& data, S32 max_depth) c if(isalpha(c)) { auto cnt = deserialize_boolean(istr,data,NOTATION_TRUE_SERIAL,true); - if(PARSE_FAILURE == cnt) parse_count = cnt; + if(PARSE_FAILURE == cnt) parse_count = (S32)cnt; else account(cnt); } else @@ -735,7 +735,7 @@ S32 LLSDNotationParser::doParse(std::istream& istr, LLSD& data, S32 max_depth) c S32 LLSDNotationParser::parseMap(std::istream& istr, LLSD& map, S32 max_depth) const { - LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD + LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD; // map: { string:object, string:object } map = LLSD::emptyMap(); S32 parse_count = 0; @@ -796,7 +796,7 @@ S32 LLSDNotationParser::parseMap(std::istream& istr, LLSD& map, S32 max_depth) c S32 LLSDNotationParser::parseArray(std::istream& istr, LLSD& array, S32 max_depth) const { - LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD + LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD; // array: [ object, object, object ] array = LLSD::emptyArray(); S32 parse_count = 0; @@ -836,7 +836,7 @@ S32 LLSDNotationParser::parseArray(std::istream& istr, LLSD& array, S32 max_dept bool LLSDNotationParser::parseString(std::istream& istr, LLSD& data) const { - LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD + LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD; std::string value; auto count = deserialize_string(istr, value, mMaxBytesLeft); if(PARSE_FAILURE == count) return false; @@ -847,7 +847,7 @@ bool LLSDNotationParser::parseString(std::istream& istr, LLSD& data) const bool LLSDNotationParser::parseBinary(std::istream& istr, LLSD& data) const { - LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD + LL_PROFILE_ZONE_SCOPED_CATEGORY_LLSD; // binary: b##"ff3120ab1" // or: b(len)"..." @@ -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: '!'<br> * Boolean: '1' for true '0' for false<br> diff --git a/indra/llcommon/llsdserialize_xml.cpp b/indra/llcommon/llsdserialize_xml.cpp index 88cbb3b984..6396caf8d5 100644 --- a/indra/llcommon/llsdserialize_xml.cpp +++ b/indra/llcommon/llsdserialize_xml.cpp @@ -554,7 +554,7 @@ void LLSDXMLParser::Impl::parsePart(const char* buf, llssize len) if ( buf != NULL && len > 0 ) { - XML_Status status = XML_Parse(mParser, buf, len, false); + XML_Status status = XML_Parse(mParser, buf, (int)len, 0); if (status == XML_STATUS_ERROR) { LL_INFOS() << "Unexpected XML parsing error at start" << LL_ENDL; @@ -930,7 +930,7 @@ void LLSDXMLParser::parsePart(const char *buf, llssize 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 ); diff --git a/indra/llcommon/llsdutil.cpp b/indra/llcommon/llsdutil.cpp index dd3a58c26d..12f67208c1 100644 --- a/indra/llcommon/llsdutil.cpp +++ b/indra/llcommon/llsdutil.cpp @@ -51,7 +51,7 @@ // U32 LLSD ll_sd_from_U32(const U32 val) { - std::vector<U8> v; + LLSD::Binary v; U32 net_order = htonl(val); v.resize(4); @@ -63,7 +63,7 @@ LLSD ll_sd_from_U32(const U32 val) U32 ll_U32_from_sd(const LLSD& sd) { U32 ret; - std::vector<U8> v = sd.asBinary(); + const LLSD::Binary& v = sd.asBinary(); if (v.size() < 4) { return 0; @@ -76,7 +76,7 @@ U32 ll_U32_from_sd(const LLSD& sd) //U64 LLSD ll_sd_from_U64(const U64 val) { - std::vector<U8> v; + LLSD::Binary v; U32 high, low; high = (U32)(val >> 32); @@ -94,7 +94,7 @@ LLSD ll_sd_from_U64(const U64 val) U64 ll_U64_from_sd(const LLSD& sd) { U32 high, low; - std::vector<U8> v = sd.asBinary(); + const LLSD::Binary& v = sd.asBinary(); if (v.size() < 8) { @@ -112,7 +112,7 @@ U64 ll_U64_from_sd(const LLSD& sd) // IP Address (stored in net order in a U32, so don't need swizzling) LLSD ll_sd_from_ipaddr(const U32 val) { - std::vector<U8> v; + LLSD::Binary v; v.resize(4); memcpy(&(v[0]), &val, 4); /* Flawfinder: ignore */ @@ -123,7 +123,7 @@ LLSD ll_sd_from_ipaddr(const U32 val) U32 ll_ipaddr_from_sd(const LLSD& sd) { U32 ret; - std::vector<U8> v = sd.asBinary(); + const LLSD::Binary& v = sd.asBinary(); if (v.size() < 4) { return 0; @@ -135,17 +135,17 @@ U32 ll_ipaddr_from_sd(const LLSD& sd) // Converts an LLSD binary to an LLSD string LLSD ll_string_from_binary(const LLSD& sd) { - std::vector<U8> value = sd.asBinary(); + const LLSD::Binary& value = sd.asBinary(); std::string str; str.resize(value.size()); - memcpy(&str[0], &value[0], value.size()); + memcpy(&str[0], value.data(), value.size()); return str; } // Converts an LLSD string to an LLSD binary LLSD ll_binary_from_string(const LLSD& sd) { - std::vector<U8> binary_value; + LLSD::Binary binary_value; std::string string_value = sd.asString(); for (const U8 c : string_value) @@ -214,7 +214,7 @@ bool compare_llsd_with_template( const LLSD& template_llsd, LLSD& resultant_llsd) { - LL_PROFILE_ZONE_SCOPED + LL_PROFILE_ZONE_SCOPED; if ( llsd_to_test.isUndefined() && @@ -337,7 +337,7 @@ bool filter_llsd_with_template( const LLSD & template_llsd, LLSD & resultant_llsd) { - LL_PROFILE_ZONE_SCOPED + LL_PROFILE_ZONE_SCOPED; if (llsd_to_test.isUndefined() && template_llsd.isDefined()) { @@ -533,7 +533,7 @@ class TypeLookup public: TypeLookup() { - LL_PROFILE_ZONE_SCOPED + LL_PROFILE_ZONE_SCOPED; for (const Data *di(boost::begin(typedata)), *dend(boost::end(typedata)); di != dend; ++di) { @@ -543,7 +543,7 @@ public: std::string lookup(LLSD::Type type) const { - LL_PROFILE_ZONE_SCOPED + LL_PROFILE_ZONE_SCOPED; MapType::const_iterator found = mMap.find(type); if (found != mMap.end()) @@ -595,7 +595,7 @@ static std::string match_types(LLSD::Type expect, // prototype.type() LLSD::Type actual, // type we're checking const std::string& pfx) // as for llsd_matches { - LL_PROFILE_ZONE_SCOPED + LL_PROFILE_ZONE_SCOPED; // Trivial case: if the actual type is exactly what we expect, we're good. if (actual == expect) @@ -634,7 +634,7 @@ static std::string match_types(LLSD::Type expect, // prototype.type() // see docstring in .h file std::string llsd_matches(const LLSD& prototype, const LLSD& data, const std::string& pfx) { - LL_PROFILE_ZONE_SCOPED + LL_PROFILE_ZONE_SCOPED; // An undefined prototype means that any data is valid. // An undefined slot in an array or map prototype means that any data @@ -768,7 +768,7 @@ std::string llsd_matches(const LLSD& prototype, const LLSD& data, const std::str bool llsd_equals(const LLSD& lhs, const LLSD& rhs, int bits) { - LL_PROFILE_ZONE_SCOPED + LL_PROFILE_ZONE_SCOPED; // We're comparing strict equality of LLSD representation rather than // performing any conversions. So if the types aren't equal, the LLSD @@ -878,7 +878,7 @@ namespace llsd LLSD& drill_ref(LLSD& blob, const LLSD& rawPath) { - LL_PROFILE_ZONE_SCOPED + LL_PROFILE_ZONE_SCOPED; // Treat rawPath uniformly as an array. If it's not already an array, // store it as the only entry in one. (But let's say Undefined means an @@ -905,7 +905,7 @@ LLSD& drill_ref(LLSD& blob, const LLSD& rawPath) // path entry that's bad. for (LLSD::Integer i = 0; i < path.size(); ++i) { - LL_PROFILE_ZONE_NUM( i ) + LL_PROFILE_ZONE_NUM(i); const LLSD& key{path[i]}; if (key.isString()) @@ -935,7 +935,7 @@ LLSD& drill_ref(LLSD& blob, const LLSD& rawPath) LLSD drill(const LLSD& blob, const LLSD& path) { - LL_PROFILE_ZONE_SCOPED + LL_PROFILE_ZONE_SCOPED; // drill_ref() does exactly what we want. Temporarily cast away // const-ness and use that. @@ -949,7 +949,7 @@ LLSD drill(const LLSD& blob, const LLSD& path) // filter may be include to exclude/include keys in a map. LLSD llsd_clone(LLSD value, LLSD filter) { - LL_PROFILE_ZONE_SCOPED + LL_PROFILE_ZONE_SCOPED; LLSD clone; bool has_filter(filter.isMap()); @@ -990,8 +990,7 @@ LLSD llsd_clone(LLSD value, LLSD filter) case LLSD::TypeBinary: { - LLSD::Binary bin(value.asBinary().begin(), value.asBinary().end()); - clone = LLSD::Binary(bin); + clone = LLSD::Binary(value.asBinary().begin(), value.asBinary().end()); break; } default: diff --git a/indra/llcommon/llsingleton.h b/indra/llcommon/llsingleton.h index 7c6be25309..316831cd74 100644 --- a/indra/llcommon/llsingleton.h +++ b/indra/llcommon/llsingleton.h @@ -37,7 +37,8 @@ #include "llmainthreadtask.h" #ifdef LL_WINDOWS -#pragma warning( disable : 4506 ) // no definition for inline function +#pragma warning(push) +#pragma warning(disable : 4506) // no definition for inline function #endif class LLSingletonBase: private boost::noncopyable @@ -861,4 +862,8 @@ private: template <class T> T* LLSimpleton<T>::sInstance{ nullptr }; +#ifdef LL_WINDOWS +#pragma warning(pop) +#endif + #endif diff --git a/indra/llcommon/llstl.h b/indra/llcommon/llstl.h index 1b52d94258..7d41c42ba7 100644 --- a/indra/llcommon/llstl.h +++ b/indra/llcommon/llstl.h @@ -226,11 +226,11 @@ void delete_and_clear_array(T*& ptr) // 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 <typename K, typename T> -inline T* get_ptr_in_map(const std::map<K,T*>& inmap, const K& key) +template <typename T> +inline typename T::mapped_type get_ptr_in_map(const T& inmap, typename T::key_type const& key) { // Typedef here avoids warnings because of new c++ naming rules. - typedef typename std::map<K,T*>::const_iterator map_iter; + typedef typename T::const_iterator map_iter; map_iter iter = inmap.find(key); if(iter == inmap.end()) { diff --git a/indra/llcommon/llstring.cpp b/indra/llcommon/llstring.cpp index 514d73b24b..c57f8b1e96 100644 --- a/indra/llcommon/llstring.cpp +++ b/indra/llcommon/llstring.cpp @@ -250,7 +250,7 @@ LLWString utf16str_to_wstring(const U16* utf16str, size_t len) while (i < len) { llwchar cur_char; - i += utf16chars_to_wchar(chars16+i, &cur_char); + i += (S32)utf16chars_to_wchar(chars16+i, &cur_char); wout += cur_char; } return wout; @@ -1208,6 +1208,75 @@ namespace LLStringFn return output; } + using literals_t = std::map<char, std::string>; + static const literals_t xml_elem_literals = + { + { '<', "<" }, + { '>', ">" }, + { '&', "&" } + }; + static const literals_t xml_attr_literals = + { + { '"', """ }, + { '\'', "'" } + }; + + static void literals_encode(std::string& text, const literals_t& literals) + { + for (const std::pair<char, std::string> it : literals) + { + std::string::size_type pos = 0; + while ((pos = text.find(it.first, pos)) != std::string::npos) + { + text.replace(pos, 1, it.second); + pos += it.second.size(); + } + } + } + + static void literals_decode(std::string& text, const literals_t& literals) + { + for (const std::pair<char, std::string> it : literals) + { + std::string::size_type pos = 0; + while ((pos = text.find(it.second, pos)) != std::string::npos) + { + text[pos++] = it.first; + text.erase(pos, it.second.size() - 1); + } + } + } + + /** + * @brief Replace all characters that are not allowed in XML 1.0 + * with corresponding literals: [ < > & ] => [ < > & ] + */ + std::string xml_encode(const std::string& input, bool for_attribute) + { + std::string result(input); + literals_encode(result, xml_elem_literals); + if (for_attribute) + { + literals_encode(result, xml_attr_literals); + } + return result; + } + + /** + * @brief Replace some of XML literals that are defined in XML 1.0 + * with corresponding characters: [ < > & ] => [ < > & ] + */ + std::string xml_decode(const std::string& input, bool for_attribute) + { + std::string result(input); + literals_decode(result, xml_elem_literals); + if (for_attribute) + { + literals_decode(result, xml_attr_literals); + } + return result; + } + /** * @brief Replace all control characters (c < 0x20) with replacement in * string. diff --git a/indra/llcommon/llstring.h b/indra/llcommon/llstring.h index 123f4184b5..b69a068830 100644 --- a/indra/llcommon/llstring.h +++ b/indra/llcommon/llstring.h @@ -890,6 +890,20 @@ namespace LLStringFn /** + * @brief Replace all characters that are not allowed in XML 1.0 + * with corresponding literals: [ < > & ] => [ < > & ] + */ + LL_COMMON_API std::string xml_encode(const std::string& input, bool for_attribute = false); + + + /** + * @brief Replace some of XML literals that are defined in XML 1.0 + * with corresponding characters: [ < > & ] => [ < > & ] + */ + LL_COMMON_API std::string xml_decode(const std::string& input, bool for_attribute = false); + + + /** * @brief Replace all control characters (0 <= c < 0x20) with replacement in * string. This is safe for utf-8 * diff --git a/indra/llcommon/llsys.cpp b/indra/llcommon/llsys.cpp index cfb05873df..79625ad9f8 100644 --- a/indra/llcommon/llsys.cpp +++ b/indra/llcommon/llsys.cpp @@ -74,6 +74,8 @@ using namespace llsd; # include <mach/mach_host.h> # include <mach/task.h> # include <mach/task_info.h> +# include <sys/types.h> +# include <mach/mach_init.h> #elif LL_LINUX # include <errno.h> # include <sys/utsname.h> @@ -85,6 +87,7 @@ const char MEMINFO_FILE[] = "/proc/meminfo"; #endif LLCPUInfo gSysCPU; +LLMemoryInfo gSysMemory; // Don't log memory info any more often than this. It also serves as our // framerate sample size. @@ -797,33 +800,32 @@ U32Kilobytes LLMemoryInfo::getPhysicalMemoryKB() const } //static -void LLMemoryInfo::getAvailableMemoryKB(U32Kilobytes& avail_physical_mem_kb, U32Kilobytes& avail_virtual_mem_kb) +void LLMemoryInfo::getAvailableMemoryKB(U32Kilobytes& avail_mem_kb) { + LL_PROFILE_ZONE_SCOPED_CATEGORY_MEMORY; #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()); - avail_physical_mem_kb = (U32Kilobytes)statsMap["Avail Physical KB"].asInteger(); - avail_virtual_mem_kb = (U32Kilobytes)statsMap["Avail Virtual KB"].asInteger(); + avail_mem_kb = (U32Kilobytes)statsMap["Avail Physical 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 ; + // use host_statistics64 to get memory info + vm_statistics64_data_t vmstat; + mach_msg_type_number_t count = HOST_VM_INFO64_COUNT; + mach_port_t host = mach_host_self(); + vm_size_t page_size; + host_page_size(host, &page_size); + kern_return_t result = host_statistics64(host, HOST_VM_INFO64, reinterpret_cast<host_info_t>(&vmstat), &count); + if (result == KERN_SUCCESS) + { + avail_mem_kb = U64Bytes((vmstat.free_count + vmstat.inactive_count) * page_size); + } + else + { + avail_mem_kb = (U32Kilobytes)-1; + } #elif LL_LINUX // mStatsMap is derived from MEMINFO_FILE: @@ -874,15 +876,14 @@ void LLMemoryInfo::getAvailableMemoryKB(U32Kilobytes& avail_physical_mem_kb, U32 // 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 ; + LLSD statsMap(loadStatsMap()); + avail_mem_kb = (U32Kilobytes)statsMap["MemFree"].asInteger(); #else //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_mem_kb = (U32Kilobytes)-1 ; #endif } @@ -928,7 +929,7 @@ LLSD LLMemoryInfo::getStatsMap() const LLMemoryInfo& LLMemoryInfo::refresh() { - LL_PROFILE_ZONE_SCOPED + LL_PROFILE_ZONE_SCOPED; mStatsMap = loadStatsMap(); LL_DEBUGS("LLMemoryInfo") << "Populated mStatsMap:\n"; @@ -977,7 +978,7 @@ LLSD LLMemoryInfo::loadStatsMap() // 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)); + GetProcessMemoryInfo(GetCurrentProcess(), (PROCESS_MEMORY_COUNTERS*) &pmem, sizeof(pmem)); stats.add("Page Fault Count", pmem.PageFaultCount); stats.add("PeakWorkingSetSize KB", pmem.PeakWorkingSetSize/div); diff --git a/indra/llcommon/llsys.h b/indra/llcommon/llsys.h index f97d49eeb1..827b0dc048 100644 --- a/indra/llcommon/llsys.h +++ b/indra/llcommon/llsys.h @@ -134,8 +134,8 @@ public: 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 in KiloBytes. + static void getAvailableMemoryKB(U32Kilobytes& avail_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. @@ -169,6 +169,7 @@ bool LL_COMMON_API gunzip_file(const std::string& srcfile, const std::string& ds // gzip srcfile into dstfile. Returns false on error. bool LL_COMMON_API gzip_file(const std::string& srcfile, const std::string& dstfile); +extern LL_COMMON_API LLMemoryInfo gSysMemory; extern LL_COMMON_API LLCPUInfo gSysCPU; #endif // LL_LLSYS_H diff --git a/indra/llcommon/llthread.cpp b/indra/llcommon/llthread.cpp index faaaefd561..e5d25b52f0 100644 --- a/indra/llcommon/llthread.cpp +++ b/indra/llcommon/llthread.cpp @@ -269,6 +269,7 @@ void LLThread::shutdown() mStatus = STOPPED; return; } + delete mThreadp; mThreadp = NULL; } @@ -299,6 +300,7 @@ void LLThread::start() { mThreadp = new std::thread(std::bind(&LLThread::threadRun, this)); mNativeHandle = mThreadp->native_handle(); + mThreadp->detach(); } catch (std::system_error& ex) { @@ -344,7 +346,7 @@ bool LLThread::runCondition(void) // Stop thread execution if requested until unpaused. void LLThread::checkPause() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; mDataLock->lock(); // This is in a while loop because the pthread API allows for spurious wakeups. @@ -376,20 +378,20 @@ void LLThread::setQuitting() // static LLThread::id_t LLThread::currentID() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; return std::this_thread::get_id(); } // static void LLThread::yield() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; std::this_thread::yield(); } void LLThread::wake() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; mDataLock->lock(); if(!shouldSleep()) { @@ -400,7 +402,7 @@ void LLThread::wake() void LLThread::wakeLocked() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; if(!shouldSleep()) { mRunCondition->signal(); @@ -409,13 +411,13 @@ void LLThread::wakeLocked() void LLThread::lockData() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; mDataLock->lock(); } void LLThread::unlockData() { - LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD + LL_PROFILE_ZONE_SCOPED_CATEGORY_THREAD; mDataLock->unlock(); } diff --git a/indra/llcommon/lltimer.cpp b/indra/llcommon/lltimer.cpp index a3e871661c..28d6e4e4cc 100644 --- a/indra/llcommon/lltimer.cpp +++ b/indra/llcommon/lltimer.cpp @@ -91,7 +91,7 @@ U32 micro_sleep(U64 us, U32 max_yields) U32 micro_sleep(U64 us, U32 max_yields) { - LL_PROFILE_ZONE_SCOPED + LL_PROFILE_ZONE_SCOPED; #if 0 LARGE_INTEGER ft; ft.QuadPart = -static_cast<S64>(us * 10); // '-' using relative time @@ -101,7 +101,7 @@ U32 micro_sleep(U64 us, U32 max_yields) WaitForSingleObject(timer, INFINITE); CloseHandle(timer); #else - Sleep(us / 1000); + Sleep((DWORD)(us / 1000)); #endif return 0; @@ -109,7 +109,7 @@ U32 micro_sleep(U64 us, U32 max_yields) void ms_sleep(U32 ms) { - LL_PROFILE_ZONE_SCOPED + LL_PROFILE_ZONE_SCOPED; micro_sleep(ms * 1000, 0); } diff --git a/indra/llcommon/lltraceaccumulators.cpp b/indra/llcommon/lltraceaccumulators.cpp index 8741087f3a..dc9a87eb80 100644 --- a/indra/llcommon/lltraceaccumulators.cpp +++ b/indra/llcommon/lltraceaccumulators.cpp @@ -100,7 +100,7 @@ bool AccumulatorBufferGroup::isCurrent() const return mCounts.isCurrent(); } -void AccumulatorBufferGroup::append( const AccumulatorBufferGroup& other ) +void AccumulatorBufferGroup::append(const AccumulatorBufferGroup& other) { LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; mCounts.addSamples(other.mCounts, SEQUENTIAL); @@ -109,7 +109,7 @@ void AccumulatorBufferGroup::append( const AccumulatorBufferGroup& other ) mStackTimers.addSamples(other.mStackTimers, SEQUENTIAL); } -void AccumulatorBufferGroup::merge( const AccumulatorBufferGroup& other) +void AccumulatorBufferGroup::merge(const AccumulatorBufferGroup& other) { LL_PROFILE_ZONE_SCOPED_CATEGORY_STATS; mCounts.addSamples(other.mCounts, NON_SEQUENTIAL); @@ -140,7 +140,7 @@ void AccumulatorBufferGroup::sync() F64 SampleAccumulator::mergeSumsOfSquares(const SampleAccumulator& a, const SampleAccumulator& b) { - const F64 epsilon = 0.0000001; + constexpr F64 epsilon = 0.0000001; if (a.getSamplingTime() > epsilon && b.getSamplingTime() > epsilon) { @@ -170,7 +170,7 @@ F64 SampleAccumulator::mergeSumsOfSquares(const SampleAccumulator& a, const Samp return a.getSumOfSquares(); } -void SampleAccumulator::addSamples( const SampleAccumulator& other, EBufferAppendType append_type ) +void SampleAccumulator::addSamples(const SampleAccumulator& other, EBufferAppendType append_type) { if (append_type == NON_SEQUENTIAL) { @@ -205,7 +205,7 @@ void SampleAccumulator::addSamples( const SampleAccumulator& other, EBufferAppen } } -void SampleAccumulator::reset( const SampleAccumulator* other ) +void SampleAccumulator::reset(const SampleAccumulator* other) { mLastValue = other ? other->mLastValue : NaN; mHasValue = other ? other->mHasValue : false; @@ -243,7 +243,7 @@ F64 EventAccumulator::mergeSumsOfSquares(const EventAccumulator& a, const EventA return a.mSumOfSquares; } -void EventAccumulator::addSamples( const EventAccumulator& other, EBufferAppendType append_type ) +void EventAccumulator::addSamples(const EventAccumulator& other, EBufferAppendType append_type) { if (other.mNumSamples) { @@ -269,12 +269,12 @@ void EventAccumulator::addSamples( const EventAccumulator& other, EBufferAppendT } } -void EventAccumulator::reset( const EventAccumulator* other ) +void EventAccumulator::reset(const EventAccumulator* other) { mNumSamples = 0; mSum = 0; - mMin = F32(NaN); - mMax = F32(NaN); + mMin = NaN; + mMax = NaN; mMean = NaN; mSumOfSquares = 0; mLastValue = other ? other->mLastValue : NaN; diff --git a/indra/llcommon/lltraceaccumulators.h b/indra/llcommon/lltraceaccumulators.h index ba7acf9547..0a2e2bf997 100644 --- a/indra/llcommon/lltraceaccumulators.h +++ b/indra/llcommon/lltraceaccumulators.h @@ -39,7 +39,7 @@ namespace LLTrace { - const F64 NaN = std::numeric_limits<double>::quiet_NaN(); + constexpr F64 NaN = std::numeric_limits<double>::quiet_NaN(); enum EBufferAppendType { @@ -251,8 +251,8 @@ namespace LLTrace EventAccumulator() : mSum(0), - mMin(F32(NaN)), - mMax(F32(NaN)), + mMin(NaN), + mMax(NaN), mMean(NaN), mSumOfSquares(0), mNumSamples(0), @@ -288,11 +288,11 @@ namespace LLTrace void sync(F64SecondsImplicit) {} F64 getSum() const { return mSum; } - F32 getMin() const { return mMin; } - F32 getMax() const { return mMax; } + F64 getMin() const { return mMin; } + F64 getMax() const { return mMax; } F64 getLastValue() const { return mLastValue; } F64 getMean() const { return mMean; } - F64 getStandardDeviation() const { return sqrtf(mSumOfSquares / mNumSamples); } + F64 getStandardDeviation() const { return sqrt(mSumOfSquares / mNumSamples); } F64 getSumOfSquares() const { return mSumOfSquares; } S32 getSampleCount() const { return mNumSamples; } bool hasValue() const { return mNumSamples > 0; } @@ -307,7 +307,7 @@ namespace LLTrace F64 mMean, mSumOfSquares; - F32 mMin, + F64 mMin, mMax; S32 mNumSamples; @@ -322,8 +322,8 @@ namespace LLTrace SampleAccumulator() : mSum(0), - mMin(F32(NaN)), - mMax(F32(NaN)), + mMin(NaN), + mMax(NaN), mMean(NaN), mSumOfSquares(0), mLastSampleTimeStamp(0), @@ -378,11 +378,11 @@ namespace LLTrace } F64 getSum() const { return mSum; } - F32 getMin() const { return mMin; } - F32 getMax() const { return mMax; } + F64 getMin() const { return mMin; } + F64 getMax() const { return mMax; } F64 getLastValue() const { return mLastValue; } F64 getMean() const { return mMean; } - F64 getStandardDeviation() const { return sqrtf(mSumOfSquares / mTotalSamplingTime); } + F64 getStandardDeviation() const { return sqrt(mSumOfSquares / mTotalSamplingTime); } F64 getSumOfSquares() const { return mSumOfSquares; } F64SecondsImplicit getSamplingTime() const { return mTotalSamplingTime; } S32 getSampleCount() const { return mNumSamples; } @@ -402,7 +402,7 @@ namespace LLTrace mLastSampleTimeStamp, mTotalSamplingTime; - F32 mMin, + F64 mMin, mMax; S32 mNumSamples; diff --git a/indra/llcommon/lltracerecording.cpp b/indra/llcommon/lltracerecording.cpp index 1ec83be7cb..c23adca7e8 100644 --- a/indra/llcommon/lltracerecording.cpp +++ b/indra/llcommon/lltracerecording.cpp @@ -229,7 +229,7 @@ F32 Recording::getPerSec(const StatType<TimeBlockAccumulator::CallCountFacet>& s 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(); + return (F32)(accumulator.mCalls + (active_accumulator ? active_accumulator->mCalls : 0)) / (F32)mElapsedSeconds.value(); } bool Recording::hasValue(const StatType<CountAccumulator>& stat) @@ -296,11 +296,11 @@ F64 Recording::getMean( const StatType<SampleAccumulator>& stat ) const SampleAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mSamples[stat.getIndex()] : NULL; if (active_accumulator && active_accumulator->hasValue()) { - F32 t = 0.0f; + F64 t = 0.0; S32 div = accumulator.getSampleCount() + active_accumulator->getSampleCount(); if (div > 0) { - t = active_accumulator->getSampleCount() / div; + t = (F64)active_accumulator->getSampleCount() / (F64)div; } return lerp(accumulator.getMean(), active_accumulator->getMean(), t); } @@ -319,7 +319,7 @@ F64 Recording::getStandardDeviation( const StatType<SampleAccumulator>& stat ) 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())); + return sqrt(sum_of_squares / (F64)(accumulator.getSamplingTime() + active_accumulator->getSamplingTime())); } else { @@ -382,11 +382,11 @@ F64 Recording::getMean( const StatType<EventAccumulator>& stat ) const EventAccumulator* active_accumulator = mActiveBuffers ? &mActiveBuffers->mEvents[stat.getIndex()] : NULL; if (active_accumulator && active_accumulator->hasValue()) { - F32 t = 0.0f; + F64 t = 0.0; S32 div = accumulator.getSampleCount() + active_accumulator->getSampleCount(); if (div > 0) { - t = active_accumulator->getSampleCount() / div; + t = (F64)active_accumulator->getSampleCount() / (F64)div; } return lerp(accumulator.getMean(), active_accumulator->getMean(), t); } @@ -405,7 +405,7 @@ F64 Recording::getStandardDeviation( const StatType<EventAccumulator>& stat ) 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())); + return sqrt(sum_of_squares / (F64)(accumulator.getSampleCount() + active_accumulator->getSampleCount())); } else { diff --git a/indra/llcommon/lltracerecording.h b/indra/llcommon/lltracerecording.h index 985f06cd59..ad4c91d85b 100644 --- a/indra/llcommon/lltracerecording.h +++ b/indra/llcommon/lltracerecording.h @@ -35,6 +35,11 @@ #include "llpointer.h" #include <limits> +#ifdef LL_WINDOWS +#pragma warning(push) +#pragma warning(disable : 4244) // possible loss of data on conversions +#endif + class LLStopWatchControlsMixinCommon { public: @@ -714,4 +719,8 @@ namespace LLTrace }; } +#ifdef LL_WINDOWS +#pragma warning(pop) +#endif + #endif // LL_LLTRACERECORDING_H diff --git a/indra/llcommon/llunittype.h b/indra/llcommon/llunittype.h index 83ce0d05a8..bb1408609a 100644 --- a/indra/llcommon/llunittype.h +++ b/indra/llcommon/llunittype.h @@ -31,6 +31,11 @@ #include "llpreprocessor.h" #include "llerror.h" +#ifdef LL_WINDOWS +#pragma warning(push) +#pragma warning(disable : 4244) // possible loss of data on conversions +#endif + //lightweight replacement of type traits for simple type equality check template<typename S, typename T> struct LLIsSameType @@ -846,4 +851,8 @@ LL_FORCE_INLINE S2 ll_convert_units(LLUnit<S1, base_unit_name> in, LLUnit<S2, un typedef LLUnit<U64, ns::unit_name> U64##unit_name; \ typedef LLUnitImplicit<U64, ns::unit_name> U64##unit_name##Implicit +#ifdef LL_WINDOWS +#pragma warning(pop) +#endif + #endif //LL_UNITTYPE_H diff --git a/indra/llcommon/lluriparser.cpp b/indra/llcommon/lluriparser.cpp index 2ebb7fc742..33a48d970d 100644 --- a/indra/llcommon/lluriparser.cpp +++ b/indra/llcommon/lluriparser.cpp @@ -29,12 +29,7 @@ #include "linden_common.h" #include "lluriparser.h" -#if LL_DARWIN -#include <signal.h> -#include <setjmp.h> -#endif - -LLUriParser::LLUriParser(const std::string& u) : mTmpScheme(false), mNormalizedTmp(false), mRes(0) +LLUriParser::LLUriParser(const std::string& u) : mTmpScheme(false), mNormalizedTmp(false), mRes(false) { if (u.find("://") == std::string::npos) { @@ -42,36 +37,52 @@ LLUriParser::LLUriParser(const std::string& u) : mTmpScheme(false), mNormalizedT mTmpScheme = true; } - mNormalizedUri += u.c_str(); + mNormalizedUri.append(u); mRes = parse(); } LLUriParser::~LLUriParser() { - uriFreeUriMembersA(&mUri); } -S32 LLUriParser::parse() +bool LLUriParser::parse() { - mRes = uriParseSingleUriA(&mUri, mNormalizedUri.c_str(), NULL); + try + { + auto res = boost::urls::parse_uri(mNormalizedUri); + if (res) + { + mUri = *res; + mRes = true; + } + else + { + mRes = false; + } + } + catch (const std::length_error&) + { + LL_WARNS() << "Failed to parse uri due to exceeding uri_view max_size" << LL_ENDL; + mRes = false; + } return mRes; } -const char * LLUriParser::scheme() const +const std::string& LLUriParser::scheme() const { - return mScheme.c_str(); + return mScheme; } -void LLUriParser::sheme(const std::string& s) +void LLUriParser::scheme(const std::string& s) { mTmpScheme = !s.size(); mScheme = s; } -const char * LLUriParser::port() const +const std::string& LLUriParser::port() const { - return mPort.c_str(); + return mPort; } void LLUriParser::port(const std::string& s) @@ -79,9 +90,9 @@ void LLUriParser::port(const std::string& s) mPort = s; } -const char * LLUriParser::host() const +const std::string& LLUriParser::host() const { - return mHost.c_str(); + return mHost; } void LLUriParser::host(const std::string& s) @@ -89,9 +100,9 @@ void LLUriParser::host(const std::string& s) mHost = s; } -const char * LLUriParser::path() const +const std::string& LLUriParser::path() const { - return mPath.c_str(); + return mPath; } void LLUriParser::path(const std::string& s) @@ -99,9 +110,9 @@ void LLUriParser::path(const std::string& s) mPath = s; } -const char * LLUriParser::query() const +const std::string& LLUriParser::query() const { - return mQuery.c_str(); + return mQuery; } void LLUriParser::query(const std::string& s) @@ -109,9 +120,9 @@ void LLUriParser::query(const std::string& s) mQuery = s; } -const char * LLUriParser::fragment() const +const std::string& LLUriParser::fragment() const { - return mFragment.c_str(); + return mFragment; } void LLUriParser::fragment(const std::string& s) @@ -119,19 +130,6 @@ void LLUriParser::fragment(const std::string& 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<std::string::size_type>(len)); - } - else - { - str = LLStringUtil::null; - } -} - void LLUriParser::extractParts() { if (mTmpScheme || mNormalizedTmp) @@ -140,96 +138,24 @@ void LLUriParser::extractParts() } else { - textRangeToString(mUri.scheme, mScheme); + mScheme = mUri.scheme(); } - 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; - } + mHost = mUri.host(); + mPort = mUri.port(); + mQuery = mUri.query(); + mFragment = mUri.fragment(); + mPath = mUri.path(); } -#if LL_DARWIN -typedef void(*sighandler_t)(int); -jmp_buf return_to_normalize; -static int sLastSignal = 0; -void uri_signal_handler(int signal) -{ - sLastSignal = signal; - // Apparently signal handler throwing an exception doesn't work. - // This is ugly and unsafe due to not unwinding content of uriparser library, - // but unless we have a way to catch this as NSexception, jump appears to be the only option. - longjmp(return_to_normalize, 1 /*setjmp will return this value*/); -} -#endif - -S32 LLUriParser::normalize() +bool LLUriParser::normalize() { mNormalizedTmp = mTmpScheme; - if (!mRes) + if (mRes) { -#if LL_DARWIN - sighandler_t last_sigill_handler, last_sigbus_handler; - 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 - // If you encountered this, please try to figure out what's wrong: - // 1. Verify that library's input is 'sane' - // 2. Check if we have an NSexception to work with (unlikely) - // 3. See if passing same string causes exception to repeat - // - // Crash happens at uriNormalizeSyntaxExA - // Warning!!! This does not properly unwind stack, - // if this can be handled by NSexception, it needs to be remade - llassert(0); - - LL_WARNS() << "Uriparser crashed with " << sLastSignal << " , while processing: " << mNormalizedUri << LL_ENDL; - signal(SIGILL, last_sigill_handler); - signal(SIGBUS, last_sigbus_handler); - return 1; - } -#endif - - mRes = uriNormalizeSyntaxExA(&mUri, URI_NORMALIZE_SCHEME | URI_NORMALIZE_HOST); - -#if LL_DARWIN - signal(SIGILL, last_sigill_handler); - signal(SIGBUS, last_sigbus_handler); -#endif - - if (!mRes) - { - S32 chars_required; - mRes = uriToStringCharsRequiredA(&mUri, &chars_required); - - if (!mRes) - { - chars_required++; - std::vector<char> label_buf(chars_required); - mRes = uriToStringA(&label_buf[0], &mUri, chars_required, NULL); - - if (!mRes) - { - mNormalizedUri = &label_buf[mTmpScheme ? 7 : 0]; - mTmpScheme = false; - } - } - } + mUri.normalize_scheme().normalize_authority(); + mNormalizedUri = mUri.buffer().substr(mTmpScheme ? 7 : 0); + mTmpScheme = false; } if(mTmpScheme && mNormalizedUri.size() > 7) @@ -302,7 +228,7 @@ bool LLUriParser::test() const return uri == mNormalizedUri; } -const char * LLUriParser::normalizedUri() const +const std::string& LLUriParser::normalizedUri() const { - return mNormalizedUri.c_str(); + return mNormalizedUri; } diff --git a/indra/llcommon/lluriparser.h b/indra/llcommon/lluriparser.h index 77eb4031d5..61d613f399 100644 --- a/indra/llcommon/lluriparser.h +++ b/indra/llcommon/lluriparser.h @@ -30,7 +30,7 @@ #define LL_LLURIPARSER_H #include <string> -#include "uriparser/Uri.h" +#include "boost/url.hpp" class LL_COMMON_API LLUriParser { @@ -38,36 +38,35 @@ public: LLUriParser(const std::string& u); ~LLUriParser(); - const char * scheme() const; - void sheme (const std::string& s); + const std::string& scheme() const; + void scheme (const std::string& s); - const char * port() const; + const std::string& port() const; void port (const std::string& s); - const char * host() const; + const std::string& host() const; void host (const std::string& s); - const char * path() const; + const std::string& path() const; void path (const std::string& s); - const char * query() const; + const std::string& query() const; void query (const std::string& s); - const char * fragment() const; + const std::string& fragment() const; void fragment (const std::string& s); - const char * normalizedUri() const; + const std::string& 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(); + bool normalize(); private: - S32 parse(); - void textRangeToString(UriTextRangeA& textRange, std::string& str); + bool parse(); std::string mScheme; std::string mHost; std::string mPort; @@ -76,9 +75,9 @@ private: std::string mFragment; std::string mNormalizedUri; - UriUriA mUri; + boost::url mUri; - S32 mRes; + bool mRes; bool mTmpScheme; bool mNormalizedTmp; }; diff --git a/indra/llcommon/tests/lleventfilter_test.cpp b/indra/llcommon/tests/lleventfilter_test.cpp index a01d7fe415..d7b80e2545 100644 --- a/indra/llcommon/tests/lleventfilter_test.cpp +++ b/indra/llcommon/tests/lleventfilter_test.cpp @@ -81,13 +81,13 @@ class TestEventThrottle: public LLEventThrottleBase public: TestEventThrottle(F32 interval): LLEventThrottleBase(interval), - mAlarmRemaining(-1), - mTimerRemaining(-1) + mAlarmRemaining(-1.f), + mTimerRemaining(-1.f) {} TestEventThrottle(LLEventPump& source, F32 interval): LLEventThrottleBase(source, interval), - mAlarmRemaining(-1), - mTimerRemaining(-1) + mAlarmRemaining(-1.f), + mTimerRemaining(-1.f) {} /*----- implementation of LLEventThrottleBase timing functionality -----*/ @@ -100,12 +100,12 @@ public: virtual bool alarmRunning() const /*override*/ { // decrementing to exactly 0 should mean the alarm fires - return mAlarmRemaining > 0; + return mAlarmRemaining > 0.f; } virtual void alarmCancel() /*override*/ { - mAlarmRemaining = -1; + mAlarmRemaining = -1.f; } virtual void timerSet(F32 interval) /*override*/ @@ -116,7 +116,7 @@ public: virtual F32 timerGetRemaining() const /*override*/ { // LLTimer.getRemainingTimeF32() never returns negative; 0.0 means expired - return (mTimerRemaining > 0.0)? mTimerRemaining : 0.0; + return (mTimerRemaining > 0.0f)? mTimerRemaining : 0.0f; } /*------------------- methods for manipulating time --------------------*/ diff --git a/indra/llcommon/tests/llsdserialize_test.cpp b/indra/llcommon/tests/llsdserialize_test.cpp index fb2af1d2db..fae9f7023f 100644 --- a/indra/llcommon/tests/llsdserialize_test.cpp +++ b/indra/llcommon/tests/llsdserialize_test.cpp @@ -1809,7 +1809,7 @@ namespace tut std::string q("\""); std::string qPYTHON(q + PYTHON + q); std::string qscript(q + scriptfile.getName() + q); - int rc = _spawnl(_P_WAIT, PYTHON.c_str(), qPYTHON.c_str(), qscript.c_str(), + int rc = (int)_spawnl(_P_WAIT, PYTHON.c_str(), qPYTHON.c_str(), qscript.c_str(), std::forward<ARGS>(args)..., NULL); if (rc == -1) { diff --git a/indra/llcommon/tests/lltrace_test.cpp b/indra/llcommon/tests/lltrace_test.cpp index 8851f87b91..923a67ac8e 100644 --- a/indra/llcommon/tests/lltrace_test.cpp +++ b/indra/llcommon/tests/lltrace_test.cpp @@ -32,6 +32,10 @@ #include "lltracerecording.h" #include "../test/lltut.h" +#ifdef LL_WINDOWS +#pragma warning(disable : 4244) // possible loss of data on conversions +#endif + namespace LLUnits { // using powers of 2 to allow strict floating point equality diff --git a/indra/llcommon/tests/llunits_test.cpp b/indra/llcommon/tests/llunits_test.cpp index 49f2d3085a..98a58eb47e 100644 --- a/indra/llcommon/tests/llunits_test.cpp +++ b/indra/llcommon/tests/llunits_test.cpp @@ -262,7 +262,7 @@ namespace tut F32 float_val = quatloos_implicit; ensure("implicit units convert implicitly to regular values", float_val == 16); - S32 int_val = quatloos_implicit; + S32 int_val = (S32)quatloos_implicit; ensure("implicit units convert implicitly to regular values", int_val == 16); // conversion of implicits |